一文带你深入理解JavaScript对象与包装类
作者:常乐hhh
对象的创建方式
- 对象字面量:最直接的方式,通过键值对的形式定义对象。
var mrPeng = { name: '彭于晏', age: 18, sex: 'boy', };
new Object()
:构造函数方式创建一个空对象。
var obj = new Object();
- 自定义构造函数:通过
new
关键字调用自定义的构造函数来创建特定类型的对象。
function Car(name, height) { this.name = name; this.height = height; } var car = new Car('Toyota', 1500);
- 模拟构造函数:模拟一个构造函数,但不使用
new
关键字,需手动实现。
function Person(name, age){ var self = {}; self.name = name; self.age = age; return self; } let p = Person('Alice', 30);
包装类
进度一
先来看看这段JS代码:
var num = 123; num.a = 'aaa'; console.log(num.a); // undefined
简单解释一下代码:代码中先声明了一个Num
,并赋值为123
,再在Num
上挂上一个属性a
,其值为字符串aaa
,然后打印输出Num
中a
的值
如果你也是这样想的话,那么你心中输出的结果不就是字符串aaa
嘛。可是输出的结果真的是字符串aaa
吗???
当然不是,我可以清楚的告诉你,该段代码输出的是undefined
。说明属性a
并没有挂在num
上,毕竟num不是对象,那竟然没挂上去,访问不存在的东西时,不应该报错吗?那又为什么输出的是undefined
呢?
首先,我们通过该段代码能知道:在JS中原始值(原始类型数据)(如数字
Number
、字符串String
、布尔值boolean
等)不能拥有属性和方法,属性和方法只有对象才能拥有。
那么如果我们将var num = 123;
改写成var num = new Number(123);
呢,我们就得到了一个对象,可是对象里面没有key
,只有一个值为123
。展开Number(123)
这个对象看一下,就会看到有一个[[PrimitiveValue]]:123
,意思就是说这是一种特殊的对象Number(123)
,这个对象就是我们说的包装类。
你说他是对象他就是对象,你说他是数字他也是数字,他能当成数字来用。
var num = new Number(123); console.log(num*2);// 输出246 num.a = 'aaa'; console.log(num.a); //输出aaa
这就说明当你将他用来当对象,他就是对象,用来当数字,他就是数字。
var num = 123;
这种创建的叫数字字面量,而var num = new Number(123);
创建的叫Number对象(数字对象)。对象是可以有属性和方法的,而原始值是没有的。
进度二
让我们来看看先这段代码:
var str ='asdf' console.log(str.length) //输出4
为什么这个能输出4呢?总不能说刚刚得到的结论是错的吧
在解决上面这个问题前先来看看这段代码:
var num = 4; num.len = 3; // console.log(num.len); // undefined
根据上面的结论,我们能知道这里的 len
是不能挂在原始值上的,输出的肯定是undefined
,没错吧。
我们来解析一下上面那段代码,看看在v8引擎是怎样实现的:
- 首先,在执行
var num = 4;
时 ,v8会将代码执行为new Number(4)
,也就是所有的字面量都会执行成这个样子,包括字符串和布尔会执行成new String()
和new Boolean()
,将其转换为对象,也就是包装类。 - 然后,v8在执行这个代码
num.len = 3;
时,就会将len属性挂在Number
这个对象上,且值为3。因为在JS中数字对象就是为了弥补数字字面量的不足,在JS中万物皆对象,所有的东西都要往对象上靠 - 最后,在执行
console.log(num.len);
之前就会突然醒悟过来,也就是在读取该值或在执行前会使用 str.valueof()方法 ,判断这个对象(数字对象)是否能转化为原始值(str.valueof()方法只能操作包装类),如果能转化为原始值,那么就会将属性和方法移除,执行delete num.len
。然而在输出的时候,num.len
先在Number
对象中查找,找不到就会声明一个len
属性再对象中,但是没有值啊,所以输出的就是undefined
,而不不是报错!!!
访问对象不存在的属性,会返回undefined
访问不存在的不变量,会报错!!
那么现在我们来解决上面那个问题:
var str ='asdf' console.log(str.length) //输出4
- 首先,一样的,在执行
var str ='asdf'
时,v8会执行为var str =new String('asdfg')
包装类 - 然后,str调用length方法,并且输出,他没有往原始值上挂属性,直接调用的话,会去对象(包装类)中查找该方法,找不到该方法就会去,该对象的原型上找,也就是我们之前提到的,按照他的原型链去查找该方法,而String这个构造函数中是有该方法的,可以直接调用。
总结
包装类(
String
,Number
,Boolean
)是JavaScript为原始值提供的对象包装器,允许我们像操作对象一样操作原始值,包括访问属性和方法,只不过属性和方法并不是原始值身上的,而是String
,Number
,Boolean
的构造函数(对象)上的。原始值是不能拥有属性和方法,属性和方法只有对象才能拥有
重要特性:每当试图访问原始值的属性或方法时,JavaScript会自动创建包装类,执行完毕后立即销毁,确保原始值的不变性。这就是为什么直接给原始值添加属性没有效果的原因。
valueOf()
:为了使valueOf
在类型转换过程中有用,它必须返回一个原始值(基本类型值)。所有的原始类型(基本类型)都有自己的valueOf()
方法。JavaScript 调用valueOf
方法来将对象转换成原始值(基本类型值)。你很少需要自己调用valueOf
方法;当遇到需要基本类型值的对象时,JavaScript 会自动的调用该方法。原始值对象,v8 执行到包装类时,会通过
valueOf()
试探该包装类是不是原始值,如果是,则秉承原始值不用具有属性和方法的这一规则,再移除掉给包装类添加的属性
以上就是深入理解JavaScript对象与包装类的详细内容,更多关于JavaScript对象与包装类的资料请关注脚本之家其它相关文章!