JavaScript之四:自定义类型

时间:2022-01-24 14:11:50

四,自定义类

1> 简单模式

var person = new Object ();
person.name = "Nicholas";
person.age = 29;
person.job = "Software Engineer";
person.sayName = function(){
alert(this.name);
};
person.sayName();

缺陷:

i>声明相同对象,需要大量重复代码

ii>无法记录类别信息。检测出还是Object类型。


2> 工厂模式

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 person = createPerson("Nicholas", 29, "Software Engineer");
person.sayName();

优势:封装了重复代码。

缺陷:仍然无法记录类别信息。检测出还是Object类型。


3> 构造函数模式

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName();
优势:可通过instanceof方法,获得类型信息,是Person类型。

Why:因为当使用new关键字调用函数时,JavaScript会做一些额外的事。后面再讲。

缺陷:类的方法,其实也是对象,在调用构造函数时,会被重复实例化,类的实例无法共用方法,造成浪费。


4> 原型模式

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
优势:可获得类型信息。用此方法生成的对象,可共享属性和方法。

Why:

当定义函数时,JavaScritp会做一些额外的事,就是为函数添加一个名为prototype的属性,它是一个指针,指向一个新的对象,我们将其叫做原型对象。

当在Person中添加属性和方法时,实际上都添加到了这个新的原型对象中。并且这个新对象会拥有一个constructor的属性,反指向该构造函数。

当使用new调用函数时,实际上,JavaScript会在返回的新对象中,添加一个名为_proto_的属性,指向了该函数的原型对象。

当调用一个对象的属性和方法时,会先查看对象本身是否有该属性和方法,如果有,则调用。如果没有,则会找到该对象的_proto_属性所指的原型对象,查看原型对象是否有要调用属性和方法。依次类推。

(当调用instanceof方法时,会试图从自身查找constructor属性,但没有,就会上溯查找_proto_属性所指的原型对象,如果有constructor属性,则返回,这也是为什么上述构造函数模式可以记录类别信息的原因)

因此,用原型模式定义类,实例化出的对象,会共享属性和方法。

缺陷:虽然可共享,但当有属性是引用型对象时,会造成实例之间同时操作一个引用对象,造成混淆。


5> 构造函数和原型的组合模式

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
alert(this.name);
}
}
优势:由于我们只是想在对象间共享方法,因此,在构造函数的基础上,将方法的定义改用原型模式定义即可。

覆盖:

当调用对象的方法或属性时,实际上就是先搜索自身,如果搜索不到,才会通过_proto_属性到原型对象中搜索。因此,一旦对象也定义了同名的方法或属性,则会覆盖到原型对象中的方法和属性。对象可通过delete操作符,将对象自己的方法和属性删除,取消覆盖。

判断:

有时需要判断一个属性和方法是否是自身的,还是原型对象的。可调用对象的hasOwnProperty(),如果这个属性是对象自身的,则返回true。

而使用in操作符,只要有这个属性,无论从自身来,还是从原型对象来,都回返回true。

因此可结合使用,来判断属性和方法是否来自原型对象 (name in object) && ! object.hasOwnProperty(name)。


6> 动态原型模式

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
if (typeof this.sayName != "function"){
Person.prototype.sayName = function(){
alert(this.name);
};
}
}
优势:封装性

7> 寄生构造函数模式

function Person(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
优势:适合对已有类进行功能扩展。

缺陷:无法检测类型。


8>稳妥构造函数模式

function Person(name, age, job){
var o = new Object();
o.sayName = function(){
alert(name);
}
return o;
}
优势:可创建稳妥对象,所谓稳妥对象,就是没有公共属性,并且其方法也不引用this的对象。适合安全环境(这些环境禁用this和new)。

缺陷:无法检测类型。