概述
首先要知道,prototype是函数才有的属性,__proto__是每个对象都有的属性
随后,先谈一下
1.什么是prototype?
prototype对象是JS实现面向对象的一个重要机制。
在很早以前,js中是没有class这个概念的(现在js中的class是函数的语法糖)
每个函数就是一个对象(Function类型),函数对象都有一个子对象 prototype对象,在创建这个函数对象的时候,prototype会自动成为这个对象的成员。
prototype表示该函数的原型,也表示一个类的成员的集合,简称“原型”。
JS的设计者最初参考了c等的设计,引入了new关键词,用来从原型创建对象
比如
function people(name){
this.name=name
}
var a=new people("小明");
var b=new people("法外狂徒张三");
alert(a.name)//小明
为了解决每个示例的信息不共享的弊端,JS设计者引入了prototype属性
prototype 属性包含一个prototype对象(这在第一个图中也有显示)
所有实例对象需要共享的属性和方法,都放在这个对象里面
那些不需要共享的属性和方法,就放在构造函数里面
function people(name){
this.name=name
}
people.prototype = { sex : '男性' };
var a=new people("小明");
var b=new people("法外狂徒张三");
alert(a.sex);
alert(b.sex);
//都是“男性”
对于people这个函数(也就是构造器),所有基于他的实例都使用同一个prototype
通过prototype,可以实现js中对象的继承(当然js引入class后,也可以用extends实现了)
function A(){
}
A.prototype.show=function(){//扩充函数A的方法show
alert('A');
}
function B(){
alert('B');
}
B.prototype = new A();
//让B的prototype继承A的,这时B也有了show方法
执行一下A.prototype.show()和B.prototype.show()
弹出内容都是A
那么,是时候谈谈__proto__了
2.__proto__又是什么?
首先,__proto__是每个对象都有的隐性属性,这个属性指向刚刚讲的prototype
在这里创建了一个没有内容的对象,但对象里面有一个[[Prototype]],这个prototype实际上是window.Object.prototype
这里说一下,在你的JS还没开始运行,浏览器就有一个叫做window的对象
在这个对象里,有很多大家很熟悉的东西
(下面还有很多,不截了)
比如我们常用的document,也是window的一个属性
而用于取DOM的getElementById()这些就是document里面的函数
不过平时使用的时候,省略了window
(完整地是这样)
那么,因为window 对象有一个 Object 属性,而window.Object 是一个函数对象
所以,window.Object也有prototype
所有对象会像上面写prototype那样继承window.Object的prototype
window.Object.prototype 里有 toString这个函数方法,一会用它举例子
这里引用知乎上的例子
回到刚刚的代码
let obj={}
obj.toString()
首先,我们创建的这个对象没有内容,那他为什么有toString方法?(当然还有别的很多方法)
那是因为上面也讲到的,obj里有默认一个空对象__proto__指向prototype,这个prototype实际上是window.Object.prototype
这就联系起来了
调用 obj.toString 的时候,实际上调用 window.Object.prototype.toString
那么 window.Object.prototype.toString 是怎么获取 obj 的内容的呢?
那是因为 obj.toString() 等价于 obj.toString.call(obj)
同时 obj.toString.call(obj) 等价于 window.Object.prototype.toString.call(obj)
那么同理,如果有一个数组
var a=[];
a.push(1);
是怎么执行的?
首先,a是一个空的数组对象,本身也没有push方法,而数组对象和上面类似的,继承window.Array函数对象
所以毫无疑问,a.__proto__指向window.Array的prototype
所以a没有push,就向window.Array要push方法
也就是说,
arr.push 实际上调用了 window.Array.prototype.push
那么 window.Array.prototype.push 是怎么获取 a 的呢?
arr.push(1) 等价与 arr.push.call(arr,1)
arr.push.call(arr,1) 等价于 window.Array.prototype.push.call(arr, 1)
那么再联系起来,如果是
let a=[];
a.push(i=1);
a.toString();
第三句,a.toString是怎么执行的(window.Array.prototype也没有toString方法,地主家也没有余粮啊)
不要忘了上面写的,所有对象继承window.Object的prototype
你window.Array.prototype没有,你的老大window.Object.prototype有啊
所以a.__proto__没有,就去找a.proto.proto
所以 a.toString() 其实就是 window.Object.prototype.toString()
a.toString() 等价于 arr.toString.call(a)
arr.toString.call(a) 等价于 window.Object.prototype.toString.call(a)
综上,prototype是JS实现继承的方法,用于实现示例继承属性和方法
而__proto__是一个所有对象都有的空对象,指向上一级的prototype
从而实现了属性和方法的继承
这也就是JS中原型链方式的继承
(第一次写这种文,如有披露请见谅和指正)
参考:
https://www.zhihu.com/question/56770432/answer/315342130
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html
最后
以上就是虚拟豌豆为你收集整理的JS中__proto__和prototype都是什么?原型链继承解读的全部内容,希望文章能够帮你解决JS中__proto__和prototype都是什么?原型链继承解读所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复