引言
在JavaScript中,对象是构建应用程序的基础。为了更好地理解和使用这些对象,我们需要掌握几种创建对象的方法,其中最核心的就是构造函数、原型和实例之间的关系。理解这三者的关系,能够帮助我们编写更高效,更好维护的代码。
在JavaScript中创建对象的方法
- 对象字面量:使用
{}包住属性和方法来创建对象,这种方法简单,直接,但可能不够灵活。
let cao = {
name: '小超',
}
let fan = {
name: '范总',
age: 17,
}
- 构造函数: 构造函数是一种更传统的面向对象编程方式,它能够使用
new关键字来创建多个具有相同属性和方法的对象实例。
function Person(name, age) {
this.name = name;
this.age = age;
}
const wen = new Person('文', 18);
console.log(wen.name, wen.age);
- 类(class): ES6引入了
class关键字,使得JavaScript中的面向对象编程更加直观和简洁。
class Person {
constructor(name,age) {
this.name = name;
this.age = age;
}
eat() {
console.log('吃饭');
}
}
let wei = new Person('威',18);
什么是原型
每个函数在JavaScript中都是一个对象,并且这些函数对象都有一个prototype属性。这个prototype属性指向一个对象,该对象包含可以被特定类型的所有实例共享的属性和方法。这种机制是JavaScript实现继承的关键部分,特别是在使用构造函数或类创建对象时。
function Person(name, age) {
console.log(this);
this.name = name;
this.age = age;
}
// 每个函数都有一个原型对象
Person.prototype = {
eat: function() {
console.log(`${this.name}在吃饭`);
}
}
const xiao = new Person('肖',18)
xck.eat();
在上面这个例子中:
Person是一个构造函数。Person.prototype是一个对象,它包含了eat方法。- 当我们使用
new Person()创建xiao时,这个对象会通过其内部的__Proto__指向Person.prototype。 - 因此,
xiao可以访问eat方法。
构造函数和实例对象都能指向实例原型,那么实例原型能否指向构造函数呢?
当然可以,每个原型都有一个constructor属性,指向该关联的构造函数。
更新关系图
什么是原型链
当试图访问一个实例对象的属性时,如果该对象本身没有这个属性或方法,JavaScript引擎会查找与对象关联的原型中的属性,如果还找不到,就去找原型的原型,直到最顶层为止,这样就形成了原型链。
function Person(name,age) {
console.log(this);
this.name = name;
this.age = age;
}
Person.prototype.name = '陈';
const wu = new Person('吴',19);
console.log(wu.name);
delete wu.name;
console.log(wu.name);
可以看到,删除属性之前,结果是'吴',删除属性之后,该实例没有了
name属性,此时它就会顺着原型链,也就是在它的原型中查找,而Person.prototype中的name属性的值为'陈',所以删除name属性后,实例中name属性的值变成了原型中name属性的值。
那如果wu的原型中也没有name属性会怎么样呢,它会去原型的原型中查找,直到找到为止,若没找到的话,则返回undefined。
通过这种方式,JS 实现了它的继承机制,它通过对象的__proto__逐步向上查找,形成了一条原型链。
如图,红色的就是原型链。
结语
在JavaScript中,构造函数、原型和实例是创建和管理对象的三大核心概念。通过本文的介绍,我们了解了它们之间的关系以及如何利用这些机制来构建高效且可维护的代码。