来源:http://www.blogjava.net/zkjbeyond,作者:
zkjbeyond
一、javascript进阶之变量篇
仔细的看了看<javascript权威指南>,算笔记吧
1、关于变量的声名
大家都知道javascript是可以隐式声名变量的。但要注意,隐式声名变量总是被创建为全局变量。看以下代码,情愿javascript语言强制声明变量。建议大家一定要var声明变量。
2、关于变量的作用域
猜猜以下代码输出什么。
如果你的答案是 000 undefined bbb aaa。恭喜,ok.当代码用到x变量时,先从函数块(权威指南中用调用对象来解释)中找,如果找不到,从上一级函数块找,直到找到,如果知道顶层代码 (指var x='000';的位置)还没找到定义,代码会报未定义错误。
改一下代码,得到 000 undefined 111 111
3、新的问题
变量个作用域清楚了,注意上面的代码。为什么我的function a()定义以前就可以调用a函数了,而我的var x='111';前“不可以用”x啊???
让我把我的理解一一道来
首先:以下代码让我相信javascript有个预编译过程,不是完全按照顺序解释执行的。
个人理解这个预编译过程不会象java/c#那样把代码编译成虚拟机认识的语言,更不会象vb,vc那样编译成更底层的语言。猜想只是把这个函数 预装载到这段函数执行的全局环境中,在这个执行环境中,该函数被标识定义过,可以直接使用了。(看到网上很多人写的AOP的javascript实现,其 实这个预编译过程才是翻译元数据最佳时候,可惜就javascript语言来讲,是有些落伍了)
这个文章主要讲变量的一些问题。变量说了,为什么函数可以,我变量就不可以呢。
为什么我要输出undefined呢?为什么我a就不可以预编译一把呢?
大家看看以下两段代码会输出什么呢啊???
可能你运行试了,可能你本来就知道,a未定义。哈哈哈,好了。
现在我确信var a=0;被javascript解释器“预编译过”,至少是记录下来了。甚至把它的值设置为 undefined。“undefined”这个词名字取的很是让人误解,怎么能叫未定义呢,分明是javascript中所有变量的初始化值。关于 null与undefined的比较我实在不愿提了。
注意上面两段代码还反映一个现象。隐式声明的变量是在解释的时候才把自己定义为全局变量的。
关于函数与变量javascript预编译的不同处理,大家可以与java class的加载过程比较下。java也是对基本类型设出值,对象为null的。(不往远扯了)
4、区别未定义变量和未附值变量
未定义变量和未附值变量 权威指南中文版 定义的。通过第三条分析,我觉得变量就应该以 定义和未定义变量区别。未附值变量和undefined有点冲突,javascript不是强类型语言,没发附默认值,才来了个undefined。
5、基本类型和引用类型
熟悉java的朋友可能这部分很清楚。没啥
说头。
6、javascript的垃圾回收
关于这部分内容一直没见着个权威说法。在javascript权威指南中有两小节提到这个问题。
对于字符串、对象、数据这些没有固定大小,必须为它们动态的分配内存,但什么时候回收这些内存呢?javascript使用和java一样的garbage collection的方法。
运行这段代码后,"hello"没有变量会再用到他,这是"hello"的存储空间的被垃圾回收了。对于javascript的垃圾回收,你唯一要关心的是,它一定会进行,不要对内存担心。
注意,javascript不提供任何的强制垃圾回收或释放内存的运算附或语句。
javascript的delete运算附和C++中的不同。
7、作为属性的变量
猜猜以下代码会输出什么。
估计很多人能得出正确答案
100 100 300 400
------------------------
200 200 300 400
但这里我想引入 全局对象和调用对象的 概念(javascript权威指南是这么翻译滴)
在函数的调用过程中,假设有个调用对象存在,把函数的参数,和函数内的临时变量当成这个调用对象的属性。当然这个调用对象的生命周期很短。
注意,当我们访问全局变量的属性入x的时候,不必要用this.x 或window.x访问,当在有<frame><iframe>的页面时会出现混淆。
关于函数的详细讨论我后续会详细讨论。
二、 javascript进阶之函数篇
在javascript中,function作为一个关键字有两方面的应用。
a、可以定义函数。
b、可以定义一个数据类型。这里只介绍函数。关于function定义类的功能在对象中介绍。
1、函数的概念
javascript中提供了许多预定义函数,我们可以直接使用,比如Math.sin();eval()等。
我们也可以定义自己的函数。有以下四种方法:
在这,如果用add(2,3);调用,返回的结果都是5。但它们使用有很大的区别,后面在详细解释。
2、函数的参数
回想上一篇提到函数的调用对象。虽然我们不能访问它,看不见,但引入这个概念确实可以方便我们解释很多东西。
在一个函数体内,标识符arguments有特殊含义。它是调用对象的一个特殊属性。
看例子,基本你可以把arguments当成个数组使用,但并不是真正的数组。
虽然arguments.length and arguments[index]可以在函数内改变,但建议你不要在函数内改变它们。关于arguments的具体用法可以看prototype.js.
arguments还有个属性 callee.引用当前正在执行的函数。
3、函数是一种数据类型
在javascript中,函数不但能象java一样当成语言的语法特性,还可以象字符串、数字、日期一样当成一种数据。
var add=function(x,y){return x+y;};其实我们函数的定义都是把函数附值给变量。函数不但可以附值给变量,还可以当成参数传递。
其实javascript的熟手不会在全局变量里(直接在js文件中)定义函数,都会定义在全局变量的属性字段中。如
如果这种写法,我们就基本不会和别人写的程序发生命名上的冲突了。
4、函数的生命周期
在变量里我们知道函数有个预编译过程,这个过程我们也看到不到,另外函数定义不同写法情况也不同。所以,感觉函数的执行过程很是复杂。
a、javascript预编译过程(在html中, </head>前后,<body>内外有特殊情况,这指纯.js文件中)
javascript的预编译我认为是个很简单的过程,对于解释执行语言,肯定不会编译成什么中间语言。(我认为)过程如下:
首先,为执行环境(一个html也,框架环境下有几个执行环境)建立建立一个全局对象,一般客户端脚本为 window或global对象。(在这我觉得global好理解,因为浏览器会放入window总其他的属性)
然后,检查某环境中根代码块中(非函数或{}中)var关键字,把这些变量设置成global对象的属性,并附初值undefined.
如果过程中遇到直接定义的函数(fun1的定义),那么把fun1设置成global对象的属性,并附初值函数的定义(你可以把函数当成undefined,true,1,'1'等数据类型)。
b、解释执行过程
代码按照顺序执行,
一般我们把全局变量的俯值放到代码最前面,如var s="hello"; 那么把s的值用 'hello'替换预编译过程的undefined。
如果遇到变量的应用,如代码 document.writeln(a),如果我们在global找到属性a,看a是否在前面代码俯值过,如果没有,a的值为预编译的undefined。如果是隐式变量声明,在这把它添加到global的属性中去。
如果遇到类似var fun=function(){}; 把函数当成数据赋值给变量fun.
c、函数的调用过程
你运行一下以下代码,为什么结果是 test undefined local
首先:预编译代码,把s、fun设置为golbe的属性,并赋值s=undefined,fun=函数定义(可以直接调用)。
然后:按照顺序解释执行代码。赋值s="golbe"; 函数已经可以直接调用了。
执行函数:当运行到fun("test")时,开始函数调用。
(1)先为本次调用建立一个调用对象(fun-global)。
(2)预编译函数体内代码,把参数设置为fun-global的属性,值为为传 值"test",查找var,把a设置成fun-global的属性,值为undefined.(如果var s与参数名称相同,则不重复设置例如函数体内var s="local"
(3)按照顺序执行函数内代码,当代码中遇到变量,先从调用对象属性中查找,如果找到直接使用。遇到var s="local";时,代码会覆盖调用对象中属性值(和参数名称相同)
调用对象是个暂时对象,生命周期很短,只有在调用过程中存在,递归可能会建立多个独立的调用对象。
javascript的函数应该和java中一样是线程安全的吧。
5、函数的属性和方法
a、length
看了以下代码一目了然,函数的length代表函数实际需要的参数个数。
b、prototype
这个属性引用的是预定义的原型对象,只有在new 函数名 才有效。讲解对象时介绍。
c、定义自己的函数属性
d、apply() call()方法
去读读prototype.js吧。
一、javascript进阶之变量篇
仔细的看了看<javascript权威指南>,算笔记吧
1、关于变量的声名
大家都知道javascript是可以隐式声名变量的。但要注意,隐式声名变量总是被创建为全局变量。看以下代码,情愿javascript语言强制声明变量。建议大家一定要var声明变量。
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> function test ( ) { var a= 222; document. writeln (a ); } test ( ); document. writeln (a ); </SCRIPT> |
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> function test ( ) { a= 222; document. writeln (a ); } test ( ); document. writeln (a ); </SCRIPT> |
猜猜以下代码输出什么。
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> var x= '000'; document. writeln (x ); a ( ); function a ( ) { var x= 'aaa'; function b ( ) { document. writeln (x ); var x= 'bbb'; document. writeln (x ); } b ( ); document. writeln (x ); } </SCRIPT> |
如果你的答案是 000 undefined bbb aaa。恭喜,ok.当代码用到x变量时,先从函数块(权威指南中用调用对象来解释)中找,如果找不到,从上一级函数块找,直到找到,如果知道顶层代码 (指var x='000';的位置)还没找到定义,代码会报未定义错误。
改一下代码,得到 000 undefined 111 111
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> var x= '000'; document. writeln (x ); a ( ); function a ( ) { function b ( ) { document. writeln (x ); document. writeln (x ); } document. writeln (x ); var x= '111'; b ( ); } </SCRIPT> |
3、新的问题
变量个作用域清楚了,注意上面的代码。为什么我的function a()定义以前就可以调用a函数了,而我的var x='111';前“不可以用”x啊???
让我把我的理解一一道来
首先:以下代码让我相信javascript有个预编译过程,不是完全按照顺序解释执行的。
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> a ( ); function a ( ) { alert ( ); } </SCRIPT> |
个人理解这个预编译过程不会象java/c#那样把代码编译成虚拟机认识的语言,更不会象vb,vc那样编译成更底层的语言。猜想只是把这个函数 预装载到这段函数执行的全局环境中,在这个执行环境中,该函数被标识定义过,可以直接使用了。(看到网上很多人写的AOP的javascript实现,其 实这个预编译过程才是翻译元数据最佳时候,可惜就javascript语言来讲,是有些落伍了)
这个文章主要讲变量的一些问题。变量说了,为什么函数可以,我变量就不可以呢。
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> document. writeln (a ); var a= 0; </SCRIPT> |
为什么我要输出undefined呢?为什么我a就不可以预编译一把呢?
大家看看以下两段代码会输出什么呢啊???
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> document. writeln (a ); a= 0; </SCRIPT> |
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> document. writeln (a ); </SCRIPT> |
可能你运行试了,可能你本来就知道,a未定义。哈哈哈,好了。
现在我确信var a=0;被javascript解释器“预编译过”,至少是记录下来了。甚至把它的值设置为 undefined。“undefined”这个词名字取的很是让人误解,怎么能叫未定义呢,分明是javascript中所有变量的初始化值。关于 null与undefined的比较我实在不愿提了。
注意上面两段代码还反映一个现象。隐式声明的变量是在解释的时候才把自己定义为全局变量的。
关于函数与变量javascript预编译的不同处理,大家可以与java class的加载过程比较下。java也是对基本类型设出值,对象为null的。(不往远扯了)
4、区别未定义变量和未附值变量
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> var a; document. writeln (a ); </SCRIPT> |
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> document. writeln (a ); </SCRIPT> |
未定义变量和未附值变量 权威指南中文版 定义的。通过第三条分析,我觉得变量就应该以 定义和未定义变量区别。未附值变量和undefined有点冲突,javascript不是强类型语言,没发附默认值,才来了个undefined。
5、基本类型和引用类型
熟悉java的朋友可能这部分很清楚。没啥
说头。
6、javascript的垃圾回收
关于这部分内容一直没见着个权威说法。在javascript权威指南中有两小节提到这个问题。
对于字符串、对象、数据这些没有固定大小,必须为它们动态的分配内存,但什么时候回收这些内存呢?javascript使用和java一样的garbage collection的方法。
javascript代码: |
var s="hello"; var u=s. toUpperCase ( ); s=u; |
运行这段代码后,"hello"没有变量会再用到他,这是"hello"的存储空间的被垃圾回收了。对于javascript的垃圾回收,你唯一要关心的是,它一定会进行,不要对内存担心。
注意,javascript不提供任何的强制垃圾回收或释放内存的运算附或语句。
javascript的delete运算附和C++中的不同。
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> var o= new Object ( ); o. name="zkj"; o. age= 25; o. bir= new Date ( ); for (var key in o ) { document. writeln (key+ ':'+o [key ]+ '</br>' ); } document. writeln ( 'delete o.bir</br>' ); delete o. bir; for (var key in o ) { document. writeln (key+ ':'+o [key ]+ '</br>' ); } </SCRIPT> |
7、作为属性的变量
猜猜以下代码会输出什么。
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> var x= 100; document. writeln (x ); add (x ); document. writeln ( '</br>------------------------</br>' ); var x= 200; document. writeln (x ); add (x ); function add (x ) { document. writeln (x ); var x= 300; document. writeln (x ); var x= 400; document. writeln (x ); } </SCRIPT> |
估计很多人能得出正确答案
100 100 300 400
------------------------
200 200 300 400
但这里我想引入 全局对象和调用对象的 概念(javascript权威指南是这么翻译滴)
javascript代码: |
<SCRIPT LANGUAGE="JavaScript"> var x= 100; //我们在全局对象中加了个属性x. 对比 //var o=new Object();o.x=100; document. writeln (this. x ); //用this访问全局对象 add (this. x ); //把全局对象的属性值传递对函数中 document. writeln ( '</br>------------------------</br>' ); this. x= 200; //把全局变量中的x属性修改掉 document. writeln (window. x ); add (window. x ); function add (x ) { //假设有个局部对象,调用对象,函数调用过程中的对象 // temp temp.x=${传入的值} document. writeln (x ); //这打印的可是参数中的值,也就是temp.x=this.x //的值, var x= 300; //把调用对象变量的签名给覆盖了. document. writeln (x ); //打印修改过的值。 temp.x var x= 400; //temp.x=400 document. writeln (x ); } </SCRIPT> |
在函数的调用过程中,假设有个调用对象存在,把函数的参数,和函数内的临时变量当成这个调用对象的属性。当然这个调用对象的生命周期很短。
注意,当我们访问全局变量的属性入x的时候,不必要用this.x 或window.x访问,当在有<frame><iframe>的页面时会出现混淆。
关于函数的详细讨论我后续会详细讨论。
二、 javascript进阶之函数篇
在javascript中,function作为一个关键字有两方面的应用。
a、可以定义函数。
b、可以定义一个数据类型。这里只介绍函数。关于function定义类的功能在对象中介绍。
1、函数的概念
javascript中提供了许多预定义函数,我们可以直接使用,比如Math.sin();eval()等。
我们也可以定义自己的函数。有以下四种方法:
javascript代码: |
a、function add (x,y ) { return x+y; } b、var add = function (x,y ) { return x+y; } c、var add = new Function ("x","y"," return x+y;" ); d、var add =function a (x,y ) { return x+y; } |
在这,如果用add(2,3);调用,返回的结果都是5。但它们使用有很大的区别,后面在详细解释。
2、函数的参数
回想上一篇提到函数的调用对象。虽然我们不能访问它,看不见,但引入这个概念确实可以方便我们解释很多东西。
在一个函数体内,标识符arguments有特殊含义。它是调用对象的一个特殊属性。
javascript代码: |
<SCRIPT LANGUAGE = "JavaScript"> function add (x,y ) { document. writeln ( 'x = ' + x ); document. writeln ( 'y = ' + y ); document. writeln ( 'arguments[ 0 ] = ' + arguments [ 0 ] ); document. writeln ( 'arguments[ 1 ] = ' + arguments [ 1 ] ); arguments [ 0 ] = 11 ; document. writeln ( 'arguments[ 0 ] = ' + arguments [ 0 ] ); return x + y; } document. writeln (add ( 2 , 3 ) ); </SCRIPT> |
看例子,基本你可以把arguments当成个数组使用,但并不是真正的数组。
虽然arguments.length and arguments[index]可以在函数内改变,但建议你不要在函数内改变它们。关于arguments的具体用法可以看prototype.js.
arguments还有个属性 callee.引用当前正在执行的函数。
javascript代码: |
<SCRIPT LANGUAGE = "JavaScript"> function add (x,y ) { document. writeln (arguments. callee ); document. writeln ( typeof (arguments. callee ) ); return x + y; } document. writeln (add ); document. writeln ( typeof (add ) ); document. writeln ( ' </ br >-----------------------</ br > ' ); add ( ); </SCRIPT> |
3、函数是一种数据类型
在javascript中,函数不但能象java一样当成语言的语法特性,还可以象字符串、数字、日期一样当成一种数据。
var add=function(x,y){return x+y;};其实我们函数的定义都是把函数附值给变量。函数不但可以附值给变量,还可以当成参数传递。
javascript代码: |
<SCRIPT LANGUAGE = "JavaScript"> var add = function (x,y ) { return x + y; } ; var fun = add; function opetate (fun,x,y ) { return fun (x,y ); } alert (opetate (fun, 2 , 3 ) ); </SCRIPT> |
其实javascript的熟手不会在全局变量里(直接在js文件中)定义函数,都会定义在全局变量的属性字段中。如
javascript代码: |
<SCRIPT LANGUAGE = "JavaScript"> var MyLib = { } ; MyLib. fun1 = function ( ) { } ; MyLib. fun2 = function ( ) { } ; alert (MyLib ); alert (MyLib. fun1 ); </SCRIPT> |
如果这种写法,我们就基本不会和别人写的程序发生命名上的冲突了。
4、函数的生命周期
在变量里我们知道函数有个预编译过程,这个过程我们也看到不到,另外函数定义不同写法情况也不同。所以,感觉函数的执行过程很是复杂。
javascript代码: |
<SCRIPT LANGUAGE = "JavaScript"> fun1 ( ); alert (fun1 ); // ///把以下代码放到定义最后面可以执行。 fun2 ( ); alert (fun2 ) fun3 ( ); alert (fun3 ) // / function fun1 ( ) {document. writeln ( 'fun1 run ! ' ) } var fun2 = function ( ) {document. writeln ( 'fun2 run ! ' ) } ; var fun3 = new Function ( " document. writeln ( 'fun3 run!' ) " ); </SCRIPT> |
a、javascript预编译过程(在html中, </head>前后,<body>内外有特殊情况,这指纯.js文件中)
javascript的预编译我认为是个很简单的过程,对于解释执行语言,肯定不会编译成什么中间语言。(我认为)过程如下:
首先,为执行环境(一个html也,框架环境下有几个执行环境)建立建立一个全局对象,一般客户端脚本为 window或global对象。(在这我觉得global好理解,因为浏览器会放入window总其他的属性)
然后,检查某环境中根代码块中(非函数或{}中)var关键字,把这些变量设置成global对象的属性,并附初值undefined.
如果过程中遇到直接定义的函数(fun1的定义),那么把fun1设置成global对象的属性,并附初值函数的定义(你可以把函数当成undefined,true,1,'1'等数据类型)。
b、解释执行过程
代码按照顺序执行,
一般我们把全局变量的俯值放到代码最前面,如var s="hello"; 那么把s的值用 'hello'替换预编译过程的undefined。
如果遇到变量的应用,如代码 document.writeln(a),如果我们在global找到属性a,看a是否在前面代码俯值过,如果没有,a的值为预编译的undefined。如果是隐式变量声明,在这把它添加到global的属性中去。
如果遇到类似var fun=function(){}; 把函数当成数据赋值给变量fun.
c、函数的调用过程
你运行一下以下代码,为什么结果是 test undefined local
javascript代码: |
<SCRIPT LANGUAGE = "JavaScript"> var s = " golbe " ; function fun (s ) { document. writeln (s ); document. writeln (a ); var s = " local " ; var a = "" ; return s; } document. writeln (fun ( " test " ) ); </SCRIPT> |
首先:预编译代码,把s、fun设置为golbe的属性,并赋值s=undefined,fun=函数定义(可以直接调用)。
然后:按照顺序解释执行代码。赋值s="golbe"; 函数已经可以直接调用了。
执行函数:当运行到fun("test")时,开始函数调用。
(1)先为本次调用建立一个调用对象(fun-global)。
(2)预编译函数体内代码,把参数设置为fun-global的属性,值为为传 值"test",查找var,把a设置成fun-global的属性,值为undefined.(如果var s与参数名称相同,则不重复设置例如函数体内var s="local"

(3)按照顺序执行函数内代码,当代码中遇到变量,先从调用对象属性中查找,如果找到直接使用。遇到var s="local";时,代码会覆盖调用对象中属性值(和参数名称相同)
调用对象是个暂时对象,生命周期很短,只有在调用过程中存在,递归可能会建立多个独立的调用对象。
javascript的函数应该和java中一样是线程安全的吧。
5、函数的属性和方法
a、length
看了以下代码一目了然,函数的length代表函数实际需要的参数个数。
javascript代码: |
<SCRIPT LANGUAGE = "JavaScript"> function add (x,y ) { var actual = arguments. length; var expected = arguments. callee. length; if (actual != expected ) { throw new Error ( '函数需要' + expected + '个参数,你输入了' + actual + '个' ); } return x + y; } alert (add ( 3 , 2 ) ); alert (add ( 3 , 2 , 3 ) ); </SCRIPT> |
b、prototype
这个属性引用的是预定义的原型对象,只有在new 函数名 才有效。讲解对象时介绍。
c、定义自己的函数属性
javascript代码: |
<SCRIPT LANGUAGE = "JavaScript"> add. count = 0 ; function add (x,y ) { add. count ++ ; return x + y; } add ( 3 , 2 ); add ( 3 , 2 ); add ( 3 , 2 ); add ( 3 , 2 ); document. writeln ( '共调用函数几次:' + add. count ); </SCRIPT> |
d、apply() call()方法
去读读prototype.js吧。