js 原型链的那些事儿

媒介

平常谈到js中的继续的时刻,一定会遇到原型,原型链的题目,原型内里又有prototype,__proto__,constructor属性,讲到这儿,许多同砚是否是都一头雾水,傻傻分不清楚,由于工作中用到的处所是少之又少,再加上es6又出了extends语法糖,越发不必剖析之,然则关于明白继续,原型和原型链是很主要的,明白函数和对象,明白prototype和__proto__,construct之间的关联尤为主要,不过本文对继续不予以穷究,另起一篇文章写之,本日我们只议论js中的原型和原型链。

起首,容鄙人提出一个题目。
究竟prototype和__proto__是否是指同一个东西呢?
答案天然非也。

另有一个题目,就是ie8,9下是没有__proto__的观点的,怎样处理这个题目?
这个题目在这篇文章完毕之前会申明。

如今我们先来剖析js中的对象。
js中对象是很主要的,所谓万物皆对象,然则js中对象分为两种,一般对象和函数对象

一般对象和函数对象

先来看几个例子

 function f1(){};
 var f2 = function(){};
 var f3 = new Function('str','console.log(str)');

 var o3 = new f1();
 var o1 = {};
 var o2 = new Object();

 console.log(typeof Object); //function
 console.log(typeof Function); //function
 console.log(typeof o1); //object
 console.log(typeof o2); //object
 console.log(typeof o3); //object
 console.log(typeof f1); //function
 console.log(typeof f2); //function
 console.log(typeof f3); //function 

在上面的例子中,o1 o2 o3 为一般对象,f1 f2 f3 为函数对象。
那末怎样辨别一般对象和函数对象呢?
实在很简单,通常经由历程new Function()建立的对象都是函数对象,其他的都是一般对象。f1,f2,归根结柢都是经由历程 new Function()的体式格局举行建立的。Function Object 也都是经由历程 New Function()建立的。

原型对象

接下来先说一下原型对象
在js中,每当定义一个对象的时刻,对象中都邑包括一些预定义的属性。个中函数对象的一个属性就是原型对象prototype
一般对象没有prototype,只要__proto__属性,看下面的例子

function f1(){};
 console.log(f1.prototype) //{constructor:ƒ f1(),__proto__:Object}
 console.log(typeof f1.prototype) //Object
 console.log(typeof Function.prototype) // Function,这个特别,由于Function是经由历程new Function建立的
 console.log(typeof Object.prototype) // Object
 console.log(typeof Function.prototype.prototype) //undefined

从console.log(f1.prototype) //{constructor:ƒ f1(),__proto__:Object}可以看出f1.prototype就是f1的一个实例对象,就是在建立f1的时刻,建立了一个它的实例对象,并把它赋给了prototype原型对象。代码以下

const temp = new f1();
f1.prototype = temp;

那末看到这儿,人人一定会说,为何要有原型对象?这个原型对象有什么用?
刚开始我就提到了,继续里会用到。看下下面的代码:

function Cat(name){
    this.name = name;
}
Cat.prototype.getName = function(){
    alert(this.name);
}
const qqq = new Cat('qqq');
qqq.getName();//qqq

从上面的代码中可以看出,经由历程给Cat的原型对象增加属性要领,那末Cat的实例都邑具有这个要领并可以调用之。有同砚可能会有疑问,为何在原型对象上增加了属性要领,它的实例就也可以具有这个要领呢?这就牵扯到接下来说到的原型链了。

原型链

起首,js的对象(一般对象和函数对象)都邑有__proto__属性,指向建立它的组织函数的原型对象,比方上面的例子

qqq.__proto__ === Cat.prototype;//true
Cat.prototype.__proto__ === Object.prototype;//true
Object.prototype.__proto__//null 

这就形成了原型链,会一向查找原型对象的__proto__属性,直到为null。
有几个比较特别的例子,来看一下
1.Object.__proto__ === Function.prototype // true
Object是函数对象,是经由历程new Function()建立,所以Object.__proto__指向Function.prototype。
2.Function.__proto__ === Function.prototype // true
Function 也是对象函数,也是经由历程new Function()建立,所以Function.__proto__指向Function.prototype。
3.Function.prototype.__proto__ === Object.prototype //true
Function.prototype是个函数对象,理论上他的__proto__应当指向 Function.prototype,就是他自身,自身指向自身,没有意义。
JS一向强调万物皆对象,函数对象也是对象,给他认个祖宗,指向Object.prototype。Object.prototype.__proto__ === null,保证原型链可以一般完毕。

constructor

constructor是这么定义的。
在 Javascript 语言中,constructor 属性是特地为 function 而设想的,它存在于每一个 function 的prototype 属性中。这个 constructor 保留了指向 function 的一个援用。

 Cat.prototype.constructor === Cat //true
 Function.prototype.constructor === Function //true
 Object.prototype.constructor === Object //true

这里也有要注重的
1.注重Object.constructor===Function;//true 自身Object就是Function函数组织出来的
2.怎样查找一个对象的constructor,就是在该对象的原型链上寻觅遇到的第一个constructor属性所指向的对象

总结

1.原型和原型链是完成继续的一种体式格局
2.原型链真正的继续是靠__proto__,而不是prototype,且看以下这个例子

var animal = function(name){
   this.name = name;
}
var cat = function(){};
animal.say = 'lalala';
cat.prototype = animal;
var ca = new cat();
console.log(cat.say);//undefined
console.log(ca.say);//lalala

从输出效果可以看出,虽然cat的prototype指向了animal,然则读取say属性的时刻并不会依据prototype找,ca自身虽然也没有say属性,然则看下面这段代码

ca.__proto__ = cat.prototype
cat.prototype = animal

所以ca.say输出lalala
3.之前遗留的题目,关于兼容ie的__proto__
ie9有Object.getPrototypeof()要领

   function a(){console.log("aaa")};
   const b = new a();
   Object.getPrototypeof(b) === b.__proto__//true

ie8不支持Object.getPrototypeof要领,可以连系constructor和prototype

   function a(){console.log("aaa")};
   const b = new a();
   b.constructor.prototype === b.__proto__//true

末了再思索下new()历程都做了些什么?(比方new A())

  1. 建立新对象var obj = {};
  2. 将新对象的construct属性指向组织函数,__proto__属性指向组织函数的prototype
  3. 实行组织函数,A.call(obj),将this指向obj
  4. 返回新对象(注重:假如组织函数返回this,基础范例或许不返回,就是返回新对象,假如返回援用范例,就是返回援用范例)

好了,本日就先写这么多,来日诰日连系本日的原型和原型链总结下继续以及每一个继续的优缺点~~~

参考资料

    原文作者:juan26
    原文地址: https://segmentfault.com/a/1190000016043437
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞