你知道new一个对象时,js做啥了吗

1. 引言

在 JavaScript 中,当创建一个新对象时,使用 new 关键字,但是 new 背后到底发生了什么呢?在本文中,我们将会从原型链、构造函数、对象属性等多个角度来分析 new 关键字的底层实现。

2. 使用 new 关键字创建对象

在 JavaScript 中,我们常常使用 new 关键字来创建一个新的对象,通常关键字后面跟随一个构造函数:

function Person(name) {

this.name = name;

}

const person1 = new Person('张三');

在上面的代码中,我们使用了 new 关键字来创建一个名为 person1 的 Person 对象。实际上,new Person('张三') 的实现过程可以分为以下几个步骤:

创建一个新的空对象;

将新对象的隐式原型指向构造函数的显式原型(prototype);

使用 this 关键字执行构造函数,并将属性和方法绑定到新对象上;

返回新对象。

上述步骤中的第一步和最后一步都比较容易理解,下面我们来详细介绍第二步和第三步。

3. 构造函数和方法绑定

第二步提到了 prototype 属性。那么 prototype 属性到底是什么?在 JavaScript 中,每个函数都有一个 prototype 属性。它是函数的一个属性,指向一个对象。这个对象被称为原型对象(以下简称为原型)。原型是一个普通对象,它有一些常规属性,最重要的是构造函数的 constructor 属性,该属性指向构造函数本身:

function Person(name) {

this.name = name;

}

console.log(Person.prototype.constructor === Person); // true

创建一个对象时,JavaScript 引擎会将对象的隐式原型指向构造函数的 prototype 属性。因此,使用 new 关键字创建一个对象的时候,对象的隐式原型就指向了构造函数的原型:

function Person(name) {

this.name = name;

}

const person1 = new Person('张三');

console.log(person1.__proto__ === Person.prototype); // true

在第三步中,我们使用 this 关键字将属性和方法绑定到了新对象上。例如,如下代码可以访问到新对象的 name 属性:

function Person(name) {

this.name = name;

}

const person1 = new Person('张三');

console.log(person1.name); // '张三'

使用 this 关键字的另一个作用是在构造函数中使用方法。例如:

function Person(name) {

this.name = name;

}

Person.prototype.sayHello = function() {

console.log('Hello, my name is ' + this.name);

}

const person1 = new Person('张三');

person1.sayHello(); // 'Hello, my name is 张三'

在上面的代码中,我们定义了一个 sayHello 方法,并将其添加到了构造函数的原型上。我们使用 this 关键字在构造函数中创建了一个属性 name。而在 sayHello 方法中,我们同样使用了 this 关键字,来访问构造函数创建的属性。

4. 原型链

在前面的例子中,构造函数的原型提供了可供对象使用的属性和方法,对象通过隐式原型链接到构造函数的原型。这个链接在 JavaScript 中被称为原型链。在这个原型链上,我们可以在指定的连续对象上查找属性。

例如:

function Person(name) {

this.name = name;

}

Person.prototype.sayHello = function() {

console.log('Hello, my name is ' + this.name);

}

const person1 = new Person('张三');

console.log(person1.hasOwnProperty('name')); // true

console.log(person1.hasOwnProperty('sayHello')); // false

console.log('sayHello' in Person.prototype); // true

person1.sayHello(); // 'Hello, my name is 张三'

在上面的代码中,我们可以发现:

hasOwnProperty 方法用于判断一个对象是否含有指定的属性,并且该属性是否为对象自身的属性。在 person1 中,name 属性为对象自身的属性,因此返回 true;sayHello 方法是构造函数原型上的一个属性,不是对象自身的属性,因此返回 false。

in 运算符用于检查指定属性是否在指定对象或其原型链中。在上例中,'sayHello' in Person.prototype 返回 true,说明该属性位于对象的原型链上。

在最后一行代码中,通过 person1 访问到了 Person.prototype.sayHello 方法。

5. constructor 属性

很多人可能会疑惑,为什么前面的例子中 Person.prototype.constructor 属性指向了构造函数本身。实际上,这是构造函数默认的原型上的属性。如果我们重新定义了构造函数的原型对象,那么就会改变这个属性:

function Person(name) {

this.name = name;

}

Person.prototype = {

sayHello: function() {

console.log('Hello, my name is ' + this.name);

}

};

const person1 = new Person('张三');

console.log(person1.constructor === Object); // true

在上面的代码中,我们重新定义了 Person.prototype 对象。因此,constructor 属性指向了 Object 构造函数,而不是 Person 构造函数。在重写原型时,一定要记得将原型的 constructor 属性设置正确。

6. 小结

本文分析了 new 关键字的底层实现。使用 new 创建对象的过程可以分为创建新对象、指向原型、绑定属性和方法、返回新对象等多个步骤。在构造函数中,使用 this 可以将属性和方法绑定到新对象上,使用 prototype 可以为对象提供原型链接以及共享相关属性和方法。在重写原型时,一定要记得将原型的 constructor 属性设置正确。

免责声明:本文来自互联网,本站所有信息(包括但不限于文字、视频、音频、数据及图表),不保证该信息的准确性、真实性、完整性、有效性、及时性、原创性等,版权归属于原作者,如无意侵犯媒体或个人知识产权,请来电或致函告之,本站将在第一时间处理。猿码集站发布此文目的在于促进信息交流,此文观点与本站立场无关,不承担任何责任。