学习到 JavaScript 原型这个地方的时候,最开始是比较懵的状态,今天早上起来看了下红宝书中对于原型的解释,慢慢的也就有了些了解,但是解释的比较官方。接下来,我会把自己的理解分享下来,尽量用通俗易懂的话来描述。如果有什么不对的地方,希望大家指正。
1、原型
1.1 prototype
JavaScript 中,当创建一个函数的时候,这个函数就会自动创建一个 prototype
属性,该属性指向的就是原型对象。既然这个属性指向了原型对象,那么他能不能使用原型中的属性和方法呢?
先来看创建的实例访问构造函数中的属性和方法
// 构造函数
function Me() {
this.uName = "shuang";
this.sayName = function () {
console.log(this.uName);
};
}
let m1 = new Me(); // 创建实例
console.log(m1.uName) // shuang;
m1.sayName(); // shuang
下面我尝试用原型来创建新的属性和方法
// 构造函数
function Me() {
this.uName = "shuang";
this.sayName = function () {
console.log(this.uName);
};
}
let m1 = new Me(); // 创建实例
console.log(m1.uName) // shuang;
m1.sayName(); // shuang
Me.prototype.sex = "男";
Me.prototype.saySex = function () {
console.log(this.sex);
}
console.log(m1.sex); // 男
m1.saySex(); // 男
通过上面的案例可以很清楚的认识到,可以通过 prototype
指向的原型对象中添加新的属性和方法,并且可以通过实例进行访问。
这里总结出来,每一个函数被创建的时候,会创建一个 prototype
属性,这个属性是一个对象,这个对象就是通过调用构造函数创建的对象的原型。在原型对象上面定义的属性和方法可以被实例共享。不仅可以在构造函数中创建属性和方法,也可以将属性和方法直接赋值给他们的原型。
用一个图来描述构造函数与原型的关系
1.2 __proto__
(前后各是两个下划线)
上面了解到了构造函数与原型对象中通过 prototype
这个属性进行联系。我发现,上述代码创建的实例中,也可以访问到通过原型创建的属性和方法,那么考虑,实例与原型之间是否有某种联系呢?
这里稍微做一个小科普,在红宝书中有这么一段话:
每次调用构造函数创建的一个新实例,这个实例的内部有一个[[Prototype]]
指针就会被赋值为构造函数的原型对象,因为 JavaScript 脚本中没有访问这个[[Prototype]]
特性的标准方式,但是 Firefox、Safari 和 Chrome 会在每个对象上暴露__proto__
属性,通过这个属性可以访问对象的原型。
如果打印一下构造函数的prototype
属性就会在浏览器中出现下面代码:
// 定义构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 获取 构造函数 的 prototype 属性
console.log(Person.prototype);
这里在允许我做一个科普,上面的代码结果是我在 chrome 90版本之前执行的结果,现在最新的 chrome 浏览器将
__proto__
这个属性变成了[[Prototype]]
,正是红宝书提到的。
但是不用担心,因为在编写代码的时候,依旧没有[[Prototype]]
这么一个属性,所以依旧可以使用__proto__
这个属性来访问原型,只是说今后如果在 chrome 浏览器中遇到了[[Prototype]]
这个属性,要知道他其实就是__proto__
属性。
光说不够直白,下面我用最新版的 chrome 浏览器打印一下构造函数的prototype
属性:
// 构造函数
function Me() {
this.uName = "shuang";
this.sayName = function () {
console.log(this.uName);
};
}
// 获取 构造函数 的 prototype 属性
console.log(Me