1、创建对象
1)工厂模式
没有解决对象识别问题
function createPerson(name,age,job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson(‘Nicholas‘,29,‘software engineer‘); var person2 = createPerson(‘Greg‘,27,‘Doctor‘);
2)构造函数模式
创建Person 的实例,使用new操作符,经历的步骤:
1)创建一个新对象
2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
3)执行构造函数中的代码(为这个新对象添加属性)
4)返回新对象
问题:每个方法都要在每个实例上重新创建一遍
3)原型模式
我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象
这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法
判断一个对象是否是另一个对象的原型
方法:
Person.prototype.isPrototypeOf(person1); //es5 Object.getPrototypeOf(person1) == Person.prototype
每当读取某个对象某个属性时:
1)搜索从对象实例本身开始
2)搜索指针指向的原型对象
如何判断一个属性是存在于实例中,还是存在于原型对象中》
使用:hasOwnProperty()
原型与in操作符:
两种方式使用in:单独使用和在for-in循环中使用
使用for..in循环时,返回的是所有能够通过对象访问的、可枚举的属性,既包括存在于实例中的属性,也包括存在于原型中的实例
Object.keys()
用于获取对象自身所有的可枚举的属性值,但不包括原型中的属性,然后返回一个由属性名组成的数组。注意它同for..in一样不能保证属性按对象原来的顺序输出。
Object.getOwnPropertyNames()
方法返回对象的所有自身属性的属性名(包括不可枚举的属性)组成的数组,但不会获取原型链上的属性。
原型的动态性:
重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系,它们引用的仍然是最初的原型
原型对象的问题:
原型中的所有属性被很多实例共享,对于包含引用类型的值来说问题突出
4)组合使用构造函数模式和原型模式
构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性
5)动态原型模式
6)寄生构造函数模式
除了使用new操作符并把使用的包装函数叫做构造函数之外,这个模式与工厂模式其实一模一样
7)稳妥构造函数模式
2、继承
1)原型链
构造函数,实例,原型之间的关系:
每个构造函数都有一个原型对象,原型对象都包含指向构造函数的指针,而实例都包含一个指向原型对象的内部指针
让原型对象等于另一个类型的实例
结果:
原型对象包含一个指向另一个原型的指针,另一个原型中包含指向另一个构造函数的指针,如果另一个原型又是另一类型的实例,层层递进,就构成了实例与原型的链条
别忘记默认的原型:所有引用类型默认都继承了Object,默认原型会包含一个内部指针,指向Object.prototype
确定原型和实例的关系:
方法一:instanceof操作符:测试实例与原型链中出现过的构造函数
alert(instance instanceof Object); //true
方法二:isPrototypeOf():原型链中出现过的原型
Person.prototype.isPrototypeOf(person1);
给原型添加方法的代码一定要放在替换原型的语句之后
2)借用构造函数
在子类型构造函数的内部调用超类型构造函数
使用apply和call方法可以在(将来)新创建的对象上执行构造函数
传递参数:借用构造函数一个很大的优势,可以在子类型构造函数中向超类型构造函数传递参数
问题 :函数复用无从谈起
3)组合继承
使用原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承
function SuperType(name){ this.name = name; this.colors = ["red","blue","green"]; } SuperType.prototype.sayName = function(){ alert(this.name); } function Subtype(name,age){ //继承属性,同时传递了参数 SuperType.call(this,name); this.age = age; } //继承方法 Subtype.prototype = new SuperType(); Subtype.prototype.constructor = Subtype; Subtype.prototype.sayAge=function(){ alert(this.age); }; var instance1 = new Subtype(‘nic‘,29); instance1.colors.push(‘black‘); alert(instance1.colors);// "red,blue,green,black" instance1.sayName();//"nic" instance1.sayAge();//29 var instance2 = new Subtype(‘greg‘,27); alert(instance2.colors);//"red,blue,green" instance2.sayName(); instance2.sayAge()
4)原型式继承
可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制,而复制得到的副本还可以进一步改造。
借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义的类型
function object(o){ function F(){} F.prototype = o; return new F(); }
从本质上讲object()对传入其中的对象执行了浅复制
es5使用了Object.create(person)
var person = { name:‘nic‘, friends:[‘sh‘,‘co‘,‘va‘] } var anotherperson = Object.create(person)
5)寄生式继承
与原型式继承类似,基于某个对象或某些信息创建一个对象,然后增强对象,最后返回对象。为了解决组合继承模式多次调用超类型构造函数而导致效率低的问题,可以将这个模式和组合继承一起使用
6)寄生组合式继承
集寄生式继承和组合继承的优点于一身,是实现基于类型继承最有效的方式