javascript 学习笔记

来源:互联网 发布:python多进程编程 编辑:程序博客网 时间:2024/06/08 08:20


----------------------------------------------------------------------------------------------------------------------------------

2.1.1数值数据

数值数据具有两种形式:

整数:范围-2^53~2^53.

分数:也称浮点数


2.1.2文本数据

字符串是一段用引号“”括起来的文本,比如“hello world”。也可以用单引号括起来。


---------------------------------------------

2.2变量

变量名是大小写敏感的。


2.2.1声明变量并赋值

在使用一个变量之前,应该用关键字var对变量进行声明:var myFirstVariable;

JavaScript中的变量可以保存任何类型的数据。 

数组:

var myArray=new Array(6);

var myArray=new Array("x","x","x");


所有比较运算符的优先级都比算术运算符要低。


------------------------------------------------

3.3 函数。

function convert()

{

}

3.3.2变量的作用域和生存期。

对某个文件而言,任何在函数之外声明的变量。其作用域就是该页面上的所以脚本代码。 

函数内定义的变量,仅在函数内被使用,局部变量

------------------------------------------------------

4.基于对象的语言

Array 对象

Array 对象用于在单个的变量中存储多个值。

创建 Array 对象的语法:

new Array();new Array(size);new Array(element0, element1, ..., elementn);              

Array 对象方法

FF: Firefox, IE: Internet Explorer

方法描述FFIEconcat()连接两个或更多的数组,并返回结果。14join()把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。14pop()删除并返回数组的最后一个元素15.5push()向数组的末尾添加一个或更多元素,并返回新的长度。15.5reverse()颠倒数组中元素的顺序。14shift()删除并返回数组的第一个元素15.5slice()从某个已有的数组返回选定的元素14sort()对数组的元素进行排序14splice()删除元素,并向数组添加新元素。15.5toSource()返回该对象的源代码。1-toString()把数组转换为字符串,并返回结果。14toLocaleString()把数组转换为本地数组,并返回结果。14unshift()向数组的开头添加一个或更多元素,并返回新的长度。16valueOf()返回数组对象的原始值14

------------------------------------------------------------------------- 

Boolean 对象

Boolean 对象表示两个值:"true" 或 "false"。

创建 Boolean 对象的语法:

new Boolean(value); //构造函数Boolean(value);                //转换函数  

参数

参数  value 由布尔对象存放的值或者要转换成布尔值的值。

返回值

当作为一个构造函数(带有运算符 new)调用时,Boolean() 将把它的参数转换成一个布尔值,并且返回一个包含该值的 Boolean 对象。

如果作为一个函数(不带有运算符 new)调用时,Boolean() 只将把它的参数转换成一个原始的布尔值,并且返回这个值。

注释:如果省略 value 参数,或者设置为 0、-0、null、""、false、undefined 或 NaN,则该对象设置为 false。否则设置为 true(即使 value 参数是字符串 "false")。

Boolean 对象属性

FF: Firefox, IE: Internet Explorer

属性描述FFIEconstructor返回对创建此对象的 Boolean 函数的引用14prototype使您有能力向对象添加属性和方法。14

Boolean 对象方法

FF: Firefox, IE: Internet Explorer

方法描述FFIEtoSource()返回该对象的源代码。1-toString()把逻辑值转换为字符串,并返回结果。14valueOf()返回 Boolean 对象的原始值。14

Boolean 对象描述

在 JavaScript 中,布尔值是一种基本的数据类型。Boolean 对象是一个将布尔值打包的布尔对象。Boolean 对象主要用于提供将布尔值转换成字符串的 toString() 方法。

当调用 toString() 方法将布尔值转换成字符串时(通常是由 JavaScript 隐式地调用),JavaScript 会内在地将这个布尔值转换成一个临时的 Boolean 对象,然后调用这个对象的     toString() 方法。


变量并不保存对象本身的数据,它仅保存一个指向对象的引用。



---------------------------------------
http://devbean.blog.51cto.com/448512/d-5 
JavaScript面向对象程序设计(2): 数组
1. 创建数组
在JavaScript中有很多创建数组的方法。比如使用Array函数。不过这不是现在我们要讲述的。现在我们使用简单的方括号“[]”的办法来创建数组。
var objAyyar = [];  // 1  
var objAyyar = [2];  // 2  
var objAyyar = [ "a",  "b",  "c"];  // 3  
var objAyyar = [ new Date(), 123,  "abc"];  // 4
这里有四个创建数组的语句。下面来一一解释一下:
第一句,创建一个空的数组;
第二句,创建一个数组,数组元素只有一个2;
第三句,创建一个数组,数组的元素分别初始化为"a", "b", "c";
第四句,创建一个数组,其中第一个元素为一个Date类型的对象,第二个元素是数字123,第三个元素是字符串"abc"。
但是,像上面的第四句,JavaScript的数组怎么能存放不同类型的元素呢?这是因为,JavaScript是弱类型的语言,没有很大的数据类型的差别,所以数组的元素可以放入不同的类型。
那么,这个arr["js"]怎么也能成立呢?这就不是上面的问题了。也就是说,JavaScript实际是允许将字符串作为数字下标的。这在JavaScript中是完全合法的。

-------------------------------------------
对象
var  Person = {  
        name:  "Tom"  
        age: 20,  
        introduction:  function () {  
                alert( "My name is "  +  this .name +  ", my age is "  +  this .age);             
        }  
 
Person.introduction();
在JavaScript中,对象就是“键-值”对的形式,具体来说是"string-as-key": object-as-value的形式。也就是说,这个键必须是string类型的,而值可以是任何类型的。那么,方法呢?其实,JavaScript中的function也是一个类型,这个在后面会有描述的,这里仅仅先知道就可以了。这种数学上成为二元组的样式很常见,数组就是这样的,只不过数组的键必须是int。同样,JavaScript的对象也是一个特殊的二元组,只不过键是string类型的。这是不是就像是一种散列?或者说是哈希表?就是这个样子!
属性的使用
JavaScript中属性的使用或许比较特别。看下面试图使用Person的name属性的四个语句,看上去都差不多,实际上也确实如此:
alert(Person.name);  
// alert(Person."name");  
alert(Person[ "name"]);  
alert(Person[name]);
除去注释掉的一句,其他的三个语句都能够通过解释(由于JavaScript是解释型语言,不是编译型的,因此这里不说是编译),但是只有1、3句能够取出name属性!第一句和Java没有什么区别,后面的两个显得比较特别,第三句看上去像什么?对了!数组元素的访问!这进一步验证了JavaScript中的数组和对象“本是同根生”。那么,第四句呢?当然是返回undefined!因为数组下标必须是数字或者字符串嘛!


更多属性的操作
现在对JavaScript对象属性的认识应该在这样一点上:JavaScript的对象就是一个二元组,或者说就是一个散列或哈希表。如果能明白这一点,就不会对下面的操作有所奇怪了:
var Person = {};  // 创建一个空对象  
Person.name =  "Tom";  // 添加一个属性name,并赋值为Tom  
Person[ "age"] = 20;  // 用另外的办法新增属性  
Person.introduction =  function () {  
        alert( "My name is " +  this.name +  ", my age is " +  this.age);  
};  
Person.introduction();  
forvar field  in Person) {  // 使用foreach循环列出对象中所有属性  
        alert( "field name: " + field +  "; value: " + Person[field]);  
}  
delete Person.name;  // 删除name属性  
Person.introduction();  
alert(name  in Person);  // 使用in操作符判断属性是否存在

对象的constructor属性
在JavaScript中,每个对象都有一个constructor属性。这个constructor属性用来记录对象初始化时的构造函数名字。例如:
var date =  new Date();  
alert(date.constructor);  
alert(date.constructor ==  "Date");  // false  
alert(date.constructor == Date);  // true
这里有两个问题:第一,我们并没有给Person constructor属性,它怎么会有的?第二,这个constructor属性怎么是object,而不是我们的Person呢?
对于第一个问题,很明显,是JavaScript给我们加上的。事实上,每个JavaScript对象都会有这样一个属性。那么,它的值又怎么是Object呢?这个问题,在我们说道new这个运算符的时候会给大家说明的。这里请大家注意,本文中的对象其实是指的单独的使用new之后得到的对象。也就是说,那个constructor属性是在new运算符的时候获得的
--------------------------------------------------------------


在很多语言中,函数(Java里面成为方法)和对象时截然不同的两种东西。函数被定义为对象的动作,或者是全局的(像在C++中的main函数一样)。但是在JavaScript中,函数和对象的界限却显得不那么明显。
1. 函数的定义
JavaScript中有很多种定义函数的方法:
function hello() { alert( "Hello!"); }         
var hello1 =  function() { alert( "Hello!"); };         
var hello2 =  new Function( "", "alert('Hello!');");         
hello();         
hello1();         
hello2();
上面给出了三种JavaScript的函数定义语句。第一句是常见的定义,看上去和Java等语言没有太大的不同。这句是定义了一个具名函数,按照上面的例子,这里的函数定义名字为hello。第二句是将一个匿名函数定义好后赋值给一个变量,于是通过这个变量就可以引用这个匿名函数。这两句看上去效果差不多,但是它们是不一样的:第一句定义的是一个具名函数,第二句定义的是一个匿名函数——尽管你可以通过这个变量引用到这个匿名函数,但实际上它还是匿名的。它们的区别可以由下面的看出:具名函数的作用范围是全局的:你可以在定义之前使用这个函数。但是匿名函数的定义是后向的,像C/C++一样,必须在定义之后才能使用。这就是为什么hello可以使用,但是hello1就会有错误。然后试想一下这是为什么呢?JavaScript的解释过程和HTML一样是从上到下的。所以,这里的匿名函数就相当于是一个变量的定义,因此在JavaScript解释器解释执行时并不知道这个变量的定义,因此发生错误。但是,对于函数的定义则是扫描全局。
第三个语句就很有意思了。它创建了一个Function类的对象。这个构造函数(姑且这么叫吧)具有两个参数,第一个是函数的参数,第二个是函数体。具体来说,下面的两个函数定义是等价的:
function sayHelloTo(name) {  
        alert( "Hello, " + name);  
}  
var sayHelloTo1 =  new Function( "name",  "alert('Hello, ' + name)");
这种使用Function进行定义的方式并不常见,但是这个语句显示的特性却很有趣:它意味着,你可以使用这种构造函数在运行时动态的构造函数!这是一般的语言没有的特性。
2. 函数的参数
JavaScript的函数也是相当的灵活,不仅是它的定义方式多种多样,甚至它的参数都有“奇怪”的行为。由于JavaScript是弱类型的语言,因此,它不能对你的函数参数类型做检测,甚至不能保证你传入的参数个数是否和函数定义一致。这就需要有一些特殊的检测。
看这个例子,仅仅接受两个参数的函数,在调用时可以有任意个参数!但是,它仅取用符合条件的个数,在这里也就是前两个参数。所以,当你传入一个参数时,JavaScript试图将两个数字加起来,结果第二个参数不存在,因此返回值是NaN。第三种情况,实参个数多于形参个数,此时JavaScript只取前两个参数相加。
尽管很不正式,但是可以说,JavaScript的函数参数是不定参数,也就是说,你可以传入任意的参数值。使用JavaScript函数内置的arguments就可以遍历所有传入的参数。比如下面的代码:
arguments的行为很像数组,但它并不是数组。可以使用typeof操作符看一下,也可以调用它的constructor属性。
这里有一点需要说明,arguments有个callee属性,可以调用arguments自身所在的函数。也就是说,可以通过这个属性递归调用函数自身。所以,即使是匿名函数,也可以实现递归调用。如:
我觉得大家都会知道这个著名问题的答案的。
3. 函数也是对象
回想一下上面的第三个语句,它已经强烈暗示了,函数其实也是对象!那么,作为一个对象,函数应该具有对象的一切特性:添加属性、删除属性、作为返回值等等。是的!JavaScript的函数就是这么样的!
瞧!凡是对象可以做到的,函数统统都能做到!JavaScript中的函数就是对象!
现在我们已经从数组,逐渐开始到对象和函数。这些都是基本概念,后面,我们将对JavaScript的面向对象特性做进一步的介绍。

---------------------------------------------
类是面向对象程序设计的核心概念之一。一个类代表了具有相似属性的一类事物的抽象。从本篇开始,我们将正式的进入JavaScript的面向对象部分。首先需要注意的是,在JavaScript中并没有“类”这一关键字——在大多数语言中都是使用class作为关键字的。所以,这里的类就成了一个概念,它没有明确的语法标志。
1. 类和构造函数
前面说过,在JavaScript中并没有明确的类的概念。实际上,我们给出的只是类的构造函数。类的构造函数构成了这个类的全部内容。既然叫做构造函数,它也是一个普通的函数,没有什么不同之处。因此,我们能够很轻易的定义出一个构造函数:
function Person(name, age) {  
this.name = name;  
this.age = age;  
this.show =  function() {  
                alert( "Hello, my name is " +  this.name +  ", my age is " +  this.age);  
        };  
}
这里,我们定义了一个类 Person,它有两个属性:name和age;有一个方法:show。看上去和其他语言的类的定义没有什么不同。其实,这里最大的不同就是在于这个关键字function。我们使用了定义函数的方式定义了一个类。
2. new
定义出来类之后,需要创建类的对象。同其他语言一眼,JavaScript也使用new操作符创建对象。具体代码如下:
var bill =  new Person( "Bill", 30);  
alert(bill.name);  
alert(bill[ "age"]);  
bill.show();
这里使用new创建一个Person类的对象。和其他语言类似,new之后是该类的构造函数。当创建对象之后,就可以像前面的章节中说到的一样,使用.或者[]对属性进行访问。
注意一下,这里的构造函数就是一个普通的函数,那么,是不是所有的函数都可以使用new操作符呢?答案是肯定的。那么,这个new操作符到底做了什么呢?
当使用new操作符的时候,首先JavaScript会创建一个空的对象,然后将会对这个对象进行初始化。用什么来初始化呢?当然就是你调用的那个构造函数了。最后,这个创建的对象将返回给调用者,于是,我们就可以使用这个对象了。
3. prototype
prototype是原型的意思。在JavaScript中,每个对象都有一个prototype属性。这个属性指向一个prototype对象。这就是原型属性和原型对象的概念。
每个对象都有一个prototype属性,构造函数是一个普通的函数,而函数也是一个对象,因此,构造函数也有一个prototype属性。而每个prototype对象都有一个constructor属性,这个prototype对象的constructor属性指向这个prototype属性所在的构造函数本身。也就是说,new操作符要保证生成的对象的prototype属性和构造函数的prototype属性是一致的。
有点迷糊了不是?看一下下面的图,无论怎样,都要保证这个图所示的关系式正确的!
< onfocus="" onselect="" style="padding: 0px; margin: 0px; vertical-align:                                                                                           top; border: none; width: 194px; height: 261px;" onclick="" border="0" onerror="" onload="if(this.width>650) this.width=650;" onkeyup="" onunload="" ondblclick="" onsubmit="" onmousemove="" onmouseout="" onblur="" onresize="" onkeypress="" onmousedown="" width="28" onmouseover="" onreset="" onkeydown="" onabort="" height="30" onmouseup=""                                                                                           onchange="" alt="" />
需要大家注意的是,这个prototype对象是JavaScript的面向对象的基础,包括继承等的实现都是使用prototype。
4. 一个实现技巧:检测参数非空和设置参数默认值
由于JavaScript函数对于参数控制比较困难,因此参数检测成为一个不可忽视的问题。这里给出一个编程的小技巧,能够检查传入的实参是否非空,以及给参数设置默认值。
function print(mustHave, person) {  
var defaultPerson = {  
                name:  "noname",  
                age: 0  
        };  
if(!mustHave) {  // 非空检测  
                alert( "mustHave should not be null!");  
return;  
        }  
        person = person || defaultPerson;  // 设置默认值  
        alert(mustHave +  ": name- " + person.name +  "; age- " + person.age);  
}  
print();  
print( "sth");  
print( "sth", {name:  "new", age: 20});
非空检测比较简单。默认值的设置比较有技巧,利用了JavaScript的||操作的短路特性。如果形参person为空,那么||前半部分为false,通过或操作,将把person设置为defaultPerson;如果person非空,则||直接返回true,那么就不进行或操作。
PS:使用functionName.length可以获得形参的个数,在function内使用arguments.length获得的是实参的个数。

------------------------------
封装是面向对象的重要概念之一。如果一个程序没有封装性,也就谈不上什么面向对象。但是,JavaScript并不像其他的语言,比如Java,有公有变量和私有变量等;在JavaScript中只有一种作用域:公有作用域。在本章中,我们将会见识到JavaScript是如何实现封装的特性的。
1. this和公有变量
首先需要理解this关键字。看下面的一段代码,你应该对此感到熟悉:
function Person(name, age) {  
this.name = name;  // 定义一个公有变量  
this.age = age;  
this.show =  function() {  // 定义一个公有函数  
                alert( "name: " + name +  "; age: " + age);  
        }  
}  
var bill =  new Person( "Bill", 20);  
alert(bill.name);  
bill.show();
这里的this关键字是必不可少的。前面只是让大家记住,那么为什么要这样呢?想想JavaScript的对象,JavaScript的对象类似于散列,一个<string, object>键-值对的集合。这里的对象的属性实际上都是离散的,并不像其他的语言那样绑定到一个对象上面。this关键字指代的是属性或者函数的调用者,也就是说,谁调用这个属性或者函数指的就是谁。可以看到,这里的this和Java或者C++的this是有所不同的,后者的this是指属性或者函数所在的那个对象本身。而这里this的作用就是将它后面跟着的属性或者对象绑定到调用者上面。回忆一下JavaScript的new的过程,首先将创建一个空的对象,然后使用构造函数初始化这个对象,最后返回这个对象。在这个过程中,JavaScript将把this用这个对象替换,也就是把对象和这些属性或函数相关联,看上去就像是这个调用者拥有这个属性或者函数似的,其实这是this的作用。
这样看来,show里面的name和age并没有关键字,但也是可以正常的执行就会明白怎么回事了——因为前面已经用this把name和age与这个对象bill相关联,并且,show也关联到这个bill变量,因此JavaScript是可以找到这两个变量的。
似乎由this修饰的都是公有变量。事实确实如此,如果你要使一个变量成为公有变量,可以使用this。像上面代码中的name和age都是公有变量,在外面使用aPerson.name或者aPerson.age就可以访问到。
2. 私有变量
怎么声明一个私有变量呢?事实上就像前面说的,JavaScript根本没有私有作用域这一说。那么来看下面的代码:
function Person(name, age) {  
var name = name;  // 私有属性  
var age = age;  
var show =  function() {  // 私有函数  
                alert( "name: " + name +  "; age: " + age);  
        }  
}  
var bill =  new Person( "Bill", 20);  
alert(bill.name);  // undefined  
bill.show();  // error, 不存在    
这段代码和前面几乎是相同的,只是把属性前面的this换成了var。我们知道,var是用来声明变量的。show函数和bill.name都是未定义!这是怎么回事呢?
回忆一下前面说过的JavaScript的new的过程。由于name和age都是使用var声明的,JavaScript会将它看作是一个普通的变量,这样在构造初始化结束之后,构造函数就返回了,变量因超出作用域而访问不到。也就是说,我们使用JavaScript变量作用域模拟了私有属性。
3. 静态变量
静态变量是绑定到类上面的。对于不同的对象来说,它们共享一个静态变量。
Person.num = 0;  // 静态属性  
function Person() {  
this.show =  function() {  
                alert( "num: " + Person.num);  
        };  
        Person.num++;  
}  
var bill =  new Person();  
bill.show();  // 1  
var tom =  new Person();  
tom.show();  // 2  
bill.show();  // 2
在JavaScript中可以很方便的添加静态属性,因为JavaScript的对象就是散列,所以只要简单的在类名后添加一个属性或者函数即可。
4. 访问私有变量和公有变量
当对私有变量进行访问时,只需要使用变量的名字就可以了,但是,如果要访问公有变量,则需要使用this关键字。
function Person(name, age) {  
this.myName = name;  
var myAge = age;  
this.show =  function() {  
                alert( "show = name: " +  this.myName +  "; age: " + myAge);  
        }  
var showAll =  function() {  
                alert( "showAll = name: " +  this.myName +  "; age: " + myAge);  
        }  
}  
var bill =  new Person( "Bill", 20);  
bill.show();
在这里,如果去掉myName的this关键字,就会有未定义属性的错误。
简单来说,我们需要使用this来声明公有变量,使用var来声明私有变量。但是,JavaScript却不是那么简单,因为JavaScript是一个脚本语言,我们需要十分关心它的执行效率。下面,我们将会看一下JavaScript面向对象设计的最佳实践。


------------------------------------------------
闭包这个概念看上去很深奥,这个词在离散数学里面的意思确实比较难于理解。在这里,我们先可以把闭包理解成是一种匿名函数或者匿名类。
1. 什么是闭包?
什么是闭包?一种正式的解释是:所谓闭包,指的是一种拥有很多变量并且绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是这个表达式的一部分。
相信很多人都不会理解这个定义,因为他的学术味道太浓了——或许你喜欢从字面的语法上进行分析:首先,它是一个表达式,这个表达式绑定了很多变量以及这些变量的环境。不过这并没有什么意义,这依然不会告诉我们什么是闭包。
那么,来看一个例子:
function add(a) {  
return function(b) {  
return a + b;  
        };  
}  
var func = add(10);  
alert(func(20));
我想经过了前面有关函数的描述,这个例子应该很清楚的理解。JavaScript里面的函数就是对象,他可以做对象能做的一切事情——我们首先定义了一个函数add,它接受一个参数,这个函数返回一个匿名函数,这个匿名函数也接受一个参数,并且会返回这个参数同外部函数的那个参数的和。因此在我们使用的时候,我们将add返回的匿名函数赋值给func,然后调用func,就返回了这两个数的和。
当我们创建一个这样的函数,这个函数内部的一个变量能够在函数外面被引用时,我们就称创建了一个闭包。仔细的品味一下:这就是那个闭包的定义。
看看我们的代码:首先,它有一个内部变量,就是那个匿名函数;其次,这个函数将匿名函数返回了出去,以便外面的变量可以引用到内部定义的变量。
2. 闭包的作用
闭包有什么用呢?或许现在还看不出来,那么看看这段代码:
function inc(a) {  
var i = 0;  
return function() {  
return i;  
        };  
}  
var num = inc();  
alert(num());
本来,这个变量 i 在函数外面是访问不到的,因为它是 var 定义的,一旦跳出作用域,这个变量就被垃圾回收了,但是,由于我们使用了闭包,在外面是能够访问到这个变量的,因此它并不被垃圾回收!
如果还是不明白闭包的作用,那么看一段应该很熟悉的代码:
function Person() {  
var id;  
this.getId =  function() {  
return id;  
        }  
this.setId =  function(newId) {  
                id = newId;  
        }  
}  
var p =  new Person();  
p.setId(1000);  
alert(p.getId());  // 1000  
alert(p.id);  // undefined
我们定义一个类Person,它有一个id属性。现在这个属性的行为很像是私有变量——只能通过 setter 和 getter 函数访问到。没错,这就是闭包的一个用途:制造类的私有变量!
闭包还有一个作用:在内存中维护一个变量,不让垃圾回收器回收这个变量。这里的例子就不再举出了。
这里我们只是简单的说了JavaScript的闭包的概念,并没有涉及闭包的内存模型等等之类。这是一个相当重要的概念,Java社区中的部分成员一直对闭包梦寐以求,C#也已经在最新版本中添加了闭包的概念,只不过在那里称为lambda表达式。
---------------------------------------------------
http://devbean.blog.51cto.com/448512/174940 
雅的封装还是执行的效率?这是一个悖论。
优雅封装的程序看起来是那么的美妙:每个属性被隐藏在对象之后,你所能看到的就是这个对象让你看到的,至于它到底是怎么操作的,这个不需要你操心。
执行的效率就是另外一回事。就像是C语言和面向对象的C++之间的差别:C++很优雅,但是执行效率,无论是编译后的二进制代码还是运行期的内存的占用,都要比简单的C语言多出一截来。
这个问题在脚本语言中显得更加重要,因为JavaScript根本就是一种解释语言,解释语言的执行效率要比编译语言低很多。
1. 优雅的封装
我们先来看看变量封装。这里的变量不仅仅是属性,也包括函数。
前面已经说过,JavaScript中并没有类这个概念,是我们利用变量作用域和闭包“巧妙的模拟”出来的,这是一种优雅的实现。还是温故一下以前的代码:
function Person() {  
var id;  
var showId =  function() {  
                alert( "My id is " + id);  
        }  
this.getId =  function() {  
return id;  
        }  
this.setId =  function(newId) {  
                id = newId;  
        }  
}  
var p =  new Person();  
p.setId(1000);  
alert(p.id);  // undefined  
// p.showId(); error: function not defined  
var p2 =  new Person();  
alert(p.getId == p2.getId);  // false
我们很优雅的实现了私有变量——尽管是投机取巧的实现的。但是,这段代码又有什么问题呢?为什么两个对象的函数是不同的呢?
想一下,我们使用变量的作用域模拟出私有变量,用闭包模拟出公有变量,那么,也就是说,实际上每个创建的对象都会有一个相同的代码的拷贝!不仅仅是那个id,就连那些showId、getId 等函数也会创建多次。注意,考虑到JavaScript函数就是对象,就不会感到那么奇怪了。但是毫无疑问,这是一种浪费:每个变量所不同的只是自己的数据域,函数代码都是相同的,因为我们进行的是同一种操作。其他语言一般不会遇到这种问题,因为那些语言的函数和对象的概念是不同的,像Java,每个对象的方法其实指向了同一份代码的拷贝,而不是每个对象都会有自己的代码拷贝。
2. 去看效率
那种封装虽然优雅,但是很浪费。好在JavaScript是一种灵活的语言,于是,我们马上想到,把这些函数的指针指向另外的一个函数不就可以了吗?
function show() {  
        alert( "I'm a person.");  
}  
function Person() {  
this.show = show;  
}  
var p1 =  new Person();  
var p2 =  new Person();  
alert(p1.show == p2.show);  // true
这个办法不错,解决了我们以前的那个问题:不同的对象共享了一份代码。但是这种实现虽然有了效率,可是却太不优雅了——如果我有很多类,那么岂不是有很多全局函数?
好在JavaScript中还有一个机制:prototype。还记得这个prototype吗?每个对象都维护着一个prototype属性,这些对象的prototype属性是共享的。那么,我们就可以把函数的定义放到prototype里面,于是,不同的对象不就共享了一份代码拷贝吗?事实确实如此:
function Person() {  
}  
Person.prototype.show =  function() {  
        alert( "I'm a person.");  
}  
var p1 =  new Person();  
var p2 =  new Person();  
alert(p1.show == p2.show);  // true
不过,这种分开定义看上去很别扭,那么好,为什么不把函数定义也写到类定义里面呢?
function Person() {         
        Person.prototype.show =  function() {         
                alert( "I'm a person.");         
        }         
}         
var p1 =  new Person();         
var p2 =  new Person();         
alert(p1.show == p2.show);  // true
实际上这种写法和上面一种没有什么不同:唯一的区别就是代码位置不同。这只是一个“看上去很甜”的语法糖,并没有实质性差别。
最初,微软的.Net AJAX框架使用前面的机制模拟了私有变量和函数,这种写法和C#很相像,十分的优雅。但是,处于效率的缘故,微软后来把它改成了这种原型的定义方式。虽然这种方式不那么优雅,但是很有效率。
在JavaScript中,这种封装的优雅和执行的效率之间的矛盾一直存在。现在我们最好的解决方案就是把数据定义在类里面,函数定义在类的prototype属性里面。




定义和用法

prototype 属性使您有能力向对象添加属性和方法。

语法

object.prototype.name=value                                                                                                                                                                                                                                

实例

在本例中,我们将展示如何使用 prototype 属性来向对象添加属性:

<script type="text/javascript">function employee(name,job,born){this.name=name;this.job=job;this.born=born;}var bill=new employee("Bill Gates","Engineer",1985);employee.prototype.salary=null;bill.salary=20000;document.write(bill.salary);</script>                                                                                                                                                                                                                                


原创粉丝点击