原型链

prototype和proto

弄明白原型链,我感觉首先要明白这几点:

  • 任何函数都有prototype:
    这个属性指向的是一个对象的引用,对已每一个函数(类)的实例都会从prototype属性指向的对象上继承属性用一句话说就是同一个函数创建的所有的对象,都会继承一个相同的对象。
  • 任何对象都有一个proto:
    怎么说呢。看这个例子;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function show(name){
    this.name=name;
    }
    show.prototype={
    sayName:function(){
    console.log("my name is:"+this.name)
    }
    }
    var p=new show("acorn")
    p.sayName();
    //这里输出 my name is:acorn
    我们知道 p 本身是没有sayName 这个方法的。
    这里就要说到__proto__这个属性,简单来说,每个对象都会在内部初始化一个属性,就是__proto__,当我们访问一个对象的属性,如果这个对象本身没有,就在__proto__里面找,这个__proto__指向的就是他的上一级的prototype 这里p.__proto__即为show.pertotype

如果有点绕,可以我们可以画一个原型图来更好的理解。
还是这例子

1
2
3
4
5
6
7
8
9
10
function Person(name){
this.name=name;
}
show.prototype={
sayName:function(){
console.log("my name is:"+this.name)
}
}
var p=new show("acorn")
p.sayName();

0_1464152267898_upload-ad9ef3d3-57ba-44e5-b2fa-a457fb06802b

这里Person 是一个构造函数也是一个对象,就存在prototype,和proto属性。
p 这个对象是对Person这个函数 new生成, 所以p对象中的prorojiu指向Person这个构造函数中的prototype,
而 constructor 是这个Person这个构造函数中prototype这个属性中的一个属性,指向这个构造函数本身。


什么是原型链。

经过上面的例子,但是还是发现了一个很有趣的事情。

0_1464152922849_upload-cdb68dd0-91d5-4524-bb42-523dd0be664b
在chrome浏览器中p这个对象 除了可以使用sayName 这个方法还能使用很多方法,但是prototype中只写有一个sayName 方法。其他方法是从哪来的?

我们把上个例子中的图补充完整
0_1464160653429_upload-51bb8280-8d35-4ec6-9e76-c192ab8f6298
让我们在还原下当时的情况。

1
2
3
4
5
6
7
8
9
10
11
function Person(name){
this.name=name;
}//生成一个构造函数
show.prototype={
sayName:function(){
console.log("my name is:"+this.name)
}
}//定义构造函数show的一个原型属性

var p=new show("acorn")//生成一个对象实例
p.toString();//调用这个对象实例的方法。

当我们在从调用到运行经历的过程是

  • 现在这个对象本身寻找这个属性,发现没有
  • 只好通过p.proto 前往Person.prototype里面寻找,发现并没有
  • 只好顺着Person.prototype.proto找到Object.prototype 里面 找到了toString()这个方法

所以就能看到p.后面会跟很多方法了。


关于原型链的几个例子

对String做扩展,实现如下方式获取字符串中频率最高的字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
String.prototype.getMostOften=function(){
var num,
maxNum=0,
arr={};

for(var i=0;i<this.length;i++){
if(arr[this[i]]){
arr[this[i]]+=1;
}else{
arr[this[i]]=1;
}
}

for(var key in arr){
if(arr[key]>maxNum){
maxNum=arr[key];
num=key;
}
}
return ("出现次数最多的数是:"+num+" 出现次数为:"+maxNum)
}

var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch);
//出现次数最多的数是:d 出现次数为:5

instanceOf有什么作用?内部逻辑是如何实现的?

instanceOf 用于判断当前引用类型对象是不是某个构造函数的实例。例如

1
2
3
4
5
6
7
8
var a=[1,2,3,4],
b={"acorn":1,"z-one":2},
c="acorn";

a instanceof Array //true
b instanceof Array //false
b instanceof Object //true
c instanceof Array //false 对象C不是引用类型,

其实 instanceOf 内部逻辑就是判断 当前引用类型对象的proto 与 目标对象的prototype是否为同一个。从而判断是否为当前对象的实例.
代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function show(obj,node){
if(obj.__proto__===node.prototype){
return true;
}else{
return false;
}
}
var a=[1,2,3,4]
show(a,Array)//true
这里我们发现可以。但是如果遇到这种情况?
function abc(){
this.name=[1,2,3,5,6]
}
var p=new abc();
var c=p.name;
show(c.Objecet)//false
这里却为 false.这是什么原因?

insranceOf 正确判断逻辑

inStanceOf 内部逻辑判断为:先判断当前引用对象的proto是否和目标构造函数的prototype相等,如果不相等在判断引用对象的proto.proto 是否相等

1
2
3
4
5
6
7
function show(obj,node){
if(obj.__proto__===node.prototype){

return true;
}else if(obj.__proto__.__proto__===node.prototype){
return true;
}else return false;
}