代码改变世界

javscript变量作用域

2012-10-19 18:22  露珠的微笑  阅读(465)  评论(0)    收藏  举报

总算把这疑问解决啦。从入职到现在一直很困惑.看了司徒正美的博客才总算明白,以下摘抄来自司徒正美博客《javascript变量的作用域 》,个人观点文章分析得非常好:

像javascript这样的解释型语言,基本分为两个阶段,编译期(下面为符合大多数语言的称呼习惯,改叫预编译)与运行期。在预编译阶段,它是用函数来划分作用域,然后逐层为其以 var 声明的变量(下略称为var变量)函数定义开辟内存空间,再然后对var变量进行特殊处理,统统赋初始值为undefined

主要抓住一点:预编译为var变量与函数定义分配空间,有初值赋初值,没有的默认为Undefined,

                   然后按Js代码逐行执行

例子1:

var a=100;   
var b=true;   
function test(){   
    alert(a);//由于test函数用var声明了a,所以逐行执行时访问的是内围变量a,该内围变量还未赋值,js对末赋值的变量默认为undefined   
    alert(b);// 逐行执行到该行时,由于test函数作用域未用var声明b,所以js向外查看,外围有声明就用外围的b,外围若没声明就会报错:未定义b
b
=false; // 逐行执行到该行时,b的值被test作用改变了,所以此时b=true
alert(b);
var a=200; //内围变量a,逐行执行到这才赋值 alert(a/2); //访问已赋值的内围变量a } test();

执行结果为:undefined,true,false,100

分析:预编译为为var变量与函数定义分配空间,总共两个外围var变量a,b;一个内围变量a和一个函数,如下:

 详细参考:司徒正美博客《javascript变量的作用域 》:http://www.cnblogs.com/rubylouvre/archive/2009/08/21/1551270.html

 例子2:

Object.prototype.test = 'wrong'; 

var test = 'right'; 

(function f() { 

    alert(test); 

})();

例子3:

Object.test = "bbb";
Object.prototype.test = 'ccc';
window.test = "aaa";
(function f() {
    alert(test);
})();

估计有很多人猜是bbb,其实是ccc!有人就不解了,不是对象的属性的优先级比其原型属性的优先级高吗???

无错,的确如此,不过对象的属性是这样定义的:

var o = {test:"eee"}

Object.test = “XXX”这样定义,为类属性,或称静态属性。类属性优先级都是比实例属性低的

例子4

function foo(){ 
  foo.abc = function(){alert('def')} 
  this.abc = function(){alert('xyz')} 
  abc = function(){alert('@@@@@')}; 
  var abc = function(){alert('$$$$$$')} 
} 
foo.prototype.abc = function(){alert('456');} 
foo.abc = function(){alert('123');} 
var f = new foo(); 
f.abc(); 
foo.abc(); 
abc();

第一个为xyz,f.abc很明显就是调用其实例属性,通常构造函数是这样定义实例方法与实例属性的:

this.XXX = "XXXXXXXX"

第二个就是构造函数内部的foo.abc还是外部的foo.abc的问题了。我们只要搞清楚一点就可以,写在外面的那个是极晚绑定的成员,优先级极低,覆盖不了内部的同名成员。

第三个为什么会报错呢?!因为在预编译阶段,foo()的作用域就有了一个abc变量,因此abc = function(){alert('@@@@@')}就变不了window.abc = function(){alert('@@@@@')},而下面那一行就更甭提了。而我们调用的是abc,全局变量的abc,浏览器会自动给它加上window.abc,就算不加上,沿途的Objcet也没有abc这个变量,因此它在f()的作用域外找不到abc,就报未定义错误!

 

归纳:

JS引擎有两个设置变量的机会。第一次在预编译时期,所有var变量会分配到各自的作用域中,值一律为undefined。第二次在运行期,由于是逐行执行,因此是可变的