[JS]彻底理解原型链

Posted ouyangshima

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JS]彻底理解原型链相关的知识,希望对你有一定的参考价值。

从一张图看懂原型对象、构造函数、实例对象之间的关系

function Dog();  
  
Dog.prototype.name = "小黄";  
Dog.prototype.age =  13;  
Dog.prototype.getAge = function()  
    return this.age;  
  
  
var dog1 = new Dog();  
var dog2 = new Dog();  
  
dog2.name = "小黑";  
console.log(dog1.name); // 小黄 来自原型  
console.log(dog2.name); // 小黑 来自实例  

//图中的一些关系  
dog1.__proto__ === Dog.prototype  
Dog.prototype.__proto__ === Object.prototype //继承Object 下面原型链说  
dog1.__proto__.__proto__ === Object.prototype  
Dog.prototype.constructor === Dog   
Dog.prototype.isPrototypeOf(dog1)  
  
//获取对象的原型  
dog1.__proto__  //不推荐  
Object.getPrototypeOf(dog1) === Dog.prototype   //推荐 

1、prototype

在JavaScript中,每个函数都有一个prototype属性,这个属性指向函数的原型对象。

function Person(age) 
    this.age = age       

Person.prototype.name = 'kavin'
var person1 = new Person()
var person2 = new Person()
console.log(person1.name) //kavin
console.log(person2.name)  //kavin

上述例子中,函数的prototype指向了一个对象,而这个对象正是调用构造函数时创建的实例的原型,也就是person1和person2的原型。

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

2、__proto__

这是每个对象(除null外)都会有的属性,叫做__proto__,这个属性会指向该对象的原型。

function Person() 

var person = new Person();
console.log(person.__proto__ === Person.prototype); // true

3、constructor

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

function Person() 

var person = new Person();

console.log(Person.prototype.constructor === Person) // true
console.log(person.__proto__ === Person.prototype) // true

4、实例与原型

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

function Person() 


Person.prototype.name = 'Kevin';
var person = new Person();
person.name = 'Daisy';
console.log(person.name) // Daisy

delete person.name;
console.log(person.name) // Kevin

在这个例子中,我们给实例对象 person 添加了 name 属性,当我们打印 person.name 的时候,结果自然为 Daisy。

但是当我们删除了 person 的 name 属性时,读取 person.name,从 person 对象中找不到 name 属性就会从 person 的原型也就是 person.__proto__ ,也就是 Person.prototype中查找,幸运的是我们找到了 name 属性,结果为 Kevin。但是万一还没有找到呢?

原型链

原型链是实现继承的主要方法。

先说一下继承,许多OO语言都支持两张继承方式:接口继承(只继承方法签名)、实现继承(继承实际的方法)。

由于函数没有签名,在ECMAScript中无法实现接口继承,只支持实现继承,而实现继承主要是依靠原型链来实现。

原型链基本思路:

利用原型让一个引用类型继承另一个引用类型的属性和方法。

每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针(contructor),而实例对象都包含一个指向原型对象的内部指针(__proto__)。如果让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型对象的指针(__proto__),另一个原型对象也包含着一个指向另一个构造函数的指针(constructor)。假如另一个原型又是另一个类型的实例……这就构成了实例与原型的链条。

原型链基本思路(图解):

function Animal()  
    this.type = "animal";  
  
Animal.prototype.getType = function()  
    return this.type;  
  
  
function Dog()  
    this.name = "dog";  
  
Dog.prototype = new Animal();  
  
Dog.prototype.getName = function()  
    return this.name;  
  
  
var xiaohuang = new Dog();  
//原型链关系  
xiaohuang.__proto__ === Dog.prototype  
Dog.prototype.__proto__ === Animal.prototype  
Animal.prototype.__proto__ === Object.prototype  
Object.prototype.__proto__ === null  

Xiaohuang这个Dog的实例对象继承了Animal,Animal继承了Object。

如何理解原型和原型链

每个函数对象都有一个prototype属性(指针),它是一个指向原型对象的指针,原型对象里包含着所有实例共享的属性和方法。同时原型对象里也有一个constructor属性(指针)指回了其对应的构造函数。

每个对象实例都会在其内部初始化一个__proto__属性(指针),它是一个指向prototype(原型对象)的指针,当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会通过__proto__去prototype里找这个属性,这个prototype又会有自己的__proto__指向自己的原型对象, 于是就这样一直找下去,形成了原型链的概念。

原型链实现的是对属性的查找,一直顺着原型链查找到Object对象,如果没查到返回undefined,还有值得注意的一点就是,所有对象里的__proto__都是对原型对象的一个引用,而不是副本,所以当我们修改原型时,与之相关的对象也会继承这一改变。

javascript 对象中的 constructor属性的作用?

以上是关于[JS]彻底理解原型链的主要内容,如果未能解决你的问题,请参考以下文章

[JS]彻底理解原型链

js中原型和原型链理解

JavaScript中原型对象的彻底理解

一文带你彻底理解 JavaScript 原型对象

[JS]彻底明白了原型

JavaScript之彻底理解原型与原型链