//创建Object的实例,然后添加属性和方法letperson=newObject();person.name="AAA";person.sayName=function(){};//对象字面量模式letperson={name:"AAA",sayName:function(){}};6.1.1属性类型
用特性(attribute)描述属性(property)的各种特征
两种属性:1.数据属性2.访问器属性
1.数据属性
[[configurable]]:能否delete属性后从而重定义属性,能否修改属性的特性,能否把属性修改为访问器属性。默认true。改为false后不可逆。
[[enumerable]]:能否for-in循环返回属性。默认true。
[[writable]]:能否修改属性的值。默认true。
[[value]]:属性的数据值。默认undefined。
letperson={name:’AAA’},如此直接定义时特性取默认值和数据值。
1.访问器属性
[[get]]:读取属性时调用的函数。默认undefined。
[[set]]:写入属性时调用的函数。默认undefined。
6.1.2定义属性的特性
定义单个
Object.defineProperty(obj,property,descriptor);//descriptor描述符descriptor={configurable:true,enumerable:true,writable:true,value:"example"};定义多个
Object.defineProperties(obj,{property:{configurable:true,enumerable:true,get:function(){},set:function(){}}});6.1.3读取属性的特性
Object.getOwnPropertyDescriptor(obj,property)
Object.getOwnPropertyDescriptors(obj)
6.2.1工厂模式
用函数来封装以特定接口创建对象的细节
functioncreatePerson(name){letobj={name:name,sayName:function(){alert(this.name);}};returnobj;}letperson1=createPerson("lpr");虽然解决了多个相似对象的问题,但却没有解决对象识别的问题(即怎么知道一个对象的类型)
6.2.2构造函数模式
functionPerson(name){this.name=name;this.sayName=function(){alert(this.name);};}letperson1=newPerson("lpr");letperson2=newPerson("lpd");跟工厂模式的不同:
改造函数实际经历4个步骤
这样创建的实例都有一个constructor(构造函数)属性,该属性指向Person
person1.constructor===person2.constructor===Person
person1instanceofObject//true
person1instanceofPerson//true
因此可以得出实例来自同一种类型,但是其中的方法不是同一个Function实例
解决方案:
functionPerson(name){this.name=name;this.sayName=sayName();}functionsayName(){alert(this.name);}这样做确实解决了两个函数做同一件事的问题,新问题:1.全局定义的方法直给某一个对象调用,全局作用域名不副实2.多个方法多次在全局定义函数,没有封装性
6.2.3原型模式
Person.prototype.isPrototypeOf(person1);//trueObject.getPrototypeOf(person1)===Person.prototype;//true2.原型与in操作符
person1.hasOwnProperty("name");//是否自身存在属性
alert("name"inperson1);//属性是否存在于自身或原型中
可组合判断属性存在实例还是原型中
Object.keys(obj);//获取对象上自身可枚举的属性(不含Symbol),返回结果是key的数组
Object.getOwnPropertyNames();//获取对象上自身所有(可枚举+不可枚举)的属性,如'constructor'
3.更简单的原型语法
functionPerson(){}Person.prototype={constructor:Person,//每创建一个函数会同时创建它的prototype对象,这个对象也会自动获取constructor属性。//如果不重新指定,即实例的constructor不指向Person//即person1.constructor!==Person,因此要重新指定建立联系//不过这种方式会使constructor属性的特性[[Enumerable]]为true,变为可枚举name:"AAA",sayName:function(){console.log(this.name);}};//但是上述constructor变成可枚举了Object.defineProperty(Person.prototype,"constructor",{enumerable:false,value:Person});4.原型的动态性
原型对象的问题
例如原型中有个属性是数组,在实例中push,则添加到了原型中的数组里。即变成共享。
6.2.4组合使用构造函数模式和原型模式
构造函数用于实例属性,原型模式用于方法和共享方法。
每个实例都有自己的一份实例属性,又同时共享对方法的应用。是使用最广泛、认同度最高的创建自定义类型的方法。
6.3.1原型链
最顶层的原型为Object.prototype
//都为trueinstanceinstanceofObjectinstanceinstanceofSuperTypeinstanceinstanceofSubTypeObject.prototype.isPrototypeOf(instance)SuperType.prototype.isPrototypeOf(instance)SubType.prototype.isPrototypeOf(instance)3.谨慎定义方法给原型添加方法的代码一定要放在替换原型的语句之后
通过原型链实现继承时,不能使用对象字面量创建原型方法。因为这样做会重写原型链
6.3.2借用构造函数(伪造对象或经典继承)
functionSuperType(){this.color=["red","green","blue"];}functionSubType(){SuperType.call(this);//借调了超类型的构造函数}传递参数functionSuperType(name){this.name=name;}functionSubType(){SuperType.call(this,"lpr");}