首页 > JavaScript > JavaScript Creating Objects — The Prototype Pattern
2010四月23

JavaScript Creating Objects — The Prototype Pattern

关于原型模式中最重要的概念,prototype,请大家参照我之前的日志JavaScript prototype原型对象,话说那篇日志都发表半年了,沙发还健在,实在是强悍。

用原型模式解决问题

在prototype里定义的方法,会被其所有实例化后的对象共享,省了我们的内存这就足够了。这也就解决了工厂模式和构造函数模式中存在的问题。

function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
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

很神奇不是吗?想要明白这是为什么,那么咱们就一起来看一下ECMAScript中prototypes的特性。

How Prototypes Work

The important thing to understand is that a link exists between the instance and the
constructor ’ s prototype but not between the instance and the constructor.

参考前面Person类,Person constructor属性和Person.prototype关系如下图:

js_property_constructor_and_prototype

js_property_constructor_and_prototype

从图中,可以看出,Person.prototype指向的是原型对象,而Person.prototype.constructor则是指向到Person。

在我们实例化的对象,内部含有一个指向到其构造函数的原型对象,在非IE浏览器中,我们可以使用其__proto__属性来得到它(The __proto__ pointer is assigned when the constructor is called),而在IE里,该属性则被完全的隐藏,但是我们可以使用isPrototypeOf()方法来判断Person的实例化对象的原型链中是否含有Person的原型对象:

//非IE浏览器
alert(person1.__proto__ == Person.prototype);   //true
alert(person2.__proto__ == Person.prototype);   //true
//所有浏览器
alert(Person.prototype.isPrototypeOf(person1));  //true
alert(Person.prototype.isPrototypeOf(person2));  //true

The constructor property mentioned earlier exists only on the prototype and so is accessible from
object instances.

说白了,在一个类的实例化对象中查找属性和方法,就是一个履竿爬的过程

一旦我们的实例化对象用自己的属性覆盖了其构造函数的原型对象的属性,这时,我们又想访问其构造函数的原型对象的属性时咋办呢?(好长一句绕口令),使用delete运算符

person1.name = "simaopig";
alert(person1.sayName()); // simaopig
alert(person2.sayName()); // Nicholas
delete (person1.name);
alert(person1.sayName()); // Nicholas
alert(person2.sayName()); // Nicholas

如果我们要确定,属性值到底是属于实例化后的对象的,还是属于其构造函数的原型对象所有时,我们可以使用hasOwnProperty方法来检测,这里就不再给出实例了。

在IE中,我们不能使用for…in…循环来枚举自定义的不可枚举属性,这些属性包括:

hasOwnProperty() , propertyIsEnumerable() , toLocaleString() , toString() , and valueOf()

Alternate Prototype Syntax

我们可以使用对象直接量方式来定义原型对象,但是这时我们需要特殊注意constructor属性,上例中,我们执行如下代码均返回true

alert(person1 instanceof Person); //true
alert(person1.constructor == Person); //true

但是,如果我们将Person.prototype简写为对象直接量时:

function Person(){
}

Person.prototype = {
    name: "Nicholas",
    age: 29,
    job: "Software Engineer",
    sayName: function(){
        alert(this.name);
    }
}

var person1 = new Person();
alert(person1 instanceof Person);//true
alert(person1.constructor == Person); //false
alert(person1.constructor == Object) //true

这时constructor属性需要我们在定义的Person.prototype对象直接量时修正

Person.prototype={
   constructor:Person,
}

Problems with Prototypes

The prototype pattern isn ’ t without its faults.

幸好我不是完美主义者,否则我真的会怀疑这本书在玩我 -_-!!!,让我们来看一下原型模式创建js对象不完美的一面吧

  1. 和构造函数不同,原型模式无法传参,这使我们new 的实例都具有完全相同的属性值
  2. 如果说上面的一条对于我们来说有点头疼的话,那么真正让人吐血的就是原型模式创建的对象,对于引用类型的属性的共享问题
function Person(){
}

Person.prototype = {
    name: "Nicholas",
    age: 29,
    job: "Software Engineer",
    friends: ["Shelby", "Court"],
    sayName: function(){
        alert(this.name);
    }
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends);
alert(person2.friends);
alert(person1.friends === person2.friends); //true

在此例中,引用型属性(friends数组)被Person的所有实例共享,此刻,我感觉我快哭了。呵呵。

事情总是会有解决方法的,虽然构造函数模式和原型模式都不完美,但是我想我们可以试着把他们揉在一块?期待吧。

文章作者:simaopig
本文地址:http://www.xiaoxiaozi.com/2010/04/23/1751/
版权所有 © 转载时必须以链接形式注明作者和原始出处!

5 Responses to “JavaScript Creating Objects — The Prototype Pattern”

  1. #1 LAONB 回复 | 引用 Post:2010-04-24 09:58

    下面那张图我看我们JAVA工程师画过,呵呵。

    [回复]

  2. #2 Jutoy 回复 | 引用 Post:2010-04-25 13:03

    路过打酱油 :shock:

    [回复]

  3. #3 simaopig 回复 | 引用 Post:2010-04-25 18:40

    @Jutoy
    咦, 小伙子换头像了啊。咋只给个脑壳呢?

    [回复]

  4. #4 一回 回复 | 引用 Post:2011-01-10 12:54

    那张图用什么可以画出?用UML软件好像画不出来,Photoshop又太费劲

    [回复]

  5. #5 simaopig 回复 | 引用 Post:2011-01-13 11:50

    @一回
    呃。这个图我是直接在电子版上截下来的。。

    [回复]

发表评论

:wink: :twisted: :roll: :oops: :mrgreen: :lol: :idea: :evil: :cry: :arrow: :?: :-| :-x :-o :-P :-D :-? :) :( :!: 8-O 8)