JavaScript 原型和原型链
在阅读本文章之前,已经默认你了解了基础的
JavaScript
语法知识,基础的
ES6
语法知识 。本篇文章旨在为
JavaScript继承
打下基础
原型
- 在
JavaScript
里任何一个函数都有一个
prototype
属性,这个属性称之为原型
function Person() {this.name = "name";}console.log(Person.prototype)
而
Person.prototype
实际上是一个包含
constructor
属性的对象
而
constructor
实际上就是构造函数本身
// Person.prototype{constructor: Person}
-
Person.prototype
指向的对象很特殊(原型链学完就明白为什么特殊了),可以被实例所共享,可以作为实例的属性直接调用
const obj1 = new Person();const obj2 = new Person();console.log(obj1.constructor === obj2.constructor) // trueconsole.log(obj1.constructor === Person) // true
这意味着,我们可以在
Person.prototype
上加一些共享属性或者方法,然后直接在实例中共享
Person.prototype.eat = function() {console.log("eat");}// 现在obj1.eat(); // "eat";obj2.eat(); // "eat";
上面,我们简要的说明了原型,以及原型的作用,下面我们探索原型链
原型链
我们先看一个小例子
function Person() {this.name = "name";}const p = new Person();p.toString(); // [object Object]
我们并没有在
Person.prototype
上定义
toString
这个方法,按理来说当我们调用的时候应该报错 ,然而浏览器却 "不厚道" 的输出了
[object Object]
要解释这个原因,还有 "很长的路" 要走。
- 首先任何实例化出来的对象都拥有
__proto__
属性,这个属性指向构造函数的
prototype
console.log(p.__proto__ === Person.prototype) // true
之前我们写过这样的代码
Person.prototype.eat = function() {console.log("eat");}obj1.eat(); // "eat";obj2.eat(); // "eat";
我们惊讶的发现,
obj1
上也可以拥有
eat
方法了。
- 如果一个对象上没有这个属性,他就会去他的
__proto__
属性对应的对象上去找,如果还没有就继续这个对象的
__proto__
上去找
那么
Person.prototype
是否有
__proto__
呢
console.log(Person.prototype.__proto__);
在这里输出的结果中有
constuctor: Object
之前提到
constuctor
其实就是构造函数本身,因此
console.log(Person.prototype.__proto__ === Object.prototype); // true
我们在
Object.prototype
中发现了这个方法,并进行调用
console.log(Object.prototype.hasOwnProperty("toString")) // trueObject.prototype.toString.call(p); // [object Object]
至此原型链基本是说完了,有兴趣的可以探究一下
-
Object.prototype
是否有
__proto__
?
- 构造函数是否也是被实例化出来的?
- 数组的原型链是什么样的
对于第三题,有兴趣的可以自己画一下图
console.log(Array.prototype.__proto__ === Object.prototype) // true