当前位置: 首页 > Web前端 > HTML5

JS原型链和继承

时间:2023-04-05 14:16:41 HTML5

原型和原型链原型原型会在创建新函数时自动生成,原型中也会有一个构造函数,它会回指创建原型的函数对象。__proto__是对象或实例中内置的[[prototype]],它指向生成该对象的对象的原型。__proto__是在浏览器中提供给我们访问的,由__proto__组成的一个点链称为原型链。原型链的整个环节是:实例对象->构造函数原型->对象原型->null。当我们访问一个对象的属性或方法时,我们首先从对象开始查找。如果对象中不存在该属性或方法,我们将向上查找原型链,直到找到该属性或方法,或者到达null时停止。这也就解释了为什么数组对象上没有push、pop、shift、unshift等方法,却可以访问到。constructor属性指向生成函数(对象)的函数(对象),如vara=function(){};varb=newa();varc={};vard=[];//以下都是trueconsole.log(b.constructor===a)//因为实例b是由构造函数生成的console.log(a.constructor===Function)//函数a其实是a的实例功能,同console.log(c.constructor===Object)//空对象c是Object的实例console.log(d.constructor===Array)//空对象c是Object的实例console.log(Object.constructor===Function)//对象本身就是一个构造函数,同理console.log(Array.constructor===Function)//数组本身也是一个构造函数//------------------------------------------------------------//首先,__proto__指向生成对象的对象的原型,//即a.prototype,原型中的构造函数,它回指创建原型的函数对象,也就是说,函数aconsole.log(b.__proto__.constructor===a)这里顺便说下instanceof,AinstanceofB是在A的原型链中寻找B的原型,找到则返回true,找不到则返回false//有个奇怪的现象,以下都返回true,这是为什么呢?//因为JS中的一切都继承自Object,除了最顶层的null,//所以在Function的原型链中可以找到Object.prototypeconsole.log(FunctioninstanceofObject)//而Object本身就是一个构造函数,所以在Function中。prototypeconsole.log(对象实例eof函数)通过??原型链实现继承从上面的分析,我们可以使用原型链来实现继承的逻辑。继承是面向对象函数中一个很重要的概念Dog(name){this.name=name;this.say1=function(){console.log(this.name)}}Dog.prototype.say2=function(){console.log(this.name)}Dog.prototype.test=1//说应该是所有Dog实例共享方法,//如果放在构造函数中,会导致没有办法共享数据,每个实例都有自己的属性和方法副本,这是一种资源的极大浪费//如果放在Dog.prototype中,然后利用原型链的特性,所有实例可以共享一个方法,//需要注意的是,由于共享一个方法,所以属性的变化对所有实例都是透明的vardog1=newDog('lalala');letdog2=newDog('wahaha');dog1.test++;//2dog2.test++;//3console.log(dog1.say1===dog2.say1)//falseconsole.log(dog1.say2===dog2.say2)//true//现在,我们可以尝试实现继承//我们通过原型链来实现继承,//之前的原型链是:Dog实例-->Dog函数-->对象-->null//那么当前的原型链需要改成一个Dog实例-->Dog函数-->Dog父类(Animal函数)-->Object-->null//第一种方案是改Dog函数原型,让他指向Animal的实例functionAnimal(){this.species='unknown';}Dog.prototype=newAnimal();//这个变化会导致原型中的构造函数改变Dog.prototype.constructor=Dog;//方案二,改变Dog函数的原型,让他指向Animal的原型函数Animal(){}Animal.prototype.species='unknown';Dog.prototype=Animal.prototype;//这个变化会导致原型中的构造函数发生变化Dog.prototype.constructor=狗;//第三种方案,调用apply或者call,将Animal的this绑定到DogfunctionAnimal(){this.species='unknown';}functionDog(name){Animal.apply(this,arguments);this.name=name;}//第四种方法,通过Object.create()方法实现继承,过滤掉父类实例属性,Dog.prototype中不会有Animal实例化数据//这个方法是还有ES6中Class使用的方法被babel编译成ES5functionAnimal(){this.species='unknown';}functionDog(name){Animal.apply(this,arguments);this.name=name;}//Dog.prototype=Object.create(Animal.prototype)varf=function(){};f.prototype=Animal.pototype;Dog.prototype=newf();Dog.__proto__=动物;//这里的改变会导致原型中的构造函数改变上面不知道是利用原型链实现了一些继承的方法。有了以上知识,我们就可以研究ES6的class类了。这个语法糖让我们更容易实现类和继承。它提供扩展,统计ic,super等关键字//这是es6的代码实现}}classChildextendsParent{constructor(n){super(4);这个.n=n;}get(){returnthis.n}set(a){this.n=a;}}//这是使用了babel编译后es5的实现//_createClass是一个自执行函数,在构造函数中绑定了静态方法和动态方法//对于static静态关键字声明的变量,会直接boundtothefunctionobjectasstaticProperty(method)//对于类中声明的函数方法,会绑定到构造函数的原型上,通过Object.definePropety方法var_createClass=function(){functiondefineProperties(target,props){for(vari=0;i