如果题是准备面试的时候看一遍,自己简单总结一下,一劳永逸。本文从以下几个方面入手0如何理解面向对象1创建对象的方式2记住原型链的技巧3Instanceof模拟实现4new关键字模拟实现5继承实现(一步步实现)0如何理解面向对象其实我不知道我不知道怎么回答这个问题。我只知道面试官问完这个,就代表他要问一堆继承性的问题。以下是周总讲话的引述。”面向对象是一种对应面向过程的编程思想,一般的语言都是面向对象的,JS本身也是基于面向对象构建的,比如JS本身有很多内置的类,比如Promise。你可以创建一个新的Promise.Instances来管理异步编程。还有vue,它通常会创建vue的实例。”1创建对象的方法1.对象字面量varo1={name:'o1'}varo2=newObject({name:'o2'})2.通过构造函数varM=function(name){this.name=name}varo3=newM('o3')3.Object.createvaro4=Object.create(p)2record原型链提示的内存总是有规律的。比如高中学的三角函数,需要背很多公式。如果你强迫我记住所有的公式,很容易搞糊涂。不过,如果把核心点牢牢记住,剩下的公式只需要一点点推导就可以了。原型链也是如此。如果一开始就记住几点,后面就不乱了。原型链中的关键概念:constructor,instance,constructor,proto,prototype首先要记住它们的关系instance(object)有__proto__,instance(object)没有原型constructor有prototype,prototype是一个对象,那么原型就满足上面那个。除了有__proto__之外,还包含constructor构造函数的prototype的constructor指向构造函数本身,也就是上面例子中的M.prototype.constructor===M。请记住以上三点,而下面总结的完整继承与此密切相关。其实constructor、instance、constructor、proto、prototype之间的关系在上面的例子和3点的介绍中已经介绍过了。不妨回忆一下,构造函数是一个普通的函数,只不过前面多了一个new关键字,通过new添加构造函数,生成的对象是一个实例。以上面生成的o3实例为例o3.__proto__===M.prototype//trueo3.prototype//undefinedo3.__proto__===M.prototype//trueo3实例本身没有构造函数,但是会借助原型链查找,即o3.constructor===M.prototype.constructor//trueo3.constructor===M//true总结整理完这几个关键字的关系,原型链会清楚很多3instanceof模拟instanceof的实现原理是什么?我们来看看使用[]instanceofArray//true表示左边是对象,右边是类型,instanceof是判断右边类型的原型是否在左边实例的原型链上,如下例所示[].__proto__===Array.prototype//trueArray.prototype.__proto__===Object.prototype//trueObject.prototype__proto__//null然后根据这个思路实现instanceof,会比较有印象函数myInstanceof2(left,right){if(left===null||left===undefined){returnfalse}if(right.prototype===left.__proto__){returntrue}left=left.__proto__returnmyInstanceof2(左、右)}console.log(myInstanceof2([],Array))4new模拟new的实现(简略版)的过程发生了什么?生成一个空对象这个空对象的__proto__赋值是绑定this指向返回this对象的构造函数的原型//构造函数M(name){this.name=name}//nativenewvarobj=newM('123')//模拟函数create()的实现{//生成一个空对象letobj={}//获取传入参数的第一项,改变参数类数组letCon=[].shift.call(arguments)//给空对象的原型赋值obj.__proto__=Con.prototype//Bindthis//(对应下面的用法来说明:Con是参数的第一项M,//arguments是参数['123'],//是M方法的执行,参数是'123',thisisobjtoexecutethisfunction)letresult=Con.apply(obj,arguments)return结果实例对象?result:obj}vartestObj=create(M,'123')console.log('testObj',testObj)5继承实现(分步实现)由简到繁,更直观的发现继承的原理和缺点构造方法的核心Parent1.call(this)//构造函数的方法Parent1(){this.name='Parent1'}Parent1.prototype.say=function(){alert('say')}functionChild1(){Parent1.call(this)this.type='type'}varc1=newChild1()c1.say()//报错缺点:只能继承父类构造函数的内部属性,但不能继承父类构造函数的原型对象上的属性思考:为什么call实现了继承,call的本质是什么?原型仅继承CoreChild2.prototype=newParent2()//原型函数Parent2(){this.name='Parent2'this.arr=[1,2]}Parent2.prototype.say=function(){alert('say')}functionChild2(){//Parent2.call(this)this.type='type'}Child2.prototype=newParent2()varc21=newChild2()varc22=newChild2()c21.say()c21.arr.push('9')console.log('c21.arr:',c21.arr)console.log('c22.arr:',c22.arr)缺点:c21.arr和c22.arr对应同一个引用思考:为什么是同一个引用?组合继承1结合了以上两种继承方式的优点,舍弃了缺点('say')}functionChild3(){Parent3.call(this)this.type='type'}Child3.prototype=newParent3()varc31=newChild3()varc32=newChild3()c31。say()c31.arr.push('9')console.log('c31.arr:',c31.arr)console.log('c31.arr:',c32.arr)思路:没有问题这样写了吗?答:生成实例,执行Parent3.call(this),newChild3(),即执行两次Parent3组合继承2将上例中的Child3.prototype=newParent3()改成Child3.prototype=Parent3.prototype缺点:显然无法定义子类构造函数原型私有的方法组合继承优化3更改Child3.prototypein上面的例子再次=Parent3.prototypeisChild3.prototype=Object.create(Parent3.prototype)问题就解决了。因为Object.create的原理是生成一个__proto__指向传入参数的对象。思考:有没有遗漏?如果一时想不起来,可以看看这些结果/falseconsole.log(c31.constructor===Parent3)//true所以回忆一下文章开头需要牢记的点,需要重新赋值子类构造函数的构造函数:Child3.prototype.constructor=Child3,完整版如下{Parent3.call(this)this.type='type'}Child3.prototype=Object.create(Parent3.prototype)Child3.prototype.constructor=Child3varc31=newChild3()varc32=newChild3()c31.say()c31.arr。push('9')console.log('c31.arr:',c31.arr)console.log('c31.arr:',c32.arr)console.log('c31instanceofChild3:',c31instanceofChild3)console.log('c31instanceofParent3:',c31instanceofParent3)console.log('c31.constructor===Child3:',c31.constructor===Child3)console.log('c31.constructor===父母3:',c31。constructor===Parent3)5es6inheritanceclassParent{constructor(name){this.name=name}getName(){returnthis.name}}classChild{constructor(age){this.age=age}getAge()}{returnthis.age}}es6继承记住几个注意事项1构造函数不能作为普通函数执行Parent()会报错2不允许原型重定向Child.prototype=Object.create(Parent.prototype)没用3继承是这样写的。如果上面的Child类要继承父类,改成下面这样即可。我一直有整理面试题的习惯,随时准备跳出舒适区。不知不觉中整理了229页。我将在这里与您分享。如果您需要,请点击此处获取免费问题+分析PDF
