1,构造函数模式
介绍
创建自定义的构造函数。
代码示例
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person1 = new Person("Nicholas",29,"soft"); var person2 = new Person("Greg",27,"Doctor");
特点
- 没有显示创建对象。
- 直接赋值给this对象。
- 没有return。
- 函数名第一个字符大写。
- 这种方式定义的构造函数是定义在Globa对象(浏览器中是window对象)。
与普通函数的异同
唯一不同,调用方式不同。通过new操作符来调用,那它就可以作为构造函数,若无new就是普通函数,注意:作为普通函数调用函数中this指代 函数外层的作用域的变量对象,若在全局函数中定义函数,则this指代global对象。
缺点
- 不同实例具有不同的作用域链和标识符解析,不同实例上的同名函数是不相等的。
2,原型模式
介绍
每个函数都有一个prototype(原型)属性,这个属性所指对象包含着本类型的所有实例共享的属性和方法。
如下代码示例:function Person(){ } Person.prototype.name = "Nicholas"。 Person.prototype.age = 29; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); // "Nicholas" var person2 = new Person(); person2.sayName(); // "Nicholas" alert(person1.sayName == person2.sayName); // true
- 原型对象prototype,构造函数,实例对象之间的联系
创建自定义的构造函数后,其原型对象默认指挥取得constructor属性。其他方法都是从Object继承而来。
- 原型对象prototype与构造函数
prototype所指原型对象 都会获取一个constructor(构造函数)属性,constructor指向原型属性所在函数的指针。对照前面代码,即指向Person函数。 - 原型对象与实例对象
当调用构造函数创建实例对象后,该对象内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262 5管这个指针叫[[Prototype]],这个连接存在于实例和构造函数的原型对象之间,而不是存在实例与构造函数之间。
- 原型对象prototype与构造函数
有关Prototype的方法
isPrototypeOf()
alert(Person.prototype.isPrototypeOf(person1)); // true alert(Person.prototype.isPrototypeOf(person1)); // true
Object.getProtypeOf(),返回[[Prototype]]的值。
alert(Object.getProtypeOf[person1] == Person.prototype); // true alert(Object.getProtypeOf[person2].name); // "Nicholas"
- 实例的属性和方法的匹配搜索
首先搜索从实例对象本身开始,如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找。 原型对象和实例对象之间的属性关系
- 对象可以访问保存在原型中属性,但却不能重写原型中的值,如果我们给对象添加一个属性,该属性与原型中某个属性同名,该属性会屏蔽原型中那个属性。
- 使用delete操作符删除实例同名属性,从而可以让我们能够重新访问原型中的属性。
- 使用hasWwnProperty()方法可以检测一个 属性是存在实例中,还是原型
- 使用in操作符能够访问对象的属性时返回TRUE,无论该属性存在于实例中还是原型中。
可以使用下面的代码来辨别属性到底是存在对象还是原型中
function hasPrototypeProperty(object,name){ return !object.hasOwnProperty(name) && (name in object); }
- 取得所有实例属性
- ECMAScript 5中的Object.keys()
取得所有可枚举的属性
- 参数
对象 - 返回值
包含所有可枚举属性的字符串数组。
- 参数
- Object.getOwnPropertyNames()
取得所有实例属性,无论是否可枚举。
- ECMAScript 5中的Object.keys()
- 使用对象字面量重写整个原型对象
相当于完全重写了默认的prototype对象,因此constructor属性变成了新对象的constructor属性,不再指向Person函数,并且constructor的Enumerable特性被设置为true。
- 重写原型对象后影响
切断了现有原型和任何之前已经存在的对象实例之间的联系,实例中的指针还是指向原来最初的原型。
- 重写原型对象后影响
- 原型对象的问题
由于原型对象的共享特征,所以有破坏封装性的不安全因素。
3,组合使用构造函数和原型模式
参看我的下篇《JavaScript学习-组合使用构造函数和原型模式》。
4,寄生构造函数模式
介绍
这个模式除了使用new操作符并把使用的包装函数叫做构造函数之外,这个模式跟工厂模式是一样的。代码示例:funciton 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; } var friend = new Person("Nicholas",29,"Software"); friend.sayName(); // "Nicholas"
使用举例
这个模式可以在特殊的情况下用来为对象创建构造函数,比如创建一个具有额外方法的特殊数组。代码示例:function SpecialArray(){ var values = new Array(); values.push.apply(values,arguments); values.toPipedString = function(){ return this.join("/"); }; return values; } var colors = new SpecialArray("red","blue","green"); alert(colors.toPipedString()); //"red|blue|green"
缺点
- 返回的对象,与构造函数,与构造函数的原型属性之间没有关系。即,返回的对象,与在构造函数外部创建的对象没有什么不同。因此,不能依赖instanceof操作符来确定对象类型。建议不适用这种模式。
5,稳妥构造函数模式
- 介绍
道格拉斯·克罗克福德,发明了JavaScript中的稳妥模式这个概念。 和寄生构造函数,两点不同,如下:
- 没有公共属性,而且方法也不引用this对象。
- 不使用new操作符调用构造函数。
代码示例
function Person(name,age,job){ var o = new Object(); o.sayName = function(){ alert(name); }; return o; }
- 和寄生构造函数,相同点,如下:
- 返回的对象与构造函数之间没有关系。
- instanceof操作符对这种对象也没有意义。