关于“对象” 有哪些你不知道的事

85 阅读5分钟

一、引言

对象是JavaScript中的核心概念之一,理解对象、构造函数及包装类等相关知识对于深入理解掌握JavaScript至关重要,接下来我们将展开讲讲那些在JavaScript中我们不知道的关于“对象”的知识点。

二、万物皆对象

JS中,“万物皆对象”这一理念贯穿始终。JavaScript的数据类型可分为原始类型和引用类型。

🔍 原始类型:String(字符串)Number(数字)Boolean(布尔值)undefinednullsymbolbigint

🔍 引用类型:function(函数)array(数组)object(对象)

原始类型直接储存在栈内存中,引用类型的值存储在堆内存中,栈内存中存储的是指向堆内存中实际数据的引用。

三、 创建对象的方式

(一) 创建对象字面量

对象字面量是创建对象最简洁的方式,通过 花括号 {} 来定义对象,并在其中使用键值对来表示对象的属性和值。

示例:

let person = {
    name: "张三",
    age: 18,
    sayHello: function() {
        console.log("Hello!");
    }
};

该示例中,person对象有两个属性nameage,及一个方法sayHello

(二)new Object()

使用 new Object()也可以创建一个空对象,然后再为其添加属性和方法。

示例:

let newObj = new Object();
newObj.name = "张三";
newObj.age = 35;
newObj.sayHi = function() {
    console.log("Hi!");
};

这种方法较为繁琐,不如对象字面量简洁直观,但在某些动态创建对象场景中有其独特的用途。

(三)new 调用自定义的构造函数

当需要批量创建具有相似结构和行为的对象时,构造函数就派上了用场。构造函数本质上是一个普通函数,但当它被new关键字调用时,就用于创建对象实例

示例:

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayGoodbye = function() {
        console.log("Goodbye!");
    };
}

let p1 = new Person("张三", 17);
let p2 = new Person("李四", 18);

上述示例中,Person是一个构造函数,通过new Person()可以创建多个Person对象实例,每个实例都有自己的name、age属性和sayGoodbye方法。

四、关于‘构造函数’

(一)构造函数的作用

构造函数主要用于批量创建对象,它可以为对象示例初始化属性和方法。当我们需要创建多个具有相同属性和行为的对象时,使用构造函数可以提高代码的复用性和可维护性。

(二)构造函数的调用方式

当一个函数被new关键字调用时,它就成为了构造函数。

示例:

function Car(make, model) {
    this.make = make;
    this.model = model;
    this.drive = function() {
        console.log("Driving the " + this.make + " " + this.model);
    };
}

let myCar = new Car("Toyota", "Corolla");
myCar.drive();

上述示例中,Car函数在被new调用后,创建了一个Car对象实例myCar,并为其初始化了make和model属性以及drive方法。

(三)普通函数与构造函数的区别

普通函数与构造函数在本质上并没有区别,它们都是函数。区别在于调用方式,当函数被直接调用时,它是普通函数;当被new调用时,它就是构造函数。

示例:

function greet() {
    console.log("Hello!");
}
greet(); // 普通函数调用

function Animal(name) {
    this.name = name;
}
let dog = new Animal("小茂密"); // 构造函数调用

在上述示例中,greet是普通函数,直接调用执行打印操作;Animal函数在被new调用时,用于创建Animal对象实例。

五、在构造函数中,new做了什么

当使用new关键字调用构造函数时,会发生以下几个步骤:

(一)创建一个this对象

new操作符首先会创建一个空的对象,这个对象就是this所指向的对象,它将作为新创建对象的实例。

(二)执行构造函数中的代码

将this对象绑定到构造函数的执行环境中,然后执行构造函数中的代码,为this对象添加属性和方法。

function House(rooms, floors) {
    this.rooms = rooms;
    this.floors = floors;
    this.showDetails = function() {
        console.log("This house has " + this.rooms + " rooms and " + this.floors + " floors.");
    };
}

let myHouse = new House(5, 2);
myHouse.showDetails();

在上述示例中,new House()调用时,构造函数为myHouse对象添加了rooms、floors属性和showDetails方法。

(三)return这个this对象

最后,构造函数默认返回this对象,即新创建的对象实例。如果构造函数中显式地返回了一个非原始类型的值(如另一个对象),则new操作符返回的是这个显式返回的值,而不是this对象。

六、包装类

(一)包装类的概念

在JavaScript中,当用户定义一个原始类型的字面量时,V8引擎默认会执行new XXX()操作,将其包装成对应的包装类实例。例如,字符串字面量会被包装成String对象,数字字面量会被包装成Number对象,布尔值字面量会被包装成Boolean对象。

实例:

let strLiteral = "world"; 
console.log(strLiteral.length);
// 虽然 strLiteral 是原始类型字符串,但可以调用 length 属性,因为被包装成了 String 对象

(二)包装类的自动拆箱与装箱

🔍 一个包装类的实例对象,在参与运算时会自动拆箱成原始类型。

示例:

let numObj = new Number(5);
let result = numObj + 3; // numObj 自动拆箱为原始类型数字 5,然后进行加法运算 
console.log(result); // 8

🔍 当需要使用包装类的属性和方法时,原始类型会自动装箱成包装类对象。

示例:

let bool = true; 
let boolObj = bool.valueOf(); // 将布尔值装箱为 Boolean 对象,以便使用其方法 
console.log(boolObj.toString()); // "true"

(三)弱类型语言与包装类的特性

由于 JavaScript 是弱类型语言,只有在赋值语句执行时才会判断值的类型。当值被判定为原始类型时,会自动将包装对象上添加的属性移除。

示例:

let str = "test"; 
str.foo = "bar";
console.log(str.foo); // undefined,因为 str 是原始类型字符串,添加的属性被移除

上述示例很好地体现了JS中包装类的动态特性和弱类型语言的特点。

八、总结

至此,所有关于对象的知识点都尽数了解,理解万物皆对象的理念,掌握创建对象的不同方式,深入了解构造函数的原理,new操作符的执行过程和包装类的特性,我们对JaveScript的掌握将更进一步。