JavaScript是两个面向第一类(蓝本第一类)词汇,除许多此基础类别,大部份人皆为第一类,大部份的第一类都是表达式(Function也是第一类)建立的。
面向第一类的承继等许多优点,像这般人类文明的发扬和繁殖。他们先说明下 大部份人皆为第一类:都是爹养娘生的 。对JS蓝本链的泰斗Object.prototype就像人类文明的先祖那样,是其它亚种变异得来的,或是是伏羲捏出的,就并非Function内部结构出的。
###1.1 原型第一类 蓝本第一类是面向第一类中的一类。区别于面向第一类,JavaScript中的蓝本第一类是 无类别(class) 的,尽管ES6中重新加入了class这一优点,但那个class就而已两个句法糖,并并非两个面向第一类类的同时实现。JavaScript透过蓝本链这一优点来同时实现第一类的承继。
/** * 透过缺省建立第一类 */ function Obj() {}; // Obj.propotype 的缺省 console.log(Obj.propotype.constructor); // function Obj var obj = new Obj(); // Obj.propotype 的实例第一类 console.log(obj.__proto__); // Obj.propotype以内标识符同时实现了用Obj.propotype蓝本第一类的缺省Obj建立了实例第一类obj的两个实例,她们的亲密关系如下图:
嘿嘿Obj.propotype左图:
function Obj(); // 缺省 Obj.propotype; // 蓝本第一类 var obj = new Obj(); // 实例第一类1.2 蓝本第一类与面向第一类的区别
许多后端开发的同学对面向第一类的第一印象可能就是Object。像Java这样的词汇中类都是承继Object的,恰好JavaScript也有Object,大家可能先入为主的认为JS中的Object就是Java中的Object,这种想法是 错误 的。
非常典型的两个例子(反例)就是许多人在问: Function和Object到底是什么亲密关系?为什么Object是Function内部结构出的?为什么Function能够内部结构出它自己? Object大兄弟,你的家庭亲密关系有点乱哦。
Object.__proto__ === Function.prototype; // true Function.__proto__ === Function.prototype; // true说好的实例的 __proto__ (隐式蓝本)等于第一类的 prototype (蓝本)啊;说好的大部份人都是第一类,表达式也是第一类啊;为什么Object反而是Function内部结构出的?这并非逗我玩呢?
引起这样的误解是因为平时他们都以缺省的名称来简称两个蓝本第一类,其实Function和Object都而已 缺省 ,JavaScript的大部份第一类都是承继Object.prototype的,并并非Object!并非Object!并非Object!Function和Object都是 function 声明的表达式,所以它们是承继Function.prototype的,是Function内部结构出的。这里就不举人类文明起源地的例子了,有点不可描述,留在第三节说。
不知道上面的反例是把你们掰直了还是掰得更弯了。。。。
举一反三这种能力对学习是很重要的,但非常忌讳先入为主的思想,虚心使人进步。
二、承继
承继的意思不难理解,就是子承父业或是是子承祖业。在ES6之前,JavaScript没有明确规定承继的概念,ES6中才使用了extentds来规范承继的方式。
2.1 new 的同时实现原理
看了很多同行同时实现js承继的方案,很多都是基于new和Object.create。其实在缺省没有返回值的情况下,new和Ojbect.create(Obj.prototype)同时实现的效果是差不多的,都能够承继Obj.prototype,大家可以跑一下下面的标识符对比效果:
function Obj() { console.log(I am Obj constructor…); this.name = Obj; } // 这里的参数绝对并非Obj,如过是Obj,则是承继了Function var obj2 = Object.create(Obj.prototype);var obj3 = new Obj();他们可以看到,对比于Object.create,new不仅承继了Obj.prototype,还调用了缺省Obj。由此他们可以试着推理下new的同时实现:
function fnew(constructor) { var newObj = Object.create(constructor.prototype); // 承继Obj.prototype constructor.call(newObj); // 调用父第一类的缺省 return newObj; } var obj4 = fnew(Obj);他们透过fnew得到的obj4和new同时实现的obj3是那样的!
2.2 extends 的同时实现原理
按照他们对蓝本链的理解,new出的实例第一类是并非也是js的承继呢?我理解的承继是祖传父,父传子,子传孙。但new出的实例第一类因为缺少缺省而失去了再承继和实例化的能力,就是说子不能传孙了,这并非我想要的承继!我要的承继是像Function这样承继Object后还具备‘生育能力’的,像extends这样的。
结合他们人类文明的行为来思考下,要想生孩子得有爹和娘啊。现在new出的实例第一类再嫁给两个缺省就可以愉快的生孩子了,让他们改造下fnew:
function fextends(protoConstructor, constructor) { varnewObj =Object.create(protoConstructor.prototype); // 承继Obj.prototype protoConstructor.call(newObj); // 调用父第一类的构造表达式 constructor.prototype = newObj; constructor.prototype.constructor = constructor; return constructor; } var ObjChild = fextends(Obj, function() {});这样ObjChild就同时实现了Function extend Object的效果啦。那我们以此分析下ES6的class和extends其实就是类似于fextends(Object, function() {})的句法糖,class A extends B 就是类似于 var A = fextends(B, function A(){})的效果咯。
2.3 instansof原理和同时实现
MDN对instansof的说明是:instanceof运算符用于测试缺省的prototype属性是否出现在第一类的蓝本链中的任何位置。比如 Function instanceof Object 就是判断Object.prototype是否出现在Function的蓝本链( __proto__ )中。
看完instansof左图和标识符,相信大家都掌握了instansof这一优点的原理。下次再有人跟你说 A instansof B 的意思是判断A是否承继B的这样不严谨的谬论,你告诉我,我给他寄一盒的刀片。
下面再给大家举两个反例: 世界上是先有Object还是先有Function?
Function instanceof Object // true Object instanceof Function // true毋庸置疑,Function(Function.prototype的缺省)和Object(Object.prototype的缺省)都是表达式,那就是承继Function.prototype的;结论就是先有Object.prototype的。