名词解析字面量对象字面量vara={};数组文字vararr=[1,2,3];正则表达式文字varreg=/[a-z]/g;属性描述符可配置:fasle是一种单向操作,并阻止使用delete运算符删除现有属性的能力。enumerable控制是否出现在属性枚举操作中,例如for..in循环。当writeable:false时,它??将阻止在[[Prototype]]链的较低级别创建(隐藏)同名属性。你不能使用=赋值,你必须使用Object.defineProperty(..)如果在[[Prototype]]链的上层某个地方发现了一个foo,并且它是一个setter,那么这个setter总是被调用。不会将foo添加(即隐藏)到myObject,也不会重新定义foosetter。对象常量:writable:false结合configurable:false防止扩展:Object.preventExtensions(..)seals:Object.seal(..)等价于防止扩展+configurable:falsefreezes:Object.freeze(..)等价toseals+writable:false示例:创建一个可写、可枚举和可配置的属性pvaro2={};Object.defineProperties(o2,{'p':{value:2,writable:true,enumerable:true,configurable:true},});Object.getOwnPropertyDescriptor(o2,"p");o2=Object.create({},{p:{value:2,writable:true,enumerable:true,configurable:true},});o2.hasOwnProperty("p")Prototype原型(显式原型)所有的函数默认都会得到一个公共的、不可枚举的属性prototype,它可以指向任何对象。__proto__是每个对象都有的属性,而prototype是只有函数才有的属性。(Function.prototype.bind方法构造的函数除外,它没有prototype属性。)[[Prototype]](隐式原型,非标准__proto__)如果默认的[[Get]]操作不能直接在对象上如果在对象上找到请求的属性,它将沿着对象的[[Prototype]]链继续处理。所有对象(包括函数)都有一个私有属性(b.__proto__)指向它的原型对象(Foo.prototype)。原型对象也有自己的原型对象(Object.__proto__),层层叠叠直到一个对象的原型对象为null。其中,以下三个隐式原型表达式与本文相同Person.__proto__非标准Object.getPrototypeOf(Person)标准[[Prototype]]概念原型图1.先了解内置对象基本内置对象String,Number,Boolean,Object,Function的[[Prototype]],Array等内置对象Date,RegExp,Error都指向Function.prototype(Object.getPrototypeOf(String)===Function.prototype)函数。prototype是Xxx.prototype==='function'的唯一类型。其他构造函数的原型都是'object'.Object.prototype.constructor===ObjectObject.prototype.__proto__===nullFunction.prototype.constructor===FunctionFunction.prototype.__proto__===Object.prototype2。接下来尝试让我们定义一个函数,看看会发生什么。定义一个函数(functionFoo)创建一个原型对象(ObjectFoo.prototype)。构造函数是之前使用new关键字调用的任何函数。functionFoo(){}Foo.__proto__===Function.prototypeFoo.prototype.constructor===Foo//functionFoo(){}Foo.prototype.__proto__===Object.prototype3.然后是new,也许应该叫delegatenew会往[[Prototype]]链上去寻找.constructornewFoo()得到一个新的对象(暂且称它为a),这个对象内部链接到Foo.prototype对象通过[[原型]]。varb=newFoo()//新角色:建立一个链接到另一个对象的对象,加上这个函数做的任何其他事情。b.__proto__===Foo.prototype4.instanceof和原型链对象有什么关系instanceofconstructor用于测试constructor.prototype是否出现在对象原型链的任何地方。//喜欢这个对象.__proto__===constructor.prototype?object.__proto__.__proto__===constructor.prototype?object.__proto__.__proto__.__proto__===constructor.prototype?...binstanceofFoo//truebinstanceofObject//trueFoo.prototype.isPrototypeOf(b)//trueObject.prototype.isPrototypeOf(b)//trueFoo.prototype={};binstanceofFoo//falsebinstanceofObject//trueFoo.prototype.isPrototypeOf(b)//falseObject.prototype.isPrototypeOf(b)//true'class'and'inheritance'ES5大家模拟了很多继承方式,但本质上是两种变体:1.原型继承。原型继承本质上是两个对象之间建立链接,其中一个对象将对属性/函数的访问委托给另一个对象。1.1使用new//假设有一个类型需要继承AnimalfunctionCat(){}Cat.prototype=newAnimal//添加一个属性Cat.prototype.name='cat'Bar.prototype=newFoo()确实创建了一个新对象,并且这个新对象确实如我们所愿链接到了Foo.prototype上。但是,它是通过Foo(..)“构造函数调用”来实现的。如果此函数有任何副作用(例如记录日志、更改状态、注册其他对象、向此添加数据属性等),这些副作用将在链接时发生(并且很可能发生在错误的对象上!),不像正如人们所预料的那样,这最终只会在创建Bar()的“后代”时发生。因此,我们剩下的选择是使用Object.create(..)创建一个正确链接的新对象,而没有调用Foo(..)的副作用。一个小缺点是我们必须创建新对象并丢弃旧对象,而不是修改提供给我们的默认现有对象。1.2使用Object.create()functionShape(){this.x=0;this.y=0;}//父类Shape.prototype.move=function(x,y){this.x+=x;this.y+=y;};//父类方法functionRectangle(){Shape.call(this);}//子类Rectangle.prototype=Object.create(Shape.prototype);//子类继承父类Rectangle.prototype.constructor=矩形;varrect=new矩形();矩形的矩形实例;//真正的rectinstanceofShape;//trueObject.create()做什么?Object.create=function(o){functionF(){}F.prototype=o;returnnewF();}这两个操作都将Bar.prototype链接到Foo.prototype://preES6//throwawaydefaultExisting`Bar.prototype`Bar.prototype=Object.create(Foo.prototype);//ES6+//修改已有的`Bar.prototype`Object.setPrototypeOf(Bar.prototype,Foo.prototype);2.构造继承构造继承,为了符合表面我们用new来调用它,我们观察它“构造”了一个对象。本质是因为new把函数调用变成了“构造函数调用”//假设有一个类型AnimalfunctionCat(name){Animal.call(this)//添加一个属性this.name=name||'cat'}如何检查“类”继承/自省:方法错误:ainstanceofFooinstanceof只能查询a的“祖先”。勉强正确:检查o1是否与o2相关(委托)的辅助函数functionisRelatedTo(o1,o2){functionF(){}F.prototype=o2;returno1instanceofF;}正确:Foo。prototype.isPrototypeOf(a)isPrototypeOf(..)回答了这个问题:Foo.prototype是否出现在a的整个[[Prototype]]链中?3.原型继承+构造函数继承函数A(name){this.name=name;}A.prototype.sayName=function(){console.log(this.name);}函数B(年龄){this.age=age;}//原型继承B.prototype=newA("mbj");//由B的实例共享varfoo=newB(18);foo.age;//18、age是自身携带的属性foo.name;//mbj,相当于foo.__proto__.namefoo.sayName();//mbj,相当于foo.__proto__.proto__.sayName()foo.toString();//[objectObject]”,等同于foo.__proto__.__proto__.__proto__.toString();//构造函数继承原型继承缺点:1.所有子类共享父类实例,如果一个子类修改了父类,其他子类继承时,会造成意想不到的后果。2.构造子类实例时,不能给父类传递参数。//构造函数继承避免了原型继承的缺点functionB(age,name){this.age=age;A.call(this,name);}varfoo=newB(18,"wmy");foo。姓名;//wmyfoo.age;//18foo.sayName();//未定义的构造函数继承缺点:1.父类原型中的函数不能复用//原型继承+构造函数继承functionB(age,name){this.age=age;A.call(this,name);}B.prototype=newA("mbj");varfoo=newB(18,"wmy");foo.name;//wmyfoo.age;//18foo.sayName();//wmy结合了以上两种方式的优点,但是占用空间较大。ES6在ES2015/ES6中引入了class关键字,但它只是语法糖,JavaScript仍然基于原型。注意:函数声明被提升,类声明没有。//类声明classRectangle{constructor(height,width,x,y){this.height=height,this.width=width,this.x=x,this.y=y;}getarea(){returnthis.calcArea()}calcArea(){returnthis.height*this.width;}staticdistance(a,b){returnMath.hypot(a.x-b.x,a.y-b.y);}}constsquare1=newRectangle(10,10,5,5);constsquare2=newRectangle(10,10,6,6);console.log(square1.area);console.log(Rectangle.distance(square1,square2));//类表达式公式letRectangle=classRectangle{constructor(){}};extendimplementsinheritanceclassRectangleextendsShape{move(){super.move();//super关键字用于调用对象父对象上的函数}}通用(不可构造)对象实现继承varAnimal={};classCat{}Object.setPrototypeOf(Cat.prototype,Animal);混入(Mixin)Object.assign(target,...sources)方法只会将源对象(...sources)自身和可枚举的属性复制到目标对象(target)。functionMyClass(){SuperClass.call(this)OtherSuperClass.call(this)}//继承一个类MyClass.prototype=Object.create(SuperClass.prototype)//混合其他Object.assign(MyClass.prototype,OtherSuperClass.prototype)//Object.assign会将OtherSuperClass的原型上的函数复制到MyClass的原型上,//使MyClass的所有实例都可用于OtherSuperClass的方法//reassignconstructorMyClass.prototype.constructor=MyClassMyClass.prototype.myMethod=function(){}//做一件事情调用继承函数时,this指向当前继承的对象,而不是继承函数所在的原型对象。varo={a:2,m:function(){返回this.a+1;}};varp=Object.create(o);//p是一个继承自o的对象p.a=4;//创建p的自身属性aconsole.log(p.m());//5派生classMyArrayextendsArray{staticget[Symbol.species](){returnArray;}}面向委托的设计varWidget={init:function(width,height){this.width=width||50;this.height=高度||50;这个.$elem=null;},插入:function($where){if(this.$elem){this.$elem.css({width:this.width+"px",height:this.height+"px"}).appendTo($在哪里);}}};varButton=Object.create(Widget);Button.setup=function(width,height,label){//委托调用this.init(width,height);this.label=标签||“默认”;this.$elem=$("
