原生函数

也叫JavaScript的内建函数。常用的有:

String()
Number()
Boolean()
Array()
Object()
Function()
RegExp()
Date()
Error()
Symbol()——ES6新加入

封装对象包装

JavaScript会自动为基本类型值包装,所以像一些.length.toString()的属性和方法,在基本类型被字面量定义之后,也能拥有这些方法和属性。

特别注意在封装数字和布尔值后,用来进行判断时,会有一些疑惑:

var a = new Boolean(false);
if (!a) {
  console.log("Oops");  // 执行不到这里
}
var b = new Number(0);
if(!b) {
  console.log('Number');  // 执行不到这里
}

原生函数作为构造函数

Array构造函数只带一个数字参数时,这个参数为数组的预设长度,而非数组的第一个元素。

永远不要创建和使用空单元数组

除非万不得已,否则尽量不要使用Object()Function()RegExp(),直接使用字面量语法,其中RegExp()Function()在需要动态定义时才比较有用。正则使用字面量语法的执行效率要高于使用构造函数,这和JavaScript在执行前需要预编译有关。

Date()Error()没有对应的常量形式,所以在代码中用的比较多。

ES6新加入的基本数据类型——符号Symbol。主要解决对象属性重名的问题,作为对象属性时,常规的对象属性遍历是无法获取Symbol的,只能通过特殊的方法来获取——Object.getOwnPropertySymbols()。所以常被用来作为类的私有方法。用来替代_下划线前缀的属性。Symbol由于其值的”唯一性“还可以用来消除魔术字符串。阮一峰老师的blog上讲的很详细。

特殊的原生原型

typeof Function.prototype;  // "function"
Function.prototype();  // 空函数!

RegExp.prototype.toString();  // "/(?:)/"————空正则表达式
"abc".match(RegExp.prototype);  // [""]

Array.isArray(Array.prototype);  // true
Array.prototype.push(1, 2, 3);  // 3
Array.prototype;  // [1, 2, 3]

强制类型转换

类型转换分为两种,一种发生在静态语法分析时;另一种则是发生在动态类型语言的运行时(runtime),JavaScript统称为强制类型转换

强制类型转换总返回标量基本类型值,既简单值(如字符串、数字、boolean等)

值类型转换

隐式强制类型转换和显示强制类型转换是相对而言的:

var a = 42;
var b = a + "";  // 隐式
var c = String(a);  // 显示

如果明白a + ""是怎么回事,那么它也是显示的,如果不明白String(a)是怎么回事,那么它也是隐式的。

抽象值操作(即“仅供内部使用的操作”)

ToString

处理非字符串到字符串的强制类型转换。

null --> "null"
undefined --> "undefined"
true --> "true"

极大极小的数字则转换为指数形式:

var a = 1.07 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000;
a.toString();  // "1.07e21"

普通对象,除非自定义,否则toString()返回内部属性[[Class]]的值。

var obj = { a: 1 };
obj.toString();  // "[object Object]"

数组的默认toString()方法经过了重新定义,将所有单元字符串化以后再用","连接起来:

let a = [1, 2, 3];
a.toString();  // 1,2,3
let b = [{ c: 1 }, { d: 2 }];
b.toString();  // [object Object],[object Object]

数组的toString可以被显示调用,或者在需要字符串化时自动调用

JSON字符串化

对象中如果定义了toJSON方法,JSON字符串化时会首先调用该方法,然后用它的返回值来进行序列化——toJSON应该“返回一个能够被字符串化的安全的JSON值”。

JSON.stringify并不是强制类型转换,只是其中几种转换规则与ToString相同:字符串、数字、布尔值和null

ToNumber

对象转换为数字分为3步:

  1. 检查该值是否有valueOf()方法,如果有,且返回基本类型值,则使用此基本类型值强制类型转换。
  2. 如果没有valueOf()方法,则检查是否有toString()方法,有,且返回基本类型值,则同上。
  3. 如果以上两种方法都没有,则抛出TypeError错误。

ToBoolean

JavaScript规范定义了一小撮可以被强制类型转换为false的值:

undefined
null
false
+0、-0和NaN
""

但是JavaScript规范并没有明确规定假值列表之外的都是真值,不过我们可以理解为假值列表以外的值都是真值

假值对象

并不是说对象是假值,也不是说封装了假值的对象:

var a = new Boolean(false);
var b = new Number(0);
var c = new String("");
var d = Boolean(a && b && c);  // true

而是浏览器在某些特定情况下,在常规JavaScript语法基础上自己创建了一些外来(exotic)值,这些就是“假值对象”。虽然代码中会出现这些假值对象,但是它并不属于JavaScript语言范畴:

if(document.all) {...}

document.allDOM提供给JavaScript程序使用,以前曾是正真意义上的对象,可以强制转换城true,但后来废止了,IE也并不打算继续支持,但是许多程序中还有诸如以下的代码:

if(document.all) {/* it's IE */}

为了不再支持it's IE中的代码,所以将document.all作为假值来处理。

真值

假值列表以外的都是真值,值得注意的是:

var c = "''";
var d = Boolean(c);  // true

因为""是假值列表中唯一的字符串。

显示强制类型转换

字符串和数字之间的显示转换

var a = 42;
var b = String(a);  // "42"
var c = "3.14";
var d = Number(c);  // 3.14

String()遵循前面讲过的ToString规则,将值转换为字符串基本类型。Number()遵循前面讲过的ToNumber规则,将值转换为数字基本类型。

除了String()Number()以外,还有其他方法可以实现字符串和数字之间的显式转换:

var a = 42;
var b = a.toString();  // "42"
var c = "3.14";
var d = +c;  // 3.14

toString()是显示的,但是其中也涉及到隐式转换,因为toString()对于42这种基本类型不适用,需要JavaScript引擎自动为42创建一个封装对象。

+c+运算符的一元(unary)形式(即只有一个操作数)。+运算符显式地将c转换为数字,而非数字加法运算。

注意:需要区分一元运算符+-和递增++和递减--运算符。

1 - - 1;  // 2
var d = 5 + +"3.14";  // 8.14
日期显示转换为数字
const t = new Date;  // 构造函数没有参数的话,使用new运算可以不用()
+t  // 1628564390661
~运算符

字位运算符只适用于32位整数,运算符会强制操作数使用32位格式,这里则是通过抽象操作ToInt32实现的,ToInt32则首先执行ToNumber强制类型转换。