【JavaScript高级程序设计】对象的创建与继承
2013-05-08 14:08
519 查看
关于JS面向对象的部分中,关于对象的创建和继承的各种方法,以及这些方法之间的区别和适用场景是经常被问到的。
首先,关于对象的创建。
1.最简单的方法,大括号创建,var o = {};或者是用对象字面量方法,var 0 = {name:"jack",age = 10};
问题:当使用相同接口创建很多对象时,会产生大量重复的代码。
2.工厂模式方法:将创建对象的细节封装起来,这样可以解决创建多个相似对象的问题。
注意:不能用new来调用创建对象的函数,并且在函数的内部要返回那个Object对象。
3.构造函数方法
问题:每个方法都要在每个实例上创建;
创建多个完成相同任务的Function实例是没必要的。
如果把这样的Funtion从构造函数中移除来,则函数会变成为全局环境中的成员,破坏了封装性。
4.原型模式
原型:是指向一个对象的,这个对象包含由所有实例共享的方法和属性。
可以使用hasOwnPropertyp()来判断,当属性存在于对象中时返回true。if (wang.hasOwnProperty("name")) {alert(true);}
比如:
5.组合构造函数和原型模式
将实例属性在构造函数中定义。
所有实例共享的属性和方法在原型中定义。
说完了对象的创建,再说一下对象的继承。
1.原型链继承
每一个构造函数中都有一个指针prototype,这个指针指向原型对象,而原型对象中又都有一个属性constructor,指向这个构造函数。同时每个实例中都有一个指向原型对象的指针。
使用原型链方法继承时,不能用对象字面量来创建原型方法,这样会重写子类原型,使得constructor指向Object。
问题:a.由于包含引用型的原型属性会被所有实例共享。
所以,如果父类的构造函数中有一个引用型数组,则对父类的每一个实例间无影响。
但是子类的原型是父类的一个实例。
子类的所有实例都会共享这个属性。
b.创建子类实例时无法向父类的构造函数传参。
2.借用构造函数
问题:方法都在构造函数中定义,没有了函数的复用。
同时,在父类原型中定义的方法和属性,子类无法继承到。
3.组合继承
通过原型链来实现对原型属性和方法的继承;借用构造函数来实现对实例属性的继承。
问题:无论在什么情况下,都会调用2次父类构造函数。
基于现有的对象,再创建一个新对象。
适用场景:只想让一个对象与另一个对象保持相似的情况下。
object()对传入的对象进行了浅复制。
person1 = object(Person);
person2 = object(Person);
相当于创建了2个person的副本。
5.寄生式继承
与创建对象的工厂模式类似
6.寄生组合式
这是最有效的一种继承方式。只调用了一次superType()构造函数,同时还没有改变原型链。
首先创建如下函数:
最后,理解对象的创建和继承,关键是理解构造函数,原型对象以及实例之间的关系。这个稍后上图。
首先,关于对象的创建。
1.最简单的方法,大括号创建,var o = {};或者是用对象字面量方法,var 0 = {name:"jack",age = 10};
问题:当使用相同接口创建很多对象时,会产生大量重复的代码。
2.工厂模式方法:将创建对象的细节封装起来,这样可以解决创建多个相似对象的问题。
function createA(){ var o = new Object(); o.name = "jack"; o.age = 10; return o; } var A = createA();问题:带来了对象识别问题,不能知道一个对象的类型。也就是说用instansOf()方法无法确定对象的类型。
注意:不能用new来调用创建对象的函数,并且在函数的内部要返回那个Object对象。
3.构造函数方法
function Person(name,age){ this.name = name; this.age = age; this.sayName = function (){ alert(this.name); } } var person = new Person("jack",10);通过检查实例的constructor属性,或者使用instanceof()方法可以确定对象的类型。
问题:每个方法都要在每个实例上创建;
创建多个完成相同任务的Function实例是没必要的。
如果把这样的Funtion从构造函数中移除来,则函数会变成为全局环境中的成员,破坏了封装性。
4.原型模式
原型:是指向一个对象的,这个对象包含由所有实例共享的方法和属性。
function Person(){ } Person.prototype.name = "jack"; Person.prototype.age = 10; Person.prototype.sayName = function (){ alert(this.name); } var wang = new Person();注意:所有的实例保存的仅是指向对象原型的指针。所有实例共享原型的属性和方法。实例可以重写属性,覆盖原型对象中的相同属性,但是并不改变原型中的这个属性。
可以使用hasOwnPropertyp()来判断,当属性存在于对象中时返回true。if (wang.hasOwnProperty("name")) {alert(true);}
比如:
var wang = new Person(); console.log(wang.age); //10 wang.age = 20; console.log(wang.age); //20 var li = new Person(); console.log(li.age); //10问题:省略了为构造函数传参,所有实例在默认情况下都取得相同的属性值。尤其当属性为引用值时,会相互干扰。
5.组合构造函数和原型模式
将实例属性在构造函数中定义。
所有实例共享的属性和方法在原型中定义。
function Person(name,age){ this.name = name; this.age = age; } Person.prototype = { constructor: Person, sayName: function(){ alert(this.name); } }; var wang = new Person("jack",10); wang.sayName(); var li = new Person("nike", 10); li.sayName();
说完了对象的创建,再说一下对象的继承。
1.原型链继承
每一个构造函数中都有一个指针prototype,这个指针指向原型对象,而原型对象中又都有一个属性constructor,指向这个构造函数。同时每个实例中都有一个指向原型对象的指针。
function SuperType(){ } SuperType.prototype.getSuperValue = function(){ }; function subType(){ } subType.prototype = new SuperType();//重写了subType的原型,此时constructor指向superType的原型对象 subType.prototype.getSubValue = function(){ };注意:新加的子类原型方法,应该在继承了父亲原型之后。
使用原型链方法继承时,不能用对象字面量来创建原型方法,这样会重写子类原型,使得constructor指向Object。
问题:a.由于包含引用型的原型属性会被所有实例共享。
所以,如果父类的构造函数中有一个引用型数组,则对父类的每一个实例间无影响。
但是子类的原型是父类的一个实例。
子类的所有实例都会共享这个属性。
b.创建子类实例时无法向父类的构造函数传参。
2.借用构造函数
function superType(name){ this.name = name; this.colors = ["black","green"]; } function subType(){ superType.call(this,"jack"); this.age = 10; }在调用subType()时,会借调superType()的所有代码,子类的实例创建实例自己的colors副本。
问题:方法都在构造函数中定义,没有了函数的复用。
同时,在父类原型中定义的方法和属性,子类无法继承到。
3.组合继承
通过原型链来实现对原型属性和方法的继承;借用构造函数来实现对实例属性的继承。
问题:无论在什么情况下,都会调用2次父类构造函数。
function superType(name){ this.name = name; } superType.prototype.getSuperValue = function(){ }; function subType(name,age){ superType.call(this,name); this.age = age; } subType.prototype = new superType(); subType.prototype.constructor = subType; subType.prototype.sayAge = function(){ }4.原型式继承
基于现有的对象,再创建一个新对象。
适用场景:只想让一个对象与另一个对象保持相似的情况下。
function object(o){ function F(){} //创建临时性的构造函数 F.prototype = o;//将传入的对象作为这个构造函数的原型 return new F();//返回这个临时类型的新实例 }
object()对传入的对象进行了浅复制。
person1 = object(Person);
person2 = object(Person);
相当于创建了2个person的副本。
5.寄生式继承
与创建对象的工厂模式类似
function another(o){ var clone = object(o); clone.sayHi = function(){ }; return clone; }问题:无法做到函数的复用。
6.寄生组合式
这是最有效的一种继承方式。只调用了一次superType()构造函数,同时还没有改变原型链。
首先创建如下函数:
function ip(subType,superType){ var prototype = object(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; }然后使用时,与组合继承类似,但是不同的是将subType.prototype = new superType();subType.prototype.constructor = subType;这两句代码换成,ip(subType,superType);
最后,理解对象的创建和继承,关键是理解构造函数,原型对象以及实例之间的关系。这个稍后上图。
相关文章推荐
- javascript高级程序设计一书----关于创建和对象继承的总结
- JavaScript高级程序设计之面向对象的程序设计之创建对象之原型模式 第6.2.3讲笔记
- JavaScript高级程序设计之面向对象的程序设计之创建对象之稳妥构造函数模式 第6.2.7讲笔记
- javascript创建对象总结(javascript高级程序设计)
- JavaScript高级程序设计【面向对象-创建对象2】
- javascript高级程序设计第六章:面向对象的程序设计——创建对象读书笔记
- Javascript高级程序设计——面向对象之创建对象
- Javascript高级程序设计笔记(很重要尤其是对象的设计模式与继承)
- Javascript高级程序设计 笔记(四) javascript对象创建
- 《JavaScript高级程序设计 第三版》学习笔记 (四) 对象创建详解
- javascript高级程序设计第六章:面向对象的程序设计——继承读书笔记
- 读javascript高级程序设计05-面向对象之创建对象
- JavaScript高级程序设计 (6章 创建对象)---读书笔记
- JavaScript高级程序设计之面向对象的程序设计之创建对象之工厂模式第6.2.1讲笔记
- <JavaScript高级程序设计>笔记二: 创建对象
- 【JavaScript高级程序设计】读书笔记之二 —— 理解对象的原型、继承
- JavaScript高级程序设计之面向对象的程序设计之创建对象之 构造函数模式第6.2.2讲笔记
- JavaScript高级程序设计之面向对象的程序设计之创建对象之组合使用构造函数模式和原型模式 第6.2.4讲笔记
- JavaScript高级程序设计学习笔记--面向对象的程序设计(二)-- 继承
- JavaScript高级程序设计【面向对象-创建对象】