原始类型不能添加属性和方法,那length等方法为什么能直接使用呢?

0 阅读2分钟

首先我们都知道 JavaScript 的数据类型有:

1. 原始类型: string, number, boolean, undefined, null, symbol, bigInt
2. 引用类型: object, array, function

然后我们要知道,在 JavaScript 中万物皆对象。这句话要怎么理解呢?我们先来了解创建对象的方式。

创建对象的方式

  1. 字面量,也就是我们最常用的:
const obj = { // 对象字面量
    name: 'ikun'
}

其实在创建对象字面量时,v8 引擎也是偷偷执行了 const obj = new Object()

  1. new Object()
const obj = new Object() // 构造函数创建
obj.name = 'ikun'

3. new 一个构造函数

function Person(name){
    this.name = name
}

const obj = new Person('ikun')

函数有二义性:可以普通调用,也可以 new 调用

然后我们来搞清楚 new 的工作原理。

new 的工作原理

  1. new 会往函数内凭空创造一个 this 对象
  2. 执行函数中的代码
  3. 让这个对象的原型等于函数的原型,即 this.__ proto __ = Xxx.prototype
  4. return 这个对象
function Car(color) {
    // var this = {}
    this.name = 'su7'
    this.height = 1400
    this.lang = 4800
    this.weight = 1500
    this.color = color
    // return this
}

然后我们来说说 包装类

包装类

在了解包装类之前,我们要先知道两条铁律:

  • 原始类型是不能添加属性和方法的
  • v8 在对象中查找属性,如果找不到,一定会去它的原型上找

然后我们来讲包装类

  1. 当用户创建一个字面量, v8 会默认执行成 new Xxx()
const str = 'hello'  // 字符串字面量 const str = new String('hello')

2. 因为原始类型不能增加属性和方法,所以, v8 在 new 出这个实例对象后,立即会做一个拆箱操作

const str = 'hello'  // 字符串字面量 const str = new String('hello')

str.name = 'kunkun'               // str.name = 'kunkun'
                                // delete str.name
                                // str.[[PrimitiveValue]]
console.log(str.name);

注释中的是 v8 引擎进行的操作

所以使用 str.name 这个方法后,这份代码不会报错,而是输出 undefined。

最后我们来说明 原型

原型

// 原型
// 所有的 函数 都天生拥有一个属性叫 prototype
// 对象 天生拥有一个属性 叫 __proto__
function Car(color) {
    // var this = {}
    this.name = 'su7'
    // this.__proto__ = Car.prototype
}
const car = new Car()
console.log(car.tostring);

原型链有个查找规则:当前对象查找 → 原型查找 → 原型的原型 → ... → null。
car.tostring 是已经被写在 prototype 中的,所以这份代码能够运行并输出结果。

那么我们来看下面这份代码:

const str = 'hello'           //const strObj = new String('hello')
str.length = 4                // this.__proto__ = String.prototype
console.log(str.length);    // strObj.__proto__.lengths

image.png

输出结果并不是 4 ,因为原始类型不能增加属性和方法,所以输出的是原型上的 length:5 。 那么如果我们想要自己增加一个方法要怎么操作呢?我们可以:

String.prototype.len = 4
const str = 'hello'
console.log(str.len);

image.png

诸如数组中的 arr.push 、arr.unshift 等都是在原型中查找到的。

总结

在阅读完本文后我们就能清楚明白为什么 万物皆对象

我们也明白了为什么 length 等的方法能直接使用: str.length, length是 String 函数原型上的属性,并不是给字符串增加的属性。