js 原型链、__proto__、prototype

本文由用途意义,进行脑测解析,从需求角度走一遍原型链的发展。


用对象模拟类的继承

js中没有类(没有类,没有类,重要的事情说3遍)只有对象,怎么才能做到继承的效果?

var a={x:1}
var b={};
b.__proto__=a;

接下来进行约定,当访问b.x但不存在时,就自动去访问b.__proto__.x

逻辑上就这么一回事。不过需要注意,这里说的只是访问。b.x=2这种是无法对a,也就是b.__proto__造成影响的;同时这个为b赋予了x属性,b.x将覆盖掉b.__proto__.x

通俗点总结,就是给对象挂一个父对象,当对象没有相应属性时,就去它父对象那里找。


__proto__指向构造函数的prototype

var A=function(){ }
var b = new A();

这个时候又该怎样用__proto__实现继承效果?

首先函数也是一个对象,除了A();这样以函数调用,还能A.x=1;这样把A当普通对象使用(下文中函数、函数对象,都是一回事)。知道这个后实现继承很简单,增加一个属性即可:

A.prototype={constructor: A};//提醒一下怕忘记了,这里相当于A增加了属性prototype
A.prototype.x=1;
b.__proto__ = A.prototype;

js会为每个这样new出来的对象做这个处理,自己不用写。

显然,这里的A.prototype就类似与一开始例子中的a,往A.prototype增加属性,那么所有new A()出来的对象都能访问到这个新的属性。

为什么js要默认增加constructor: A这个属性到prototype中?这里与new操作符有关,是为了解决另一个问题。另外常说的prototype的构造函数,就是指这个。

总结:
反正就是通过new 函数()这样出来的对象,其__proto__默认指向构造函数(这里说的是函数对象本身,它跟在new后面也被称作构造函数)的prototype属性。

实际上我觉得一般不以这个方法进行有大量属性的继承,一是查找有无属性的效率问题,二是new时构造方法把this改为新建对象的指向就足以完成属性的添加和赋值,无需操作prototype进行继承。


值得注意的要点

__proto__、prototype是什么一回事相信已经了解,剩下的就是经常把人绕晕的Object.prototype、Function.prototype这些东西了。

先提一下,ObjectFunction都是一个函数对象,跟上面的A差不多,既能new Object()也能Object.xxx这样用。

Object:

1.所以var b=new Object();后,b.__proto__===Object.prototype这个应该没有什么疑问。

2.新的标准中可用b=Object.creat(a),可当作是b=new Object(); b.__proto__=a,还是这套操作,问题不大。

3.如果是var b={}这种直接通过字面量创建对象,js会自动进行b.__proto__=Object.prototype,知道后问题也不大。

4.就是默认情况下,你不手动搞__proto__、prototype的指向,最终__proto__都会去指向Object.prototype。

5.Object.prototype
本质上跟前面示例中的prototype没什么不同,只是这个prototype会被js自动增加一些属性

6.Object.prototype.__proto__===null 跟在c++/java中遍历链表一样,当__proto__为null时说明到头了。当作js自动设置上去的就行,没什么其他特殊

7.Object.__proto__===Function.prototype 下面再讲。

Function:

1.所有的函数对象都是Function的实例。
不是说没有类吗,这个实例又是什么意思?
emmm,习惯说法而已,具体什么操作没研究也不懂,或许当作js自动这样做:

var f=function(){}
f.__proto__=Function.prototype;

//或者这样理解
var f=new Function();
然后把你的代码放进去f

2.Function.__proto__===Function.prototype;
前面提过Object、Function都是一个函数对象,把它们代入第1点例子的f就行。上面第6点同理。

按照理解,可能会这样的疑问:Function.__proto__指向构造函数(再次提醒,是一个对象)的prototype,所以Function这个对象的构造函数是它自己?自己创建自己么?
额。。。我觉得这种操作可能就是为了统一,只要记住“所有函数对象的__proto__都是Function.prototype”就行。

3.Function.prototype.__proto__===Object.prototype;
没什么特别的,把Function.prototype代入上面Object第1点的b就行,不要特殊看待,硬要说与b不同的话,只是因为“函数对象的prototype默认会被增加一个constructor属性”而已,没什么大问题


总结:

1.我们在js中说的“类型”,可以说只是习惯用语,实际上仍旧是没有所谓的类概念的,只有用对象来“模拟类”。

2.prototype就是指向一个普通对象prototype=new Object(),只不过这个对象被添加其他一些属性后,再被自动放到到函数对象的属性中。

3.__proto__就是 原型/原型对象,不断的找原型的原型最终到--->Object.prototype--->Object.prototype.__proto__ (null)。原型对象可能是一个普通的对象;也可能是js自动放入到函数对象的prototype

4.我觉得js这套东西根本目的是批量为对象赋予属性同时减少代码冗余,上面解析的ObjectFunction、例子中的A都只是函数对象,不是像java一样的类,平时说对象的类型只是方便日常交流,instanceof也只是很粗暴的递归比较对象__proto__ === 函数对象.prototype这种。把类的概念丢掉,保留对象、属性这概念,从这出发又回头去实现“类”、“继承”这东西,就出来这么套东西。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值