-
function Employee ( name, salary )
-
{
-
this. name= name;
-
this. salary=salary;
-
-
this. addSalary=addSalaryFunction;
-
this. getSalary= function ()
-
{
-
return this. salary;
-
};
-
}
-
function addSalaryFunction (addition )
-
{
-
this. salary= this. salary+addition;
-
}
-
-
var boss1= new Employee ( "John", 200000 );
-
var boss2= new Employee ( "Joan", 200000 );
-
-
-
// 给getSalary函数对象添加属性
-
boss1. getSalary. owner= "boss1";
-
boss2. getSalary. owner= "boss2";
-
alert (boss1. getSalary. owner ); // 输出 "boss1"
-
alert (boss2. getSalary. owner ); // 输出 "boss2"
-
// 如果两个对象指向同一个函数对象,那么
-
// 上面两个输出都应该是“boss2”。
-
-
// 给addSalary函数对象添加属性
-
boss1. addSalary. owner= "boss1";
-
boss1. addSalary. owner= "boss2";
-
alert (boss1. addSalary. owner ); // 输出 "boss2"
-
alert (boss2. addSalary. owner ); // 输出 "boss2"
-
// 因为两个对象都指向同一个函数,(子乌注:原文写are not pointing to the same function,疑为笔误)
-
// 当修改其中一个的时候,会影响所有的实例(所以两个都输出“boss2”).
-
-
运行示例
也许不是重要的事情,但这里有一些关于运行类似上面的getSalary的内嵌函数的结论: 1) 需要更多的存储空间来存储对象(因为每一个对象实例都会有它自己的getSalary代码拷贝);2) javascript需要更多时间来构造这个对象。
让我们重新写这个示例来让它更有效率些。
Example DT9
-
function Employee ( name, salary )
-
{
-
this. name= name;
-
this. salary=salary;
-
-
this. addSalary=addSalaryFunction;
-
this. getSalary=getSalaryFunction;
-
}
-
function getSalaryFunction ()
-
{
-
return this. salary;
-
}
-
-
function addSalaryFunction (addition )
-
{
-
this. salary= this. salary+addition;
-
}
-
看这儿,两个函数都指向同一个地方,这将会节约空间和缩短构造时间(特别是当你有一大堆内嵌函数在一个构造函数的时候)。这里有另外一个函数的功能能够来提升这个设计,它叫做prototype,而我们将在下一节讨论它。
函数:原型
每一个构造函数都有一个属性叫做原型(prototype,下面都不再翻译,使用其原文)。这个属性非常有用:为一个特定类声明通用的变量或者函数。
prototype的定义
你不需要显式地声明一个prototype属性,因为在每一个构造函数中都有它的存在。你可以看看下面的例子:
Example PT1
-
function Test ()
-
{
-
}
-
alert (Test. prototype ); // 输出 "Object"
-
运行示例
给prototype添加属性
就如你在上面所看到的,prototype是一个对象,因此,你能够给它添加属性。你添加给prototype的属性将会成为使用这个构造函数创建的对象的通用属性。
例如,我下面有一个数据类型Fish,我想让所有的鱼都有这些属性:livesIn="water"
和price=20
;为了实现这个,我可以给构造函数Fish的prototype添加那些属性。
Example PT2
-
function Fish ( name, color )
-
{
-
this. name= name;
-
this. color=color;
-
}
-
Fish. prototype. livesIn= "water";
-
Fish. prototype. price= 20;
-
接下来让我们作几条鱼:
-
var fish1= new Fish ( "mackarel", "gray" );
-
var fish2= new Fish ( "goldfish", "orange" );
-
var fish3= new Fish ( "salmon", "white" );
-
再来看看鱼都有哪些属性:
-
for ( var i= 1; i<= 3; i++ )
-
{
-
var fish= eval ( "fish"+i ); // 我只是取得指向这条鱼的指针
-
alert (fish. name+ ","+fish. color+ ","+fish. livesIn+ ","+fish. price );
-
}
-
运行示例
输出应该是:
-
"mackarel, gray, water, 20"
-
"goldfish, orange, water, 20"
-
"salmon, white water, 20"
-
你看到所有的鱼都有属性livesIn和price,我们甚至都没有为每一条不同的鱼特别声明这些属性。这时因为当一个对象被创建时,这个构造函数将会把它的属性prototype赋给新对象的内部属性__proto__。这个__proto__被这个对象用来查找它的属性。
用prototype给对象添加函数
你也可以通过prototype来给所有对象添加共用的函数。这有一个好处:你不需要每次在构造一个对象的时候创建并初始化这个函数。为了解释这一点,让我们重新来看Example DT9并使用prototype来重写它:
Example PT3
-
function Employee ( name, salary )
-
{
-
this. name= name;
-
this. salary=salary;
-
}
-
Employee. prototype. getSalary= function getSalaryFunction ()
-
{
-
return this. salary;
-
}
-
-
Employee. prototype. addSalary= function addSalaryFunction (addition )
-
{
-
this. salary= this. salary+addition;
-
}
-
我们可以象通常那样创建对象:
-
var boss1= new Employee ( "Joan", 200000 );
-
var boss2= new Employee ( "Kim", 100000 );
-
var boss3= new Employee ( "Sam", 150000 );
-
并验证它:
-
alert (boss1. getSalary ()); // 输出 200000
-
alert (boss2. getSalary ()); // 输出 100000
-
alert (boss3. getSalary ()); // 输出 150000
-
运行示例
这里有一个图示来说明prototype是如何工作的。这个对象的每一个实例(boss1, boss2, boss3)都有一个内部属性叫做__proto__,这个属性指向了它的构造器(Employee)的属性prototype。当你执行getSalary或者addSalary的时候,这个对象会在它的__proto__找到并执行这个代码。注意这点:这里并没有代码的复制(和Example DT8的图表作一下对比)。