JS prototype与__proto__的联系与区别
关于这俩货,看了网上不少资料,概念好绕!!
https://blog.csdn.net/fivedoumi/article/details/51282593 读了这篇文章,感觉有点清晰,划个重点:
1、JavaScript里没有类的概念,一些需求也催生了JavaScript想模仿类这个概念,必然会涉及到一些继承问题,prototype与__proto__就催生了。
2、JavaScript没有类的概念,它里面的所有东西都是对象,但他的对象是有类型的
基本上每本教科书上都会列举的很清楚,分两种,原始类型(Primitive Types)与引用类型(Reference Types)
原始类型(5种):Boolean、Number、String、Null、Underfined
引用类型(6种):Array、Date、Error、Function、Object、RegExp (其实也不止这些)
3、用typeof
操作符判断一个变量的类型,
5种原始类型都可以用它判断出来(除了Null,Null类型返回object),但对于引用类型,只有两种返回值:function和object,本质上说明引用类型根本上只有两种,那就是Function和Object
4、Function能做但Object做不了的事情
4.1Fuction可以被执行。这是函数最基本的特征
4.2Fuction可以被当做Object的构造函数。当我们使用new
操作符后面跟着一个Function类型的变量时,这个Function变量会被当成构造函数返回一个Object对象
function Foo () { console.log("我是个Function");} foo = new Foo();
console.log(typeof Foo); //function console.log(typeof foo); //object
4.3Function有内置的prototype属性,而Object没有(prototype只有Function才有)
var a = {} var b = function() {} console.log(a.prototype) // undefined console.log(b.prototype) // {}
5、在考虑javascript的继承的时候,不应该去分别Function和Object,我们只需要统一把它们都看做对象即可
6、javascript是通过__proto__来明确继承关系的。__proto__不同于prototype,prototype只有在Function中有,而__proto__在Function和Object中都有
7、最简单的话来描述javascript中继承的本质:一个对象A的__proto__属性 所指向的 那个对象B 就是 它的原型对象(或者叫上级对象、父对象),对象A可以使用对象B中定义的属性和方法,同时也可以使用对象B的原型对象C的属性与方法,以此递归,这也就是所谓的原型链。
__proto__
,可称为隐式原型,一个对象的隐式原型 指向 构造该对象的 构造函数 的 原型(这话有点绕)
var A = {name:"wangyunok"}; var B = {weibo:"http://weibo.com/wangyunok"}; var C = {github:"https://github.com/wangyunok"} B.__proto__ = C; A.__proto__ = B; console.log(A.name); //wangyunok console.log(A.weibo); //http://weibo.com/wangyunok console.log(A.github); //https://github.com/wangyunok //这就实现了最简单的继承。
8、问:通过7中的例子 可以看出,__proto__一个东西把继承问题就都解决了么,那要prototype做甚?
答:prototype这个东西真正发挥作用的时候,是你把一个Function当做构造函数使用时,而所谓的与继承有关系,不过是因为__proto__并非官方标准中定义的属性,所以他们借助prototype这个属性模仿Java中类与类之间继承的模式
9:最精简的总结
__proto__是真正用来查找原型链去获取方法的对象。
prototype是在用new
创建对象时用来构建__proto__的对象。
在最后,再来提一遍 new过程的实质(上篇文章有过):
//模仿类 function Foo(name,weibo,github) { this.name = name; this.weibo = weibo; this.github = github; } Foo.prototype.whoami = function(){ console.log("I'm wangyunok, a coder of javascript!") } //创建对象 var foo = new Foo('wangyunok','http://weibo.com/wangyunok','https://github.com/wangyunok'); console.log(foo.name); //wangyunok console.log(foo.weibo); //http://weibo.com/wangyunok console.log(foo.github); //https://github.com/wangyunok foo.whoami(); //I'm wangyunok, a coder of javascript!
第一步,Foo函数被执行。Foo函数在foo的作用域下被执行,所以这里this指代的就是foo,这样name、weibo、github三个属性才会被当做foo的属性被创建,如果你在函数Foo中写一个console.log()
语句,它也会在结果中打印出来,见上面代码2。
第二步,将foo.__proto__指向Foo.prototype。这才是javascript构造函数的精髓所在,foo就继承了Foo.prototype中(以及其原型链上)的属性与方法。下面代码可以佐证:
console.log(foo.__proto__ === Foo.prototype)//true
(通过这个理解 7中 构造该对象的构造函数的原型,即 Foo 构造了 foo对象,此时foo的 __proto__ 就指向Foo的 原型)
这样一个鲜活的foo就被创建出来了。
666