js深入理解之作用域链

语法分析,


分析3样东西


第1步: 先分析参数
第2步: 再分析变量声明
第3步: 分析函数声明


一个函数能使用的局部变量,就从上面的3步分析而来




具体步骤:


0: 函数运行前的1瞬间, 生成 Active Object (活动对象),下称AO
1: 
   1.1 函数声明的参数,形成AO的属性,值全是undefined,
   1.2 接收实参,形成AO相应的属性的值


2: 分析变量声明声明声明! 如 var age, 
   如果AO上还没有age属性,则添加AO属性,值是undefined
   如果AO上已经有age属性,则不做任何影响
   


3: 分析函数声明,如 function foo() {}, 
则把函数赋给AO.foo属性
注: 如果此前foo属性已存在,则被无情的覆盖了
*/






function t(age) {
    alert(age);
}


t(5); // 5
t();//   undefined
/*
词法分析过程:
AO {age:undefined}


运行过程:
t(5)--> AO.age=5; alert(AO.age); //5


t() ---> AO.age没得到赋值, 还是undefined
*/






function t2(age) {
    var age = 99;
    alert(age);
}


t2(5); 
/*
分析过程:


0: 形成AO = {}
1: 
   1.1 分析形参 AO = {age:undefined}
   1.2 接收形参 AO = {age:5}


2: 分析var age, 发现AO已有age属性,不做任何影响




执行过程:
AO.age = 99;
alert(age);
*/






function t3(greet) {
    var greet = 'hello'; // 试着把这一句变成 var greet;再做分析
    alert(greet);


    function greet() {
    }


    alert(greet);
}


t3(null);  // hello hello


/*
词法分析过程:
0: AO = {}
1: 
   1.1 分析参数 AO = {greet:undefined}
   1.2 分析参数 AO = {greet:null}
2: 分析greet变量声明,AO已经有greet属性,因此不做任何影响
3: 分析greet函数声明, AO.greet = function() {} , 被覆盖成函数




执行过程:
greet = 'hello';
alert(greet);
alert(greet);
*/




// 再看这道题


function a(b) {
   alert(b);
   function b(){
        alert (b);
    }
    b();
}


a(1);


/*


分析期:
0: AO = {}
1: 
   1.1分析参数 AO = {b:undefined}
   1.2接收参数  AO = {b:1}


2: 分析var 声明,此函数没有var


3: 分析函数声明, AO = {b: function(){alert(b);}}


执行期:
alert(b);  // function
b();       // 由作用域寻找到a函数中的b,即 function,alert()出来   


*/



function a(b) {
   alert(b);
   b = function (){
        alert (b);
   }
   
   b();
}


a(1);


/*
学员常见答案:
1,1
1, function
1, undefined
function ,function 
*/




/*
词法分析过程:
0: AO = {}
1: 分析参数 AO = {b:undefined} --> {b:1}
2: 分析var声明,没有.
3: 分析函数声明??  没有!


(注: b = function() {} ,是一个赋值过程,在执行期才有用)




执行过程:
alert(b); // 1
b = function() {
    alert(b);
}
b();  // function


*/




// 函数声明,与函数表达式
/*
JS被称为披着C外衣的Lisp语言, 
lisp是一种强大的函数式语言


函数可以赋值给变量,可以作为参数来传递.
*/


function t1() {
}


t2 = function() {
}


// 这2种方式,效果不同的,
// t1是函数声明, 虽然全局内也得到一个t1变量,值是function
// 而t2 只是一个赋值过程------值是谁? 值是右侧的表达式的返回结果,即函数






// 就是说 function () {} 在js看来,就和 3*2, 6/3 一样,是个表达式,返回一个结果


// 因此,t1 t2 两种方式在词法分析时,有着本质区别
// 前者 在词法分析阶段,就发挥作用
// 而后者,在运行阶段,才发挥作用






// 知道了函数表达式的概念,再看看一个你以前看不懂的东西
(function(window,undefined) {
})(window);


这是jquery的最外层代码


/*
(function(window,undefined){})  // 内层表达式,返回值是函数,包在小括号里,当成表达式来执行\
(function(window,undefined){})(window) // 立即调用


// 而内层函数又没有起名字,称为匿名函数,
// 这种手法,匿名函数,立即执行,不污染全局.   称为 立即执行匿名函数表达式


*/


// 思路: 为什么传window, 而又不会传undefined?
/*
答: 传window是为了速度


function() {
    function() {
        function () {
            function () {
                function () {
                    document.getElementById... // 这个document将会尚作用域层层上找,直到最外层
                }
            }
        }
    }
}




jquery就是为了加快内部查找变局变量的速度, 而直接把window以参数形式传进来
这样 window 就在jquery内部的 AO上






不传undefined是为了安全
因为在IE,FF低版本中 ,  undefined竟然可以重新赋值 ,如 undefined = 3;




声明undefined局部变量(名字是undefined而已), 同时,又不传参,值自然是undefined
防止了外界对undefined的污染


*/

function t1(){ var d function t2(){ d = 5; e=6; }t2();}t1();console.log(d); //d is not definedconsole.log(e); //6console.log(window.d);//undefined

//注意:变量以window.xxx引用,变量不存在,以某个属性不存在报的错  undefined
  // 变量以xxx引用的时候,寻找不到,则报的是 xxx is not undefined
//  var 仅仅是一个声明变量的操作,  d = 5 只是一个赋值操作





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值