一:理解对象属性
对象有两种属性:数据属性和访问器属性。
1)数据属性
数据属性有四个描述其行为的特性,[[configurable]] [[enumerable]] [[writable]] [[value]],修改属性的特性使用Object.defineProperty
2)访问器属性
访问器属性包含一对getter和setter函数,有四个特性[[configurable]] [[enumerable]] [[get]] [[set]],修改属性使用Object.defineProperty
获取对象描述符:Object.getOwnPropertyDescriptor()
二:理解并创建对象
创建对象的方式,及各自的优缺点:
1)工厂方式
function person(name,age){var o = new Object();o.name=name,o.age=age,return o}
person1 = person('dd',12);
person2=person('ss',13);
缺点:当创建多个相似对象时,会创建多个object实例
2)自定义构造函数
function Person(name,age){this.name=name; this.age=age ; this.sayName:function(){ return name; }}
person1 = new Person('dd',12);
person2= new Person('ss',13);
优点:创建自定义的构造函数意味着可以将它的实例标注为特定的类型,而不是统一的Object类型。自定义的构造函数是属于全局window对象的,可以使用函数对象的apple和call方法,扩展作用域。
缺点:每创建一个实例,就重新创建对象的每个方法。
3)原型模式
每个函数都有一个prototype属性,prototype是一个指针,指向一个对象,这个对象包含着特定类型对象共享的所有属性和方法。
function Person(){}
Person.prototype.name = "dd";
Person.prototype.sayName = function(name){ return name}
var person1 = new Person();
var person2 = new Person();
更简洁的写法:
ps:这种写法实际上重新定义了prototype,因此原型对象的constructor属性指向了object,而不是person,
function Person(){}
Person.prototype = {
constructor:Person//指向Person
name:"dd",
sayName = function(name){ return name}
}
var person1 = new Person();
var person2 = new Person();
原型模式的工作原理:
每创建一个新函数,该函数的prototype属性指向原型对象,原型对象有个属性constructor(构造函数)指向包含prototype属性的函数。
Person.prototype.constructor = Person
当使用构造函数创建实例后,实例的内部将包含一个指针(prototype属性)指向构造函数的原型对象
确定实例与原型对象的关系:原型对象 isPrototypeOf(实例对象)
获取一个对象的原型:Object.getPrototypeOf(实例)
对象.hasOwnProperty(),来判断属性是实例的,还是原型对象的。
缺点:1) 所有实例默认的共享的属性值都是相同的。
2)原型中所有的属性和方法都是被很多实例共享的,如果属性值是引用类型,修改一个实例的属性,就会修改原型对象中的属性值,导致其他实例的该属性值都会被修改。
4)组合使用构造函数和原型模式
三:理解继承
继承有接口继承和实现继承两种,接口继承由函数签名来实现,实现继承是继承具体的实现方法。实现继承主要依靠原型链来实现。基本思想是让一个引用类型继承另一个引用类型的属性和方法,将原型对象作为另一个类型的实例。
每个构造函数都有一个属性指向原型对象,原型对象也有个内部指针指向构造函数,每个实例也有属性指向原型对象,如果原型对象是另一个对象的实例,则原型对象就可以指向另一个原型对象,就获取到另一个原型对象的属性和方法,从而实现了继承。