JS编程秘钥:字符串解锁之旅,穿越字面量至'new'国度,探索原始值真相

362 阅读5分钟

在JavaScript这门动态类型的语言中,对象扮演着至关重要的角色,它们是数据结构的基石,也是实现复杂功能的载体。本文将深入浅出地探讨JavaScript中的对象概念,重点讲述对象的创建方式、new关键字的工作原理,以及原始值对象和包装类的特殊行为,为你揭开JavaScript对象世界的神秘面纱。

image.png

Let's go !!!

一、对象与键的字符串限制

在JavaScript中,对象是一系列键值对的集合,这里的键必须是字符串类型(或可被转换为字符串的类型,如数字和符号)。这意味着,无论你以何种形式定义对象的键,最终它们都会被解释为字符串。例如,obj[1]等同于obj["1"],因为数字1在作为键时会被自动转换成字符串。

二、创建对象的三种方式

1.对象字面量

最直观且常用的方式是对象字面量,通过一对花括号{}直接定义对象及其属性。这种方式简洁明了,适合快速创建静态结构的对象:

Javascript
解释
let user = {
  name: "Alice",
  age: 30
};

2.new Object()

使用构造函数Object创建对象是另一种方式,虽然不如字面量直接,但提供了更多灵活性,特别是用于动态创建对象时:

Javascript
let user = new Object();
user.name = "Bob";
user.age = 35;

3.构造函数(new XXX()

通过自定义构造函数(首字母大写的函数)配合new关键字,可以创建特定类型的对象,实现代码复用和对象的初始化:

Javascript
解释
function User(name, age) {
  this.name = name;
  this.age = age;
}

let alice = new User("Alice", 30);

三、new关键字的魔法

当我们用new关键字调用构造函数时,JavaScript引擎执行了一系列幕后操作:

  1. 创建一个新的空对象:首先,引擎会创建一个空对象,这个对象将成为新实例。
  2. 绑定this:接着,this被绑定到这个新创建的对象上,函数体内的代码将影响这个对象。
  3. 执行函数体:函数体内的代码被执行,为这个对象添加属性和方法。
  4. 返回this:除非构造函数显示返回一个非空对象,否则默认返回this,即新创建的对象。

四、原始值与包装类

JavaScript中的原始值(String、Number、Boolean)看似不具备属性和方法,但在特定情境下,它们会临时转换为对象,这个过程称为“装箱”(boxing),对应的临时对象就是包装类(String对象、Number对象、Boolean对象)。

例如,当你尝试访问字符串的长度属性str.length时,实际上JavaScript会将字符串str包装成String对象,然后访问长度属性,访问结束后,这个临时对象会被销毁,恢复原始值的状态,确保原始值的不变性。

然而,在V8引擎(Chrome和Node.js使用的JavaScript引擎)中,对于原始值的包装类有特殊的优化。如果检测到对原始值进行了属性赋值操作(如'hello'.name = 'world'),虽然在非严格模式下这在技术上可行,但实际上V8会拒绝这种行为,避免污染原始值,保持其不可变性。这体现了JavaScript对原始值的严谨处理,确保了语言的一致性和稳定性。

以下为代码实例,注意注意啦!!!

image.png

Javascript
1var num = 123;
2num.a = 'aaa';
3console.log(num.a);

解析:

  • 变量num存储了一个原始值123
  • 当尝试给num添加属性a时,JavaScript会自动将原始值包装成一个临时的Number对象,然后添加属性。但是,这个临时对象在属性添加后立即被销毁,因此num.a的值无法保留。
  • 执行console.log(num.a)输出的结果是undefined,因为num作为一个原始值并没有保留任何属性。
Javascript
1var str = 'abcd';
2console.log(str.length); //4

解析:

  • str存储了一个字符串原始值'abcd'
  • 访问str.length时,JavaScript会临时将字符串包装成String对象来获取长度属性。这种包装是隐式的,用户不必手动使用new String()
  • 输出结果是4,即字符串的长度。
Javascript
1var str = 'abcde';
2str.length = 2;
3console.log(str);

解析:

  • 尝试修改字符串strlength属性,如同第一段代码中给数字添加属性一样,JavaScript会创建一个临时的String对象来尝试设置length
  • 但是,字符串的长度是不可变的,因此试图修改length不会影响原始字符串。这个操作实际上被忽略。
  • 输出结果仍然是'abcde',因为字符串本身没有被改变。
Javascript
解释
1var str = 'abc';
2str += 1;
3var test = typeof(str);
4if(test.length == 6){
5    test.sign = 'typeOf的返回结果可能是String';
6}
7console.log(test.sign);

解析:

  • str += 1操作将字符串'abc'与数字1相加,结果是'abc1',这是字符串连接操作。
  • typeof(str)返回'string',这是一个字符串表示的类型名称。
  • 尝试在test(其值为'string')上添加属性sign,这里需要注意的是,test虽然是一个字符串字面量,但在非严格模式下,尝试给typeof结果赋值或添加属性时,JavaScript会将其视为一个普通的对象(一个String对象的实例),因此可以临时添加属性。
  • 但在这个例子中,由于条件test.length == 6并不成立('string'的长度是6),所以test.sign并未被赋值。
  • 最终,console.log(test.sign)输出undefined,因为在实际执行中并未给test添加任何属性sign

五、总结

总结而言,JavaScript中的对象是构建程序逻辑的基石,通过多种方式创建,new关键字背后有着精心设计的机制,而原始值与包装类的特殊行为则体现了JavaScript在设计上对简洁与安全的平衡。掌握这些核心概念,能帮助你更深入地理解JavaScript的精髓,写出更加高效、可靠的代码。