基本类型使用点访问内部发生了什么

“ 最近在面试的时候,犯了一个低级的错误,是关于基本类型引用的问题,下面就让我们一起来分析一下流程是如何的。”

1. 具体代码

1
2
3
4
5
Object.prototype.test = 'test test';
var a = 123;
a.b = 456;
console.log(a.test);
console.log(a.b);

此时你是不是很好奇,基本类型还可以进行点(.)操作访问?
其实我在面试的时候也是犯了一个很低级的错误,然后不假思索的就答了一句:会报错的,那么恭喜你成功的跳进了坑里面,关键还乐开了花。

2. 思考流程

对于基本类型的值,它其实是不可变的,包括使用任何方法也都是无法改变基本类型的值。我们是不能给基本类型添加属性和方法的,即使添加了再去访问也是访问不到的。例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 任何方法都无法改变一个基本类型的值
var a = 123;
a.toString(); // '123'
a; // 123

// 不能给基本类型添加属性和方法,这里再一次证明基本类型是不可变的
var a = 123;
a.b = 456;
a.test = function () {
// todo
};
console.log(a.b); // undefined
console.log(a.test); // undefined

在了解了上面基本类型是不可变的,并且是不能给基本类型添加属性和方法的。所以当我们再来看上面的代码。先拆分一下代码:

1
2
3
4
5
6
// 首先它是不会报错的
var a = 123;
a.b = 456;
// 基本类型不可变,并且不能给基本类型添加属性和方法,
// 所以访问a.b时会打印出undefined
console.log(a.b);

接下来我们再来看看在对象原型链上添加test字段和值,在基本类型中能否访问到test字段的值呢?不卖关子了,答案是肯定的,它是能访问到并且在控制台中打印出’test test’值。
首先需要知道在JS中一切皆对象。对于基本类型的话,我们需要先了解包装对象

3. 问题衍生—包装对象

在了解完上面的问题之后,现在再来一个问题的衍生:平时我们在定义基本类型boolean、string、number时,它们没有原型链可以提供方法,但是却可以调用toString等对象原型上的方法。
其实js引擎在解析上面语句时,会把这三种基本类型解析为包装对象。什么是包装对象呢?其实就是String、Number、Boolean。

1
2
3
let str = 'hello world';
// 对于上面的基本类型,js引擎在解析时,会把它转化为包装对象(在这里是String对象)
let str = new String('hello world');

关于包装对象和引用类型区别:其实就是对象生存周期不同。包装类型只存在于一行代码的执行瞬间,当执行完毕立即被销毁;引用类型在当前作用域中都会保留
结论:基本类型不是对象,但是如果使用基本类型变量可以调用方法或者访问字段值,那是因为临时产生的包装对象
因此当我们访问test字段,其实就是访问Object对象原型上的test,它肯定是可以访问到的,因为JS中一切皆对象。其实最好的方法是大家可以看看下面这张网络上的原型链图片,图片如下所示:
原型链图
原型链图

所以最后我们综合再来看看最后输出的答案是什么:

1
2
3
4
5
Object.prototype.test = 'test test';
var a = 123;
a.b = 456;
console.log(a.test); // 'test test'
console.log(a.b); // undefined

如果你认为这篇文章对你有帮助的话,不妨来一个三连啦。