JavaScript权威指南之学习笔记(第六版)_第1页
JavaScript权威指南之学习笔记(第六版)_第2页
JavaScript权威指南之学习笔记(第六版)_第3页
JavaScript权威指南之学习笔记(第六版)_第4页
JavaScript权威指南之学习笔记(第六版)_第5页
已阅读5页,还剩48页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、JavaScript权威指南之学习笔记(第六版)核心笔记一、说明JS权威指南文字用红色标出;JS高级程序设计用橙色标出;自己加上的文字用粉红色标出;其(一)-(九)为JS权指南,(十)为JS高级程序设计 二、记法结构2.1字符集Javascript程序用的是Unicode字符集编码。2.2大小写敏感Javascript是一种区分大小写的语言,但是注意HTML是不区分大小写的(尽管XHTML区分大小写的)。也即在HTML中这些标记和属性名可以任意的大小写方式输入,但是在Javascript中它们通常都是小写的。2.4可选的分号尽管理论上说来JS允许在任意两个标识符之间放置换行符,但是实际上JS会

2、自动插入分号。例:ReturnTrue;JS会假定你的意图是:Return;True;2.7标识符第一个字母必须是字母、下划线或美元符号($)!三、数据类型和值3.1数字Javascript不区整型值和浮点型数值。在Javascript中,所有的数字都是由浮点型表示的。3.1.1,3.1.2整型直接量、八进制和十六进制的直接量十六进制直接量是以”0x”或”0X”开头,而八进制是以数字0开头。在ECMAScript标准中不支持八进制的直接量,但是Javascript的某些实现是允许八进制格式的整型直接量的。所以一般最好不要使用以0开头的整型直接量。3.1.3浮点直接量例如3.14234.342.

3、3424242.32e231.23424E-323.1.6特殊的数值当一个算术运算(如0除0)产生了未定义的结果或错误时,就会返回一个特殊的非数字的值,为NaN。这个数字值和任何数值都不相等,包括它自己在内,所以需要一个专门的数字来检测IsNaN()来检测这个值。特殊数值常量NAN Infinity 无穷大Number.MAX_VALUENumber.MIN_VALUENumber.NaNNumber.POSITIVE_INFIITYNumber.NEGATIVE_INFITY这是特殊的常量都是在运算时可能产生的,用IsNaN()或isFinite()等函数来检测。3.2字符串3.2.1字符串

4、直接量字符串是由单引号或双引号括起来的Unicode字符.在单引号可以含有双引号,双引号可以含有单引号。3.2.2字符串直接量中的转义序列0 b t n r v f ” uXXXX(四位十六进制的Unicode字符)xXX由两位十六进制指定的latin-1字符3.2.3字符串使用可以用(+)来连接字符串。3.2.4数字转换为字符串Var number=100;Var s=number.toString();还可以指定转换的基数,Var s=number.toString(16);还有三个函数可以精确指定转换后的数字格式,toFixed(),toExponential(),toPrecision

5、(); 3.2.5字符串转换为数字当把一个字符串用于数字环境中,它也会自动地转换为一个数字,Var t=”21” * “2”;利用这一优点,只要把一个字符串减去0就可以将其转换为一个数字。Var t=string_value-0;ParseInt()和ParseFloat(),这两个函数可以从字符串开始处转换和返回任何的数字,忽略或舍去非数字部分。ParseInt()甚至可以接受另一个参数来指定要解析的数字的基数。合法的范围在2至36之间。ParseInt(“012”,2);ParseInt(“0x23”);/默认返回10进制这两个函数不能把指定的字符串转换为数字,它们会返回NaN.Parse

6、Int(“ele”);/返回NaN3.7NullNull被看作对象类型的一个特殊值,即代表“无对象”的值。3.8undefined使用了已经声明但还没有赋值的变量时,又或者使用了一个并不存在的对象属性时,返回的就是这个值。注意这个特殊的undefined值不同于null。但是=运算符却将两者相等的。3.11Error对象当运行发生错误时,Js会抛出某个类的对象。3.12类型转换小结不同的值在不同的环境运行时所转换成的值值字符串数字布尔对象未定义的值“undefined”NaNfalseErrorNull“null”0falseError非空字符串不变字符串中的数字值或NaNtrueString

7、空字符串不变0falseString0“0”不变falseNumberNaN“NaN”不变falseNumber无穷“InFinity”不变trueNumber负无穷“-InFinity”不变trueNumber任意其他的数字数字字符串值 不变trueNumberTrue“true”1不变BooleanFalse“false”0不变Boolean对象toString()valueOf(),toString(),或NaN true 不变注:对于对象的转换,当在一个数字环境时JS首先调用该对象的ValueOf()方法,如果这个方法返回一个基本类型的值,这个值会被使用,然而在大多数情况下,value

8、Of()方法返回的是对象自己,在这种情况下,JS先使用toString()方法把对象转换为一个字符串,然后再试图把该字符串转换为一个数字。3.13,3.14基本数据类型的包装对象跟C#或JAVA里的包装对象是一样的,比如用一个字符串变量时使用了一个字符串对象的方法或属性,JS会为这个字符串值内部创建一个String包装对象.String对象替代了原始的字符串值。注意,这个对象中只是瞬时存在的,在用完以后就没有用了,系统会把它丢弃。Var s=”asdf”;Var len=s.length;/用长度属性。注意:JS中函数的方法call(),apply(),可能还有其它的方法能被字符串常量,数字,

9、布尔类型甚至null,undfined调用,为什么?因为包装对象啊!在这两个函数里面需要对象所以就把常量包装成对象了来调用对象,用完就丢掉!jQuery中的的each方法循环对象的属性时就是用的这个特性。3.15传值和传址基本类型为Null,Undefinded,布尔型,数字。引用类型为数组、函数、对象。JS字符串是通过传址来复制和传递的,而它们是通过传值来比较的。可以说是既能是基本类型又是引用类型!四、变量4.1变量类型JS是非类型的,也即变量可以存放任意类型的值。4.2变量的声明重复的声明和遗漏的声明可以使用VAR语句重复声明一个变量不仅是合法的,而且也不会造成任何错误。如果尝试读一个未声

10、明的变量的值,JS会生成一个错误。如果尝试给一个用VAR语句的变量赋值,JS会隐式声明这个变量,但注意,隐式声明的变量总是被创建一个全局变量,即使该变量只是一个函数体内使用。4.3变量的作用域如果一个局部变量或函数的参数声明的名字与某个全局变量的名字相同,那么就有效地隐藏了这个全局变量。局部变量必须是用var语句,否则就是全局变量了。4.3.1没有块级作用域JS中没有块级作用域的概念,函数中声明的所有变量无论是在哪里声明的,在整个函数中它们都是有定义的。实际这个说法对全局变量也是起作用的,例Var scope=”global”Function f()Alert(scope);/displays

11、 “undefined”,not globalVar scope=”local”;Alert(scope);/displays “local”F();局部变量在整个函数体内部都是有定义的,这就意味着在整个函数体中会隐藏了同名的全局变量。虽然局部变量在整个函数体中是有定义的,但是在执行var语句之前,它是不会被初始化的。这个例子说明了把有的变量集中起来放置在函数的开头是一个好的编程习惯。4.3.2未定义变量和未赋值变量未定义变量就是没有被告声明过的,无论是显示声明不是隐式声明,读取这样的变量会出错.未赋值的变量是虽已经声明了,但是没有给它赋值!4.6作为属性的变量4.6.1全局对象JS解释器开始

12、运行时,它首先要做的事情之一就是在执行任何JS代码之前,创建一个全局对象,这个对象的属性就是JS程序的全局变量。当声明一个JS的全局变量或函数时,实际上所做的是定义了那全局对象的一个属性。或者说用一个同名的属性来存储全局变量和全局函数。此外,JS解释器还会用预定义的值和函数来初始化全局对象的许多属性,如Infinity,parseInt,Math分别引用了数值infinity,预定义函数ParseInt()和预定义对象Math.在程序的顶层代码(不是函数中的代码)可以用this关键字来引用这个全局对象。在客户端JS中,Window对象代表浏览器窗口,它是包含在该窗口中的所有JS代码的全局对象,

13、这个全局对象具有自我引用的window属性,它代替了this属性,可以用来引用全局对象。4.6.2局部变量: 调用对象内嵌的函数、函数的参数和局部变量是调用对象的属性。调用对象是在函数运行时创建的!一般用完就释放,除非产生了闭包!4.7深入理解变量作用域在JS的顶层代码中,作用域链只由一个对象构成,那就是全局对象。所有的变量都是在这一对象中查询的。如果一个变量存在,那么这个变量的值就是未定义的。在一个函数(非嵌套)中,作用域链由两个对象构成,第一个函数的调用对象,第二个就是全局对象。当函数引用一个变量时,首先检查的是调用对象,其次才检查全局对象。在嵌套函数的作用域链中可以后在三个或更多的对象,

14、查找方式以此类推。以上所说也就是一个函数在运行的时候的查询变量的情况的流程!这在闭包中也是这样的一个查找过程!五、表达式和运算符5.3算术运算符1.除法运算符在js中,由于所有的数字都是浮点型的,所以除法的结果也是浮点型的(不像C+或C#中的那种除出来是整形!),除数是0的结果为正无穷大或负无穷,而0/0的结果则是NaN.2.模运算符取模操作的运算数通常都是整数,但它也适用于浮点数,如-4.3%2.1=-0.1;除了加号比较特殊外,其它减、除、模、一元减(-)、一元加(-)、递增运算符(+)、递减运算符(-)都会把非数字变成数字的!5.4相等运算符5.4.1相等运算符和等同运算符判定=运算符比

15、较的两个值是否相等。如果两个值具有相同的类型,那么就检测它们的等同性。如果两个值的类型不同,它们仍然可能相等,用下面的规则和类型转换来检测它们的相等性。(数字有最高的优先级)1)如果一个值是Null,另一个值是Undefined,则它们相等。2)如果一个值是字符串,另一个值是数字,那么字符串先转化为数字再进行比较3)如果一个值是布尔值,另一个值为数字或字符串,布尔值和字符串都先转化为数字再进行比较,true为1,false为0.4)如果一个值是对象,别一个是数字或字符串,则对象转换为相应的原始类型的值。5)其它组合的值不等的。5.5关系运算符5.5.1比较运算符(<,>,<=

16、,=>)这些比较运算符的运算数可以是任意类型的。但是比较运算只能在数字和字符串上执行,所以不是数字或字符串的运算数将被转换为数字或字符串。1)      字符串和数字比较,转换为数字再进行比较。2)操作数不能转换为数字或字符串时,比较结果为false。3)若一个操作数为NAN或转换为了NAN,比较结果为false。5.5.2In运算符In运算符要求左边的运算数是一个字符串,或可以被转换为字符串,右边的运算数是一个对象或数组或函数。如果该运算符左边的值是其右边对象的一个属性名,它返回true。例Var point=x:1,y:2;Var h

17、as_x_record=”x” in point;/return trueVar has_z_record=”z” in point;/return false函数之所以可以由此运算符来检测属性,因为函数也可以有属性,并且本身就是特殊的对象(或叫类更好些),所以由推开去,很多对象有的功能,函数和数组也有5.5.3instanceof运算符(跟C#的is关键字类似)Instanceof运算符要求左边的运算数是一个对象,右边的运算数是对象类型的名字。注意,所有对象都是类object类的实例。例:Var d=new Date();d instanceof Date;/return trued ins

18、tanceof Object;/return trued instanceof Number/return falsevar a=1,2,3;a instanceof Array;/return truea instanceof Object;/return true5.6字符串运算符字符串算符“+“中,字符串的优先级最高。如:1+”2”=”12”,”2”+1=”21”.5.7逻辑运算符5.7.1逻辑与运算符(&&)先计算左边表达式的值,如果左边表达式值可以转换为false,那么返回的是左边表达式的值,否则,它将计算右边的表达式的值,并且返回这个表达式的值。5.7.2逻辑或运算

19、符(|)原理同逻辑与运算符,先计算左边表达式的值,如果左边表达式的值可以转换为true,则返回这个表达式的值,否则,它将计算右边表达式的值,并且返回该表达式的值。5.7.3逻辑非运算符(!)在对操作数取反之前,!运算符先把它的运算数转换为一个布尔类型的值,这意味着,对任何值x应用两次运算符(即!x)都可以将它转换成一个布尔值。第一次为了使操作数在布尔环境中取得操作数的相反的布尔值,而第二次就是使取得操作数的正确的布尔值!5.10其它运算符5.10.2typeof运算符(与C#的typeof()运算符一样的)它测试一个操作数,返回一个字符串来表式一个操作数的类型。对数字、字符串或布尔值,返回”n

20、umber”、”string“、”boolean”,而对数组、对象和Null,它返回的是”object”,而对函数运算数,返回的是”function”,如果运算数是未定义的,它将返回”Undefined”.5.10.4delete运算符它将删除运数所指定的对象的属性、数组元素或变量或函数的属性。如果删除成功返回true,若不能删除,返回false。并非所有的属性和变量都是可以删除的,某些内部的核心和客户端属性不能删除,用var语句声明的用户定义变量也不能被删除。注意,删除属性、变量(数组不一样)不只是把它们的值设置为undefined,当删除它们后,它们全部变成未定义的,也即不存在的,再次尝试

21、读取它们时会出错。Delete所能影响的只是属性值,并不能影响被这些属性引用的对象,即这些对象只要用其它属性引用就还存在!5.10.5void运算符它可以出现在任何类型操作数之前,它总是舍弃运算数的值,然后返回undefined.这种运算符通常用在客户端的javascript:Url中,在这里可以计算表式的值,但是不会显示出这个值。<a href=”javascript:void window.open();”>open a widnow</a>六、语句6.1switch语句ECMAScript v3标准允许case 语句扣跟随任意的表达式。例如:Case 60*60:

22、Case Math.pi;Case n+1;注意:由于匹配的case表达式是用=等同运算符判定的,而不是用=运算符判定的,所以表达式必须在没有类型转换的情况下进行匹配。6.9for/in语句For(variable in object)statementVariable应该是一个变量名,声明一个变量的var语句,数组的一个元素或者是对象的一个属性。Object是一个对象名。在循环体执行之前,对象的一个属性名会被作为字符串赋给变量variable。在循环体中可以使用这个变量和运算符查询该对象属性的值。注意,for/in循环中的variable可以是任意的表达式,只要它们的值适用于赋值表达式的的左

23、边即可。JS的数组是一种特殊的对象,因此可以像循环对象属性那样枚举数组下标。如果for/in循环的主体删除了一个还没有枚举出的属性,那么该属性就不再枚举,如果循环主体定义了新属性,那么循环是否枚举该属性则由JS的实现决定。For/in循环并不会遍历所有对象的所有可能的属性,那些被标记为只读的、永久的或不可列举的(继承的也不可以),这些属性使用此语句是枚举不出来的,所有用户自定义的属性可以枚举的!6.14function语句函数定义可以嵌套在其它函数定义中,但是只能嵌套在那些函数顶层中,也就是说,函数定义不能出现在IF语句,while语句或其它任何语句中。在技术上说,function语句并非是一

24、个语句.JS中语句会引发动态的行为,但是函数定义描述的却是静态的程序结构。语句是在运行时执行的,而函数则是实际运行之前,当JS代码被解析或被编译时定义的。当JS解析程序遇到一个函数定义时,它就解析并存储构成函数主休的语句,然后定义一个和该函数同名的属性(如果函数定义在其它的函数中,那么就在调用对象中定义这个属性,否则在全局对象中定义这个属性)以保存它。这会产生一些奇怪的行为。例:Alert(f(4);/displays 16Var f=0;Function f(x);Reutrn x*x;Alert(f);displays 0.f() has been overwritten by the v

25、ariable f出现这种情况是由于函数定义和变量定义出现在不同的时刻。6.15return语句如果一个函数执行了一个不带expression的return语句,或者因为它执行到了函数的尾部而返回,那么这个函数的表达式的值就是undefined。6.16throw语句Throw expressionExpression的值可以是任何类型的值,但通常它是一个Error对象或Error子类的一个实例。6.17try/catch/finally语句这个语句的使用和c#的使用差不多。Try catch(e) finally七、对象和数组7.1对象包含在一个花括号中,每个属性名可以是一个JS标识符或一个

26、字符串或一个字符串,而每个属性值可以是一个常量或任意的JS表达式。例:Var empty=;Var point=x:0,y:0;Var homer=“name”:”homer”,”age”:34;(2)new创建对象Var d=new Date();Var reg=new RegExp();7.2对象属性对象的属性和变量工作方式相似,即可以把值存储其中,也可以从中读取值。一旦通过给属性赋值创建了该属性,就可以在任何时刻修改这个属性的值。可以通过把一个值赋给对象的一个新属性来创建它。Var book=;Bool.widht=20/create 7.2.1属性的枚举For/in语句枚举属性。JS权

27、威指南中说,for/in循环枚举列出的属性并没有特定顺序,其它细节见6.9.但是,我做了一个示例它是按属性的定义来枚举的,那会在什么情况下的顺序会不定呢?var obj= t1:1, t2:2, t3:3, t4:4 ;for(o in obj)alert(objo);/output 1,2,3,47.2.2检查属性的存在In运算符可以用来测试一属性的存在,详见.3删除属性delete运算符删除属性并不是仅仅把属性设置为undefined,它实际上从对象中移除了属性,在删除之后,for/in将不会枚举该属性。详见作为关联数组的对象就是用像读取数组的方式来读取属

28、性值。其实对象的属性也可以是数字的,类数组的对象!Opery;Obj“property”/关联数组7.4通用ojbect属性和方法7.4.1.constructor属性每个对象都有一个constructor属性,它引用了初始化这个对象的构造函数。例:Var d=new Date();d.constructor=Date/return true 7.4.3.hasOwnProperty()方法如果此方法中指定的参数属性来自本地定义的一个非继承的属性,此方法返回true。Var o=;O.hasOwnProperty(“unde”);/return false,the property

29、 is not definedO.hasOwnProperty(“toString”);/false,toString is an ihherited propertyMath.hasOwnProperty(“cos”);/true:the Math object has a cos pertyIsEnumeralbe()方法如果此方法中指定的参数属性来自本地定义的一个非继承的属性,并且如果这个属性可以在一个for/in循环中枚举,此方法返回true。注意,一个对象的所有用户定义的属性都是可以枚举的,不能枚举的属性通常是继承的属性,因此这个方法几乎总是会和ha

30、sOwnProperty()返回相同的值。7.4.7.isPrototypeOf()方法如果此方法所属的对象是参数的原型对象,那么就返回true。Var o=;Ototype.isPrototypeOf(o);/trueObject.isPrototypeOf(o);/false7.5数组数组不过是一个具有额外功能的对象。 字面值创建数组Var empty=;Var primes=2,3,4;Var misc=1.1,true,”ik”;直接量的值还可以是表达式Var base=23;Var tablebase,base+3,base+4;直接量还可以是对象直接量或数组直接量

31、Var b=1,x:1,y:2,2;未定义的元素通过忽略逗号之间的元素值来创建Var count=1,2;/数组有三个元素,中间的元素没有赋值Var undef=,;/数组有2个元素,全部为没有赋值用Array()构造函数创建数组Var a=new Array():Var b=new Array(3,2.3,4,”saf”,”sf”);Var c=new Array(10);/这里的每个元素都没有赋值为undefined7.6数组元素的读写7.6.1添加数组新元素JS中可以在任何时刻改变元素个数,而且由于JS数组是稀疏的,即数组的下标不必落在一个连续的数字范围内,只有那些真正存储在数组中的元素

32、才能由JS实现分配内存。例 a0=1;a100=2;这里JS解释器只给数组下标为0和100的元素分配内存,而试图访问其它的元素时将得到一个undefined7.6.2删除数组元素用delete运算符把一个元素设置为一个undefined值,但是元素本身还继续存在,要真正地删除一个元素,那么必须使用一个数组方法。(当用方法移出了一个元素后,再去访问该元素,虽然也会返回一个undefined值,但用length属性去测试会发现长度变短了,说明是真正的移出了一个元素;但是仅仅用delete运算符去删除一个元素,用length属性去测试时会发现长度没有变,说明没有真正移出元素!)7.6.3.数组长度(

33、length属性)7.6.5截断或增长数组 Length属性是可读可写的,通过修改length的值可以截断和增长数组的长度。7.6.6多维数组JS不支持真正的数组,它支持数组的数组,即变长数组!Var a=new Array(10);For(var b=0;b<a.length;b+)Ab=new Array(10);7.7数组方法参考API去7.8类似数组的对象把任何具有一个length属性以及相应的非负整数属性的对象作为一种数组,这是合理。虽然不能调用数组的方法或者length属性期待特殊的行为,仍然可以用遍历一个真实数组代码来遍历它们。事实证明,许多数组对于类似数组的对象和真正的数

34、组对象都是一样有效的。只要不尝试对类似数组的对象添加元素或者改变length属性。()例:var a=;var i=0;while(i<10)ai=1*I;i+;a.length=i;var total=0;for(var j=0;j<a.length;j+)total+=aj;结果:45a.length=9;/改变length属性想改变类似对象数组的元素个数。 for(var j=0;j<a.10;j+)total+=aj;结果为:45上述改变为什么不成功?因为这些操作对类似数组的对象没用,想通过改变length来改变类似对象数组的个数,那是不可能的,它仅仅是一个对象的属性

35、。不能作任何用处实际上!八、函数8.1函数定义和调用JS也不会检测传递的数据是不是那个函数所要求的类型,也不会检测传递给它的参数个数是否正确。如果传递的参数比函数需要的个数多,那么多余的值会忽略掉; 如果传递的参数比函数需要的个数少,那么所被忽略的参数就被赋予undefined。8.1.2函数直接量Var f=function(x) return x*x;或Var f=fucntion fact(x) return x*x;/也可以加函数名字Var test=(function(x) return x*x;)(10);/定义后马上调用8.1.3函数命名函数名小写字母开始!8.2函数参数8.2.

36、1.可选参数它是利用了当传递给函数的参数个数小于函数的参数时,其它的参数有一个undefined值。要用可选参数时,必须能够为忽略掉的参数分配一个默认的合理值。Function test(o,/*optional*/ a)a=a | ;for(var property in o) a.push(property);return a;注意,在使用可选参数时,应该确保把可选参数放在参数列表的末尾。8.2.2.可变长度的参数列表:arguments对象arguments并不是一个数组,它是一个对象,它虽然定义了带编码的元素和length属性。arguments对象允许完全地存取那些实际参数值,即使某

37、些或全部参数还没有被命令。例如有一个函数f,它定义了一个参数x,但是调用f时传递给了它两个参数,那第个一参数可以用x或arguments0可以存取第一个参数,而第二个实际参数只能通过arguments1来存取。一般argumetns对象来编写这样的函数:期待固定数目的具有名字的且必须的函数,紧接着是任意数目的没有命名的可选参数。Arguments数组和命名了的参数不过是引用同一变量的两种不同方法。相反,用参数名改变一个参数的值同时会改变通过arguments数组获得的值;通过arguments数组改变参数的值同样会改变用参数名获取的参数值。记住,arguments只是一个普通的JS标识符,而不

38、是一个保留字,如果函数有一个参数或者局部变量使用了这个名字,它就会隐藏对arguments对象的引用。属性calleearguments对象用callee属性来引用当前正在执行的函数!8.4作为方法的函数Var calculator=Operand1:1,Operand2:2,Compute:function()This.result=this.operand1+this.operand2;任何用作方法的函数都被效地传递了一个隐式的参数,即this,调用对象。当一个函数作为函数而不是作为方法调用的时候,这个this关键字引用全局对象.当一个嵌套的函数(作为函数)在一个包含的函数之中调用,而这个

39、包含的函数是作为方法调用的,this关键字在包含的函数中有一个值,但是它却引用嵌套的函数体的内部的全局对象。8.6函数的属性和方法8.6.1属性length这个属性是只读属性,返回的是函数需要的实际参数的数目,也就是在函数的开式参数列表中声明的形式参数的数目。注意,和arguments.length不同,这个length属性在函数体的内部和外部都有效。8.6.3定义自己的函数属性当函数需要使用一个在调用过程中都保持不变的值时,使用function对象的属性比定义全局变量更加方便。也即我们可以为函数定义属性。例:UniqueInteger.counter=0;Function uniqueInt

40、eger()Return uniqueInteger.counter+;这里的counter相当于函数的静态局部变量一样!8.6.4方法apply()和call()call和apply的第一个参数都是要调用函数的对象,在函数体内这一参数是关键字this值。call()剩余的参数是传递给要调用的函数的值。例:f.call(o,1,2)上例是把两个数字传递给函数f(),并将它作为对象的方法调用。apply()传递给函数的参数是由数组指定的。f.apply(o,1,2):8.8函数作用域和闭包8.8.1词法作用域JS函数是通过记法来划分作用域的,而不动态地划分作用域的。这意味着,它们在定义它们的作用

41、域里运行,而不是在执行它们的作用域里运行。当定义一个函数时,当前的作用域链就保存起来,并且成为函数的内部状态的一部分。在最顶级,作用域链仅由全局对象组成,而并不和词法作用域相关。当定义一个嵌套的函数时,作用域链就包括外围的函数。这意味着嵌套的函数可以访问包含函数的所有参数和局部变量。8.8.2 调用对象当JS解释器调用一个函数时,它首先将作用域设置为定义函数的时候起作用的那个作用域链。接下来,它在作用域的前面添加一个新对象,即调用对象。然后把函数内的传递的参数和局部变量及Arguments对象都放在调用对象中8.8.4作为闭包的嵌入函数如果定义了一个嵌套的函数,这个函数引用了调用对象,因为调用

42、对象在这个函数所定义的作用域链的顶端。如果一个嵌套的函数只是在外围函数的内部使用,那么,对嵌套函数的唯一引用在调用对象之中。当外围函数返回的时候,嵌套的函数引用了调用对象,并且调用对象引用了嵌套的函数,(互相引用?)但是没有其它的东西引用它们二者,因此对这两个对象进行垃圾回收。(看看全局对象和调用对象的说法,就能理解嵌套函数引用了调用对象和调用对象引用了嵌套的函数)如果把一个嵌套的函数的引用保存到一个全局作用域中,情况不同了。使用嵌套函数作为外围函数的返回值,或者把嵌套的函数存储为某个其他对象的属性来做到这一点。在这种情况下,有一个对嵌套的函数的外部引用,并且嵌套的函数将它的引用保留给外围函数

43、的调用对象。结果是外围函数的一次特定调用的调用对象依然存在,函数的参数和局部变量的名字和值在这个对象中得以维持。JS代码不会以任何方式访问这个调用对象,但是它所定义的属性是对嵌套函数任何调用的作用域链的一部分。(注:如果一个外围函数存储了两个嵌套函数的全局引用,这两个嵌套函数共享同一个调用对象,并且,一个函数的一次调用所做出的改变对于另一个函数的调用来说也是可见的)JS函数是将要执行的代码以及执行这些代码的作用域构成一个综合体,叫闭包。JS解释器调用一个函数时,会创建一个执行环境,而一个执行环境是和作用域链相关的。例子:function a()    &

44、#160;var i = 0;    function b()      alert(+i);        return b;      var c = a();   c();  1. 当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时a所在的“环境”,如果

45、a是一个全局函数,则scope chain中只有window对象。2. 当执行函数a的时候,a会进入相应的执行环境(excution context)。3. 在创建执行环境的过程中,首先会为a添加一个scope属性,即a的作用域,其值就为第1步中的scope chain。即a.scope=a的作用域链。4. 然后执行环境会创建一个活动对象(call object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过JavaScript代码直接访问。创建完活动对象后,把活动对象添加到a 的作用域链的最顶端。此时a的作用域链包含了两个对象:a的活动对象和window对象。5. 下一步是在活

46、动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。把所有函数a的形参和内部的函数b的引用也添加到a的活动对象上。在这一步中,完成了函数b的的定义,因此如同第3步,函数b的作用域链被设置为b所被定义的环境,即a的作用域。九、类、构造函数和原型JS中函数是特殊对象,而且这个特殊对象是有属性和方法的,那么如果用函数名去调用它自身的方法,方法中this指向的就是这个函数!Jquery中S的extend方法就是这样!Jquery函数,extend就是它的方法!9.1构造函数通过构造函数首字母大写,以区分普通函数。实际上它们是没有区别的!Function Car()9.2原型和继承

47、JS对象从它的原型那里继承属性一个对象的原型就是它的构造函数的prototype属性的值。所有的函数都有一个prototype属性,当这个函数被定义的时候,prototype属性自动创建和初始化。Prototype属性的初始化是一个对象,这个对象中带有一个属性。这个属性名为constructor,它指回到和原型相关联的那个构造函数。添加给这个原型对象的任何属性,都会成为被构造函数所初始化的对象的属性。原型对象是放置方法和其他不变属性的理想地方。注意,继承作为查找一个属性值的过程的一部分。属性并非从原型对象那里复制到新对象,它们只是像那些对象的属性一样地出现。首先,使用原型对象可以显著地减少每个

48、对象的内存数量。其次,即便是在对象创建以后才添加到原型中的属性,对象也可以继承它。9.2.1读取和写入继承的属性当读取对象o的属性p的时候,JS首先检查o是否有一个名为p的对象。如果没有,它接下来检查o的原型对象是否有一个p的属性。当写入一个对象的属性值的时候,JS不会使用原型对象。9.3JS中模拟类9.3.1实例属性每个对象都拥有它的实例属性的一份单独拷贝。默认情况下,JS中的任何对象属性都是一个实例属性,这里我们特指由构造函数创建和初始化的属性。9.3.2实例方法在JS中,通过构造函数的原型对象中的一个属性设置为一个函数值,从而定义了一个实例方法。每个实例方法由一个类的所有实例方法共享。9

49、.3.3类属性也就是为构造函数定义属性,跟普通的函数一样的。Test.Unique=2;9.3.4类方法也就是为让相应函数成为构造函数的一个属性而已。Test.f=function() 9.3.7私有成员JS中没有私有成员。一般把属性设置为以下划线开头的属性。来自JS高级程序设计:定义类的常用两种方法1.混合构造函数/原型方式Function Car(scolor,sdoors)This.color=scolor;This.door=sdoors;Ctotype.showColor=function () alert(this.color);2.动态原型方法Function Car

50、(scolor,sdoors)This.color=scolor;This.door=sdoors;If( typeof Car._initialized=”undefined”)Ctotype.showColor=function()alert(this.color);Car._initialized=true;9.4通用对象模型9.4.1toString方法当定义一个类时,就为它定义一个toString()方法。9.4.2valueOf方法如果一个类需要把对象转换为某种基本类型,一般是转换为数字。那么可以为这个类定义此方法。注意,在某些条件下,在把一个对象转换为一个字符串的时候

51、,valueof方法可以比toString()方法更优先使用。因此如果要把类强制转换为一个字符串时,可能需要更加显式调用toString()方法。9.4.3比较方法要比较对象时最好自定义一个方法。因为等同运算符和相等运算符比较的是对象的引用,而关系运算符会把对象转换为数字或字符串。9.5超类和子类例:function Rectangle(w,h)this.width=w;this.height=h;Rtotype.area=function()return this.width*this.height;Function DerivedRectangle(x,y,w,h)

52、Rectangle.call(this,w,h);/this就是子类的一个实例对象,那么超类Rectangle成了这个实例对象的一个属性方法来调用,那么这个方法里的this就变成了当前的实例对象,显然里面的属性也成了这个实例对象的属性!This.x=x;This.y=y;DerivedRtotype=new Rectangle();Delete DerivedRtotype.width;Delete DerivedRtotype.height;DerivedRtotype.constructor=DerivedRectangle;DerivedRtotype

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论