前言
浅聊 JavaScript 中的原型概念,理清 prototype 和__proto__ 的关系,图解原型链是怎样的一个结构。参考了几篇文章,简单聊聊我对原型的理解。知识水平有限,如果文章有什么错误之处,望指出。
JavaScript 中的原型
在 JavaScript 中, 原型(prototype)是联结每一个函数和对象的对象。默认情况下,每个函数都有原型对象。并且函数的原型(prototype)是可访问和可修改的。
在原型对象(prototype)上附加的属性,将会在其构造函数的所有实例中共享。
function Student(){
this.name = "Zhangsan"
this.gender = "male"
}
Student.prototype.age = 15
var studObj = new Student();
console.log(studObj.age); // 15
任何通过字面语法或者 new 关键字创建的对象都包含 __proto__属性,这个属性指向创建此对象的函数的原型对象(prototype)。
function Student(){
this.name = "Zhangsan"
this.gender = "male"
}
var studObj = new Student();
console.log(Student.prototype); // object
console.log(studObj.__proto__); // object
console.log(typeof Student.prototype); // object
console.log(typeof studObj.__proto__); // object
console.log(Student.prototype === studObj.__proto__); // true
对象的原型
建议使用 Object.getPrototypeOf(obj) 而不是 __proto__访问原型对象(prototype)。
function Student(){
this.name = "Zhangsan"
this.gender = "male"
}
var studObj = new Student();
var proto = Object.getPrototypeOf(studObj1); // 返回 Student 的 Prototype
console.log(proto.constructor) // 返回 Student 函数
原型链
function Student(){
this.name = "Zhangsan"
this.gender = "male"
}
var studObj = new Student();
studObj.toString(); // '[object Object]'
Student.prototype.__proto__ === Object.prototype // true
上述例子中,Student 中并没有定义 toString() 方法,那么它是从哪里找到 toString() 的呢?
- JavaScript 引擎检查 toString() 方法是否存在于 studObj ?
- 如果找不到,那么就会往 studObj.__proto__ 所指向的 Student 的 prototype 对象上寻找。
- 如果还是找不到,通过 studObj.__proto__.__proto__ 这个原型对象的原型对象,它会到 Object.prototype 对象查找 toString() 方法。
- 最后,我们在 Object.prototype 对象上找到了 toString() 并执行它。
- 或者,如果达到了原型链顶端,还是找不到这个方法,则返回 undefined
JavaScript 实现这种查找功能所依赖的原型的链式结构,就称为原型链。
小结
- 原型(prototype)是指函数上的一个对象。__proto__ 是一个函数实例化对象的一个属性,指向这个函数的原型。
- 通过对象上的 __proto__ 指向函数的原型对象(prototype),函数的原型的__proto__再指向 函数原型对象的原型,一层一层往上所构建的结构称为原型链。
- 原型和原型链的作用包括但不限于:
- 作为 函数实例化的对象的模板
- 通过原型链向上查找对象的属性和方法
- 通过原型链实现对象的继承
拓展
- new 做了什么
- 如何为 Object.prototype 新增属性
- class 是如何实现的,constructor 是什么