理解JavaScript作用域

理解JavaScript作用域作用域也就是变量对象能被其他对象访问的作用范围主要包括以下几个概念:1、全局作用域与局部作用域2、静态作用域与动态作用域3、块级作用域4、作用域

大家好,欢迎来到IT知识分享网。

作用域也就是变量对象能被其他对象访问的作用范围


主要包括以下几个概念:

1、全局作用域(Global Scope)与局部作用域(Local Scope)

2、静态(词法)作用域(Lexical Scope)与动态作用域(Dynamic Scope)

3、块级作用域(Block Scope)

4、作用域链(Scope Chain)

理解JavaScript作用域

现在来具体举例说明下这几个区别:

1、全局作用域,指在全局的范围都能访问到。例如:

let a = 1;

(function foo() {

b = 2;

}())

window.c = 3;

console.log(a, b, c);

其中a,b,c能被全局访问到。a定义在当前全局环境,b没有关键词声明也是全局,c定义在window全局对象下。

2、局部作用域,也就是函数作用域,只有在函数内部才能访问到

var a = 1;

(function foo() {

var a = 2;

var b = 2;

}())

console.log(a, typeof b);

从外部能访问到a,但是外部的a,值为1,而b就是undefined。

理解JavaScript作用域

局部作用域能访问全局的作用域,子函数能访问父函数的作用域,但父函数不能访问子函数的作用域。如果要想外部访问内部作用域,那就得利用闭包了,相当于利用函数复制了一个封闭的空间出来,供外部调用。

3、词法作用域,也就是作用域在变量定义时决定,范围在所定义的位置,因为JS解析引擎在提取代码进行词法分析生成语法树时就决定了。动态作用域则是程序在运行阶段动态来确定变量的作用域范围,也就是从调用方来查找,而不是定义的环境。JS的call与apply,bind可以动态地改变执行上下文,可以改变变量的执行上下文this,相当于修改了对象作用域的范围,但不是修改作用域。

理解JavaScript作用域

var a = 1;

var a = 2;

function foo() {

console.log(a);

}

function change() {

var a = 3;

foo();

}

change();

变量a在定义时的作用范围内,所以打印仍是2,foo里面a作用范围在定义时的foo局部作用域内。如果是动态作用域则打印3。一般编程语言都是静态作用域,例如C、JavaPython、JS等,但如shell脚本或velocity模板语言是动态作用域。

4、块级作用域,也就是变量作用范围在一个块内,一般是花括号标识。大多数语言都是块级作用域域。JS直到ES6推出了后,通过let关键字声明的变量作用域在块内。

{

var a = 1;

let b = 1;

}

console.log(a, b);

这里a将打印1,b就会报错,因为变量未定义而调用。

for (var i = 0; i < 5; i++) {

setTimeout(function() {

console.log(i);

}, 0);

}

这里会打印5次5,因为没有块级作用域,后面的覆盖了前面的,这里一般要用闭包才能打印出1到5来。

for (let i = 0; i < 5; i++) {

setTimeout(function() {

console.log(i);

}, 0);

}

而如果换成let,则打印1到5,虽然同样是超时打印,这是因为变量的作用域不同。至于let与var的其他不同,以及var带来的变量提升等问题,就不在这里赘述了。

5、作用域链,JS的代码在执行时会针对执行代码块(global, function和eval)创建执行上下文(Execution Context, 包括this, variable object,[[scope]]等),执行上下文中的变量对象会从子函数(是一个执行上下文)逐级往上到父函数(也是一个执行上下文)中查找该变量,一直到全局。函数通过一个[[scope]]属性供其他的其他对象来链接查找。这里注意不要将变量逐级往上查找与变量作用域本身混淆。变量逐级查找是基于作用域链向上查找该变量,而变量作用域是该变量的作用范围,这个范围是声明时所在的位置。同时也不要跟this混淆(this表示对象本身,执行上下文也会创建一个this,用来代表这个执行环境,但并不等于这个上下文),函数的this可以看作是函数的指针,指向函数的调用方,它可以被动态修改。

var a = ‘a’;

function outer() {

var b = ‘b’;

function child(b) {

a = ‘1’;

b = ‘2’;

function inner() {

console.log(‘inner:’, ‘a=’ + a, ‘b=’ + b);

}

inner(b);

}

child(b);

console.log(‘outer:’, ‘a=’ + a, ‘b=’ + b);

}

outer();

输出:

inner: a=1 b=2

outer: a=1 b=b

inner结果原因:a变量在inner里面没有,向上查找child,child里没有,再向上找到outer,依然没有,直到最外层找到a。a在执行child()时被重新重新赋值为1。b是向上在child作用域中找中。

outer结果原因:a在outer作用域下没有,向上才找到a,但a在执行child()时已经被赋值为1了,b因为传递的是值而非引用,因此child()执行,b被修改时并非修改的outer下的b,而是child(b)形参定义的b变量。

理解JavaScript作用域


以上就把作用域说完了,很简单吧。好了,来一个例子,如果你能说清原理,那就说明理解了。


function foo(b) {

var a = b;

return {

a: a,

change: function(b) {

console.log(a, b, this.a);

a = b + this.a;

},

output: function() {

console.log(a, this.a, b);

}

}

}

var x = foo(1);

console.log(‘change before:’)

console.log(x.a); // 1;

x.output(); // 1, 1, 1

x.a = 3;

x.change(2); // 1, 2, 3

console.log(‘after change:’);

console.log(x.a); // 3

x.output(); // 5, 3, 1

关于这个答案讲解可以放在以后的章节中。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/52257.html

(0)
上一篇 2024-08-13 21:26
下一篇 2024-08-13 22:26

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信