前端深度思考(一)——原型和原型链

390 阅读2分钟

每日深入学习记录前端面试题,争取早日成为面霸

prototype

每一个js对象(null除外)在创建的时候就会与之关联另一个对象【Prototype】,这个对象就是我们所说的原型。每个对象都会从原型“继承”属性。

举个例子

var obj = {
    name: "zhangsan"
}

var newObj = Object.create(obj)

newObj.name // zhangsan

上述例子中,newObj对象的【Prototype】属性引用了obj对象,也就是说newObj对象的【Prototype】指向了obj对象,并继承了obj的属性。

几乎所有的对象在创建时【Prototype】属性都会被赋予非空的值,由【Prototype】串联起来的对象的关系链条我们就称为【Prototype】链也就是原型链,一般情况下【Prototype】链的最顶层是Object.prototype

每个函数都有一个 prototype 属性。

function Person(){}

Person.prototype.name = "zhangsan"

var person = new Person()

person.name // zhangsan

proto

每一个js对象(除null)都具有一个属性叫proto,这个属性会指向改对象的原型。

对象可以通过__proto__访问内部的【Prototype】属性,即我们可以通过__proto__访问对象的原型。

ps: __proto__是一种非标准的方法,实际开发中我们应该使用Object.getPrototypeOf()来获取对象的原型

function Person(){}

var person = new Person();

person.__proto__ === Person.prototype // true

constructor

每个原型都有一个constructor属性指向关联的构造函数,实例原型指向构造函数

function Person(){}
person.__proto__ == Person.prototype // true
Person === Person.prototype.constructor // true

Object.getPrototypeOf(person) === Person.prototype // true

补充说明:

function Person() {

}
var person = new Person();
person.constructor === Person// true

当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:

person.constructor === Person.prototype.constructor

实例与原型

 当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。

原型链

简单的回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。

Object.prototype.__proto__ === null // true