原生函数 -- Javascript基础探究篇(3)

626 阅读2分钟

除了我们能自定义函数外,js中还具有一些原生函数,如StringNumberBooleanObjectFunctionArrayDateRegExpErrorSymbol等。可以看到有些内置类型和简单基本类型名字和很相似。

使用这些原生函数构造出来的对象,对其使用typeof时返回的都是object

const str = new String("abc");
const obj = new Object({ a: 1 });
console.log(typeof str); // object
console.log(typeof obj); // object

内部属性[[Class]]

所有使用typeof返回为object的对象,内部都包含一个[[Class]]属性。该属性无法直接访问,一般通过Object.prototype.toString查看:

const str = new String("abc");
const obj = new Object({ a: 1 });
const arr = new Array(1, 2, 3);

console.log(Object.prototype.toString.call(str)); // [object String]
console.log(Object.prototype.toString.call(obj)); // [object Object]
console.log(Object.prototype.toString.call(arr)); // [object Array]

多数情况下,对象内部的[[Class]]属性和创建该对象的原生构造函数对应。但是nullundefined例外:

console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(null)); // [object Null]

事实上,UndefinedNull这样的原生函数并不存在

装箱拆箱

我们都知道基本类型(如booleannumberstring)并不是对象,但实际使用时,仍然可以像使用对象一样调用方法:

const strPrimitive = "primitive string";
const strObject = new String("object string");

console.log(typeof strPrimitive); // string
console.log(typeof strObject); // object
console.log(strPrimitive.toUpperCase()); // PRIMITIVE STRING
console.log(strObject.toUpperCase()); // OBJECT STRING

上述代码中strPrimitive并不是一个对象,它只是一个不可变的字面量。在需要对它进行一些操作时,如toUpperCase,js会自动将它转换为一个String对象,从而获取这些方法和属性。所以我们并不需要使用构造形式创建一个简单基本类型。这就是装箱操作(也叫做封装对象)。

类似的,当我们声明其他基本变量numberboolean)时,当我们在调用某些属性时,都会被自动转换为对应的对象,相当于是new SomeType()。当我们声明对象类型变量时,也会在声明后自动变成封装对象。所以它们都能访问对应构造函数中的方法。

const str = "string";
str.slice(); //等价于 new String("string").slice();

const num = 1;
num.toFixed(); //等价于 new Number(1).toFixed()

const bool = true;
bool.valueOf(); //等价于 new Boolean(true).valueOf()

const obj = {}; // 等价于 new Object()
function foo() {} // 等价于 new Function("{}")
const arr = [1, 2]; // 等价于 new Array(1, 2)

由于js存在封装对象的特性,所以我们定义变量时尽量直接使用基本类型值,而不使用构造形式。

如果想要得到封装对象中的基本类型值,可使用valueOf方法进行拆箱解封:

const a = new String("abc");
const b = new Number(10);
const c = new Boolean(true);

console.log(a.valueOf()); // "abc"
console.log(b.valueOf()); // 10
console.log(c.valueOf()); // true

在需要用到封装对象的基本类型值时,会发生隐式拆箱。

const a = new String("abc");
const b = a + "!";

console.log(b); // abc!
console.log(typeof b); // string