一道面试题,让你深入理解JavaScript的包装类
前言
包装类是JavaScript语言的一个关键特性,它帮助桥接了基本数据类型与对象之间的差距,使得基本数据类型能够像对象一样使用方法和属性,也就是说包装类的由来,是由于设计者想要让这些基本类型能像对象一样工作,可以调用方法和访问属性。而包装类就可以解决这个问题,下面我们就来介绍一下什么是包装类吧!
我们先抛出面试题吧,大佬可以先做哦,后面我们会慢慢介绍为什么:
var str = 'abc'
str +=1
var test = typeof(str)
if(test.length === 6){
test.sign = 'typeOf的返回结果可能是String';
}
console.log(test.sign);
看看你会输出什么吧!
了解JavaScript中的对象
在JavaScript中,对象是一种数据结构,它存储属性的集合,属性可以是各种数据类型,包括函数(称为方法)。对象是动态的,可以随时添加、删除或修改其属性。JavaScript的对象遵循“原型链”原则,这意味着对象可以从其他对象继承属性和方法。
JavaScript对象的特点:
- 属性:对象中的键值对,键是字符串,值可以是任何类型,包括函数。
- 方法:对象上的函数,它们为对象提供了行为。
- 构造函数:用于创建新对象的特殊函数,可以初始化对象的属性。
- 原型继承:对象可以从另一个对象继承属性和方法,形成原型链。
- 动态性:对象的属性可以在运行时添加、删除或修改。
创建JavaScript对象的方式:
创建对象的三种方式如下
- 使用对象字面量:
let obj = {};
- 使用构造函数:
let obj = new Object();
引擎自带的对象 - 自定义:
let obj = new XXX()
,这里的xxx是自己创建的一个函数对象。
为对象添加属性
对象.属性名 = value
如下:对象[a] = value
这里的a是变量,你可以随便赋值,一样的为对象添加属性a,值是value;
对象['a'] = value
如果是这样,js引擎会认为你要为对象添加一个属性为''
内部字符串,值为value,可以看下面:
原始数据类型与对象
在JavaScript中,原始数据类型包括number
, string
, boolean
, null
, 和 undefined
。这些类型的值是按值传递的,并且不像对象那样拥有属性和方法。例如,你不能直接在一个number
或string
变量上调用方法,如.length
或.toUpperCase()
。原始值(原始数据类型)是不能拥有属性和方法的,属性和方法只有对象才拥有。
好,那么再来一段一段分析前面的面试题:
var str = 'abc'
str +=1
var test = typeof(str)
if(test.length === 6){
console.log(111)
test.sign = 'typeOf的返回结果可能是String';
}
console.log(test.sign);
我们先声明了一个str变量赋值为字符串'abc',然后在执行到str+=1
时,因为string类型的变量有很强的吸引力,在和任何类型的变量进行运算时,都会转化成字符串的拼接。所以str = 'abc1'
,而函数typeof()
主要是判断传入的参数是什么类型的数据,返回参数的类型字符串string
,当传入的是数值类型,则返回字符串number
,以此类推。
我们可以检查一下这个代码是否进入到了条件判断内部,这里明显是进去了。
、
但是之前我们提到不能直接在一个number
或string
变量上调用方法,如.length
或.toUpperCase()
。
这是为什么呢?
其实这里面还有一个点,我们需要理清楚,在v8引擎的眼里,这些代码可不长这样。每一个原始数据类型的创建都是由new产生的,也就是像下面这样:
所以这些内置在原始数据类型对象(new String 返回一个对象,而且还叫字符串对象)的方法都会被实例继承,这也就是为什么,test
可以调用.length
方法。再从上面的结果中我们可以看到打印了undefined
,这又是为什么?很奇怪对吧,明明test.sign = 'typeOf的返回结果可能是String';
代码可以被执行到,为什么打印却是undefined
呢?
其实v8引擎对包装类有这样的规则,一个原始值对象,v8执行到包装类时,会通过valueOf试探包装类是不是原始值,
- 如果是原始值,则秉承原始值不能具有属性和方法的这一规则,再移除掉给包装类添加的属性
- 如果不是原始值,那就属性可以被添加到该对象上。
var str = 'abc'
str +=1 // str = 'abc1' 它是一个字符串string类型
var test = typeof(str) // test = 'string' 在v8眼里它是-> new String('string') 长度为6
if(test.length === 6){
test.sign = 'typeOf的返回结果可能是String';
//v8引擎看到可以为其添加,就默认了
//但是在执行之后会通过valueof函数进行判断test,原则就和上面一样添加的属性会被删除
}
console.log(test.sign); // new String(test).sign = undefined
如果test是原始值类型数据,必须秉承原始值不能具有属性和方法的这一规则。
注:对于字符串类型的数据而言,不管是不是原始数据类型都不修改其继承方法的值比如说查看字符串长度的方法.length
:请看下面的演示
所以这道面试题的结果是undefined,你做对了吗?
转载自:https://juejin.cn/post/7377295478280749071