wangzhenggui/blog

javaScript深入之原型和原型链

Opened this issue · 0 comments

构造函数

我们先看一下javaScript对象的创建

function Person() {
}
var p1 = new Person();
var p2 = new Person();

当然JS中也可以简单的定义一个对象类型
var a = {}; 其实这个也是通过构造函数来创建的,只不过背后的过程JS引擎帮我们做了new Object()的操作

prototype

每一个函数都有一个prototype属性,指向由这个函数所实例化对象的原型。看下面代码分析

function Person() {
}
Person.prototype.name = 'person';
var p1 = new Person();
var p2 = new Person();
console.log(p1.name); // person
console.log(p2.name); // person

那么Person.prototype指向的就是p1和p2对象的原型对象
那什么是原型呢?每个JS对象在创建的时候(除了null),都会有一个原型对象与之关联,每个对象都会从这个原型对象上继承属性
prototype2

既然实例对象和构造函数都可以指向原型,那么原型是否有属性指向构造函数或者实例呢?

constructor

原型对象并没有属性指向实例对象,但是每一个原型对象都有一个constructor属性指向构造函数
prototype3
通过一行代码来验证上面图的关系

Person.prototype.constructor === Person
person.__proto__ === Person.prototype

实例和原型

当获取实例的属性的时候,如果当前实例对象上没有找到该属性就会去该实例对象的原型对象上去查找,如果原型对象上也没有找到,就会去原型对象的原型上去查找,一直到原型对象指向null为止,代码说明:

function Person() {
}
var person = new Person();
person.toString();

person并没有toString方法,那么执行person的toString方法为什么不会报错呢?

因为person上没有找到toString方法,他就会去他的原型对象Person.prototype上面去查找,
Person.prototype也没有找到,此时,他就会去Person.prototype的原型对象上面去查找,而他的原型对
象是Object.prototype,正好这个原型对象上面有toString方法,就“继承”了Object的原型对象上的toString
方法!
还有一个例子:

person.constructor === Person // true

这段代码执行为true;person这个实例对象是没有constructor做个属性的,那么这个属性是哪里来的呢,按照上面一个例子分析可以知道这个constructor属性来自于person这个实例对象的原型对象上的

那我们怎么能够知道对象上的属性是来自与自身还是继承(来自与原型)来的呢?

 这个地方有一个属性特别的重要了,hasOwnProperty
 在对对象的属性遍历时
for (attr in obj) {
    if(obj.hasOwnProperty(attr)) {
        // 可以判断属性是否来源与自身
    }
}
但是实例对象的hasOwnProperty属性又是哪里来的呢?
哈哈哈,其实全部来自与Object.prototype这个原型的

原型与原型之间的联系

我们实例的原型也是一个对象,既然是对象他就有他的原型对象,
实例:person 原型:Person.prototype 原型对象的原型: Object.prototype
prototype5

下面引出原型链的概念

上图中的蓝色链状结构就是原型链
从实例对象开始通过隐式原型( _ proto _ )相互链接,直到最后一个原型对象的隐式原型指向null为止,这样形成的链状关系称之为原型链
在附上一张无敌全面的原型链的图,从实例对象到构造函数,然后一直沿着这条线看下去!
prototype6