继承和原型链。作为一名前端工程师,你必须了解JavaScript中的原型、__proto__和构造函数。与基于类的语言相比,JavaScript虽然是动态的,但它本身并不提供类的实现。尽管在ES6中引入了class关键字,那只是语法糖,但JavaScript仍然是基于原型的。说到继承,JavaScript只有一种结构:object,每个实例对象都有一个私有属性__proto__,指向其构造函数的原型对象prototype。__proto__和构造函数是对象特有的属性。prototype只是函数的属性。JavaScript中的函数也是对象,所以函数不仅有原型,还有__proto__和构造函数属性functionFunc(){return1}letf1=newFunc()letf2=newFunc()和f2是Func的实例。因此,函数对象和实例对象各自的属性:Func有如下属性:prototype、__proto__、constructorf1和f2有如下属性:__proto__、constructor,其中constructor是inherited继承属性JavaScript对象是动态属性“package”(指的是它自己的属性)。JavaScript对象有一个指向原型对象的链。当尝试访问对象的属性时,它不仅会在对象上搜索,还会在对象的原型上搜索,然后在对象原型的原型上搜索,依此类推,直到找到具有匹配名称的属性或到达原型链的末端。继承方法JavaScript没有其他基于类的语言所定义的“方法”。在JavaScript中,任何函数都可以作为对象的属性添加到对象中。函数继承与其他属性继承没有区别,包括上面的“属性阴影”(这种情况相当于其他语言的方法重写)。调用继承函数时,this指向当前继承对象,而不是继承函数所在的原型对象。创建对象和生成原型链的方法1.使用语法结构创建对象varo={a:1};//o这个对象继承了Object.prototype上面的所有属性//o它没有一个名为hasOwnProperty的属性//hasOwnProperty是Object.prototype的一个属性//所以o继承了Object.prototype的hasOwnProperty//Object.prototype的原型为null//原型链如下://o--->Object.prototype--->nullvara=["yo","whadup","?"];//数组都是继承自Array.prototype//(Array.prototype包含indexOf,forEach等方法)//原型chain如下//a--->Array.prototype--->Object.prototype--->nullfunctionf(){return2;}//函数继承自Function.prototype//(Function.prototype包含call和bind等方法)//原型链如下://f--->Function.prototype--->Object.prototype--->null2.使用构造函数创建对象在JavaScript中,构造函数是实际上是一个普通的函数。当使用new操作符作用于这个函数时,可以称之为构造函数(constructor)。函数图(){this.vertices=[];this.edges=[];}Graph.prototype={addVertex:function(v){this.vertices.push(v);}};varg=newGraph();//g是生成的对象,它自己的属性包括'vertices'和'edges'。//g.[[Prototype]]在实例化g时指向Graph.prototype。//所以当g.addVertex(1)被调用时,Graph.prototype.addVertex(1)被调用。3、使用Object.create创建对象ECMAScript5引入了一个新方法:Object.create(),它创建一个New对象,使用现有对象提供新创建对象的__proto__。语法:Object.create(proto,[propertiesObject])参数:proto新创建对象的原型对象。propertiesObject可选参数,需要传入一个对象,如果指定了该参数且没有undefined,则传入对象的自枚举属性(即自己定义的属性,不是其原型链上的可枚举属性)会加上指定的属性值和相应的属性描述符到新创建的对象。可以调用此方法来创建新对象。新对象的原型是调用create方法时传入的第一个参数:vara={a:1};//a--->Object.prototype--->nullvarb=Object.create(a);//b--->a--->Object.prototype--->nullconsole.log(b.a);//1(继承)varc=Object.create(b);//c--->b--->a--->Object.prototype--->nullvard=Object.create(null);//d--->nullconsole.log(d.hasOwnProperty);//未定义,因为d没有继承自Object.prototype4,使用class关键字创建对象ECMAScript6引入了一组新的关键字来实现class。使用基于类的语言的开发人员会发现这些结构很熟悉,但又有所不同。JavaScript仍然基于原型。这些新关键字包括class、constructor、static、extends和super。类多边形{构造函数(高度,宽度){this.heigth=heigth;this.width=宽度;}}classSquareextendsPolygon{constructor(sideLength){super(sideLength,sideLength)}getarea(){returnthis.heigth*this.width}setsideLength(newLength){this.heigth=newLength;this.width=newLength;}}varsquare=newSquare(2)//console.log(square.area)//4square.sideLength=8console.log(square.area)//64performance在原型上查找属性比较耗时链,它对性能有副作用,这在性能关键的情况下非常重要。此外,尝试访问不存在的属性将遍历整个原型链。在遍历对象的属性时,会枚举原型链上的每个可枚举属性。要检查一个对象是否有自己定义的属性而不是原型链上的属性,必须使用所有对象继承自Object.prototype的hasOwnProperty方法,该方法返回一个布尔值,表示对象是否在其原型链上具有指定的属性自己的属性属性。函数图(){this.vertices=[];this.edges=[];}Graph.prototype={addVertex:function(v){this.vertices.push(v);}};varg=newGraph();//g是生成的对象,它自己的属性包括'vertices'和'edges'。//g.[[Prototype]]在实例化g时指向Graph.prototype。//所以当g.addVertex(1)被调用时,Graph.prototype.addVertex(1)被调用console.log(g.hasOwnProperty('vertices'))//trueconsole.log(g.hasOwnProperty('nope'))//falseconsole.log(g.hasOwnProperty('addVertex'))//falseconsole.log(g.__proto__.hasOwnProperty('addVertex'))//trueconsole.log(g.__proto__.hasOwnProperty('addVertex'))//false,区分大小写prototype和getPrototypeOf()Object.getPrototypeOf()方法返回指定对象的原型(内部[[Prototype]]属性的值,即__proto__)。varproto={};varobj=Object.create(proto);Object.getPrototypeOf(obj)===proto;//truevarreg=/a/;Object.getPrototypeOf(reg)===RegExp.prototype;//真的
