1.js变量的查找
js中函数嵌套是十分普遍的
对变量是如何寻找的?------->从内部向外部寻找
首先在函数内寻找
找不到就在外层找
直到全局(window)区域
源码例子
var c=5;
function t1(){
var d=6;
function t2(){
var e=7;
//var d=3; 去掉注释观察结果的变化
alert(c+d+e);
}
t2();
}
t1();//分别得到15,18
2.声明变量var的作用
alert(window.d);//undefine
alert(window.e);//undefine
function t(){
d=5;
var e=6;
}
t();
alert(window.d);//5 没有加var就是仅仅是赋值操作,寻找t域内的函数,没有找到,继续寻找。。。。>window-->window.d=5
alert(window.e);//undefine
//var 是在函数运行的上下文中,申明一个变量 如果不加var,则是一个赋值操作,不要狭隘理解为创造了一个全局变量
function t1(){
var d;
function t2(){
d=5;
e=6;
}
t2();
}
t1();
console.log(d);//d is not defined错误
console.log(e);//6
console.log(window.d);//undefine
//注意:以window.xxx引用全局变量,寻找不到作为某个属性不存在,返回 undefined 直接以xxx引用某变量寻找不到则是报 xxx is not define 错误
例题
var str1='global';
function t1(){
console.log(str1);//返回global
console.log(str2);//报str2 is not defined
str2='local';//做了window.str2='local'这样一个操作
}
t1();
//在t1寻找str1---没有,在window上寻找str1---有 打印global
//在t1寻找str2---没有,在window上寻找str2---没有,报str2 is not defined
//(实际上出错还没有执行到这一些)才把全局的str2的变量赋值上去
var str1='global';
function t1(){
console.log(str1);//返回global
console.log(str2);//返回undefined
var str2='local';
}
t1();
js代码自上而下执行
但是js代码在整体运行分为 词法分析期 ,运行期
自上而下执行之前,先有个词法分析过程
------------------------------------------------例如---------------------------------------------------------------
第一步:先分析t1函数
分析出t1内有str2局部变量,注意此时代码未运行str2未赋值,所以str2的值是undefined
第二步:执行t1函数
console.log(str1);//返回global
console.log(str2);//返回undefined
str2='local'//此时str2的值为local
3.词法分析
词法分析
第一步:分析参数
第二部:分析变量声明
第三步:分析函数声明
一个函数能使用的全局变量,就是按照上面的三个步骤分析而来的
具体步骤:
0:函数运行前的瞬间,生成active object(活动对象),下面简称为ao
1:函数声明的参数形成ao的属性,参数的值就是属性的值,接收实参,形成ao相应属性的值
2:分析变量的声明
如果ao没有有age属性则添加为ao属性,值全是undefined
如果ao上已经有age属性,则不做任何影响
3:分析函数申明,如function foo(){}
把函数赋给ao.foo属性
注:如果此时foo属性已经存在,则被无情覆盖
实例1
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
*/
实例2
function t2(age){
var age=99;
alert(age);
}
t2(5);
/*
分析过程:
0:形成ao={}
1:分析形参ao={age:undefined}
接收形参ao={age:5}
2:分析var age,发现ao已经有age属性,不做任何影响
执行过程:
ao.age=99;
alert(age);
*/
实例3
function t3(greet){
var greet='hello';//试着变成var greet试一下
alert(greet);
function greet(){
}
alert(greet);
}
t3(null);//hello hello
/*
词法分析过程:
0:ao={}
1:分析参数ao={greet:undefined}
接收形参ao={greet:null}
2:分析greet变量声明,ao已经有greet 属性,因此不做任何影响
3:分析greet函数声明,ao.greet=function(){},被覆盖为函数
执行过程:
greet='hello';
alert(greet);//---------->hello
alert(greet);//---------->hello
*/
实例4
function a(b){
alert(b);
function b(){
alert(b);
}
b();
}
a(1);
/*
分析:
0:ao={}
1:分析参数ao= {b:undefined}
接收参数ao={b:1}
2:分析var 声明,此函数没有var
3:分析函数声明,ao={b:function{alert(b);}}
执行:
alert(b);
*/
实例6
function a(b){
alert(b);
b=function(){
alert(b);
}
b();
}
a(1);
/*
分析:
0:生成ao对象ao={}
1:分析参数ao={b:undefined}-->{b:1}
2:分析var声明--->没有
3:分析函数声明,--->没有,b=function(){}是一个赋值过程,是函数表达式返回值赋给变量b,这是一个赋值过程,要在执行过程中生效
执行:
alert(b);//1
b=function(){
alert(b);
}
b();//function
*/
4.函数声明和函数表达式
js被称为披着c外衣的lisp语言,
lisp是一种强大的函数式语言
函数的地位比较高,函数可以作为参数来传递,可以复制给变量
function t1(){}//t1是函数声明
t2=function(){}//t2是函数赋值过程,值是右侧表达式的返回结果
//function(){}在js看来就是3+2一样,是一个表达式,返回一个结果
//因此,t1 t2 在词法分析过程有着明显的区别,前者在词法分析阶段就发挥作用,后者在运行阶段才发挥作用
(function (window.undefined){})(window);
//这是jquery的最外层代码
(function(window.undefined))//内层表达式,返回值是函数,包在小括号内,当成表达式来使用
(window)//立即调用,并传一个window
//而内层函数没有起名字,叫匿名函数,这种方法好处: 立即执行不污染全局,称为 立即执行匿名函数表达式
//为什么传window不传undefined?
//传window是为了速度,加快内部查找全局变量的速度,直接把window以参数形式传进来,这样window就在jquery内部的ao上
function(){
function(){
function(){
function{
function(){
document.getElementById()//这个document会将作用域层层上找,直到最外层
}
}
}
}
}
//不传undefined是为了安全,在ie低版本张,undefined竟然可以重新赋值,如undefined=3
//声明undefined局部变量(名字是undefined而已),同时又不传参,值自热是undefined,阻止了外界对undefined的污染
5.作用域链
JavaScript 开发进阶:理解 JavaScript 作用域和作用域链
Js作用域与作用域链详解