您的位置:首页 > Web前端 > JavaScript

JavaScript--变量作用域、函数作用域及作用域链

2017-05-05 14:33 309 查看

JavaScript–变量作用域、函数作用域及作用域链

变量作用域

一个变量的作用域是代码中定义这个变量的区域。

全局变量拥有全局作用域,在js代码中任何地方都有定义

在函数内声明的变量只在函数体内有定义——局部变量,函数参数也是局部变量,只在函数体内有定义

在函数体内,局部变量的优先级高于同名的全局变量。

var scopr="global";//全局变量
function checkscope(){
var scope="local";//同名局部变量
return scope;//返回局部变量值而不是全局变量
}
checkscope();//local


函数作用域

JS没有类似C语言的块级作用域,使用函数作用域:变量在声明他们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

function test(o){
var i=0;//i在整个函数体内有定义
if(typeof o=="object"){
var j=0;//j在函数体内是有定义的,不仅仅是这个代码段内
for(var k=0;k<10;k++){ //k在函数体内是有定义的,不仅仅是这个循环内
console.log(k);//输出0-9
}
console.log(k);//输出10
}
console.log(j);//j已经定义了,但可能没有初始化
}


由于函数作用域的特点,js实现了声明提前:函数里声明的所有变量(但不涉及赋值),都提前至函数顶部。

如下例:

var scope="global";
function f(){
console.log(scope);//输出undefined,而不是global
var scope="local";//变量在这里初始化赋值。但变量本身在函数体内任何地方都有定义
console.log(scope);//输出local
}


相当于:

var scope="global";
function f(){
var scope;
console.log(scope);//输出undefined,而不是global
scope="local";//变量在这里初始化赋值。但变量本身在函数体内任何地方都有定义
console.log(scope);//输出local
}


声明函数和变量

声明变量,变量不能删除(delete),属性可以删除

变量的声明只有一种方式,那就是用var关键字声明,直接赋值不是一种声明方式。这仅仅是在全局对象上创建了新的属性(而不是变量)。

var a=10;//变量
b=10;//不是变量,是在全局对象上创建了新的属性(不会声明提前)
alert(delete b); // true
alert(window.b); // undefined


但是,在“eval”的上下文中,变量是可以删除的:

eval('var a = 10;');
alert(window.a); // 10
alert(delete a); // true
alert(window.a); // undefined


函数声明

函数的声明有三种方式

(1)function name( ){ }直接创建方式
(2)new Funtion构建函数创建
(3)给变量赋值匿名函数方法创建

function add(a,b){
return a+b;
}
var add=new Function("a", "b", "return a+b;");
var add = function(a,b){
return a+b;
}
add(4,5);


当变量名和函数名声明时相同,函数优先声明。

作用域链

将局部变量看作是自定义实现的对象的属性

每一段JS代码(全局代码或函数)都有一个与之关联的作用域链(scope chain)

这个作用域链是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量。当JS查找变量X的值的时候,它从链中的第一个对象开始查找,如果这个对象有名为x的属性,则直接使用该属性值,否则JS继续查找下一个对象,直至找完不存在X,抛出引用错误一场(ReferenceError)

在JS的最顶层代码中,作用域链就是一个全局对象组成

function add(a,b){
var sum = a + b;
return sum;
}
此时作用域链(Scope Chain)只有一级,就为Global Object

scope(add) -> Global Object(VO)


当调用这个函数的时候,它创建了一个新的对象来存储它的局部变量,将这个对象添加至保存的那个作用域链上。

add(1,2);
//此时作用域链就有2级了
scope(add) -> activation object(AO)-> Global Object(VO)


嵌套的函数体内,作用域链至少有3个对象

function add(a,b){
var sum = a + b;
function add2() {
var z = 30;
console.log(a + b + z);
};

add2()
}
add(3,4);
//此时scope -> add2.AO -> add.AO -> Global Object


此时这三个对象:

add2.AO = {
z : 30,
__parent__ : add.AO
}

add.AO = {
this:window,
arguments : [3,4],
a : 3,
b : 4,
add2 : <reference to function>,
__parent__ : <Global Object>
}

Global Object = {
this:window,
add: <reference to function>,
__parent__ : null
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: