我在 Javascript 中阅读范围链,但它对我没有任何意义,谁能告诉我什么是范围链以及它如何与图形一起工作,甚至是白痴也能理解的东西。我用谷歌搜索了它,但我没有找到可以理解的东西:(
6 回答
要了解作用域链,您必须了解闭包的工作原理。
当您嵌套函数时会形成一个闭包,即使在其父函数已经执行之后,内部函数也可以引用其外部封闭函数中存在的变量。
JavaScript 通过向上遍历作用域链,从本地移动到全局来解析特定上下文中的标识符。
考虑这个包含三个嵌套函数的示例:
var currentScope = 0; // global scope
(function () {
var currentScope = 1, one = 'scope1';
alert(currentScope);
(function () {
var currentScope = 2, two = 'scope2';
alert(currentScope);
(function () {
var currentScope = 3, three = 'scope3';
alert(currentScope);
alert(one + two + three); // climb up the scope chain to get one and two
}());
}());
}());
推荐阅读:
ECMAScript(JS 所基于的核心语言)中的任何函数调用都会产生一个单独的执行上下文,它们彼此单独运行。在每个执行上下文中,this
指的是有问题的对象,默认为函数所附加的任何内容。
function foo() {
alert(this===window)
}
会警告 true,因为窗口是拥有 'foo' 方法的对象。函数中定义的任何变量都可以通过该函数的唯一作用域链环境访问。
function world() {
var name = 'global';
alert(name)
}
显然会提醒“全球”。
function world() {
var name = 'global';
(function() {
var name = 'country';
alert(name)
})();
alert(name)
}
在最新示例中,当调用第一个警报时,Javascript 确定在内部函数的范围链中name
定义了标识符,因此它不必查找范围链来获取它。
在第二次警报调用中,name
也在相同的上下文中定义并警报“全局”;
function world() {
var name = 'global';
(function() { alert(name) })();
}
在此示例中,name
标识符未在同一上下文中定义,因此它必须沿作用域链向上移动到定义名称的外部函数,并警告全局。
参考:
我知道这是一篇旧文章,但它仍然对开发人员有帮助。我想用一点不同的方式来做这件事,因为它对初学者来说更容易理解范围链。这是我修改后的代码版本:
var currentScope = 0; // global scope
function a () {
var currentScope = 1, one = 'scope1';
alert(currentScope);
function b () {
var currentScope = 2, two = 'scope2';
alert(currentScope);
function c () {
var currentScope = 3, three = 'scope3';
alert(currentScope);
alert(one + two + three); // climb up the scope chain to get one and two
}
c();
}
b();
}
a();
这是关于关闭。您可以在内部范围内使用范围外的变量:
function get_inner_scope () {
var outer = 'Outer variable value';
return function () {
alert(outer);
}
}
f = get_inner_scope();
f(); // alerts Outer variable value
通过第一个 google 的链接获取更多关于其他示例的详细信息:http: //blogs.msdn.com/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx
亚历克斯是个快乐的人,在美好的一天,他拿着月薪走在路上被抢劫了。
后来他意识到明天是支付女儿 1000 美元学费的最后一天。
他跑回家,找到了 400 美元的积蓄,担心剩下的(600 美元)。瞬间闪过的念头,是向父亲马修借一些。
可怜的木匠马修(Mathew)身无分文,以 300 美元的价格卖掉了他继承的手镯,并借给了他的儿子亚历克斯。
亚历克斯在社会上有很好的声誉,立即从当地一家银行拿到了剩余的300美元,并按时支付了女儿的学费。
回到 Javascript 中的作用域链:
Alex-javascript 中的函数
Mathew-立即函数,Alex 嵌套在
其中。Mathews parents-立即函数 Mathew 嵌套在其中。Bank-
全局变量。
function Bank() {
loan=300;
Mathew();
function Mathew() {
mathew=300;
Alex();
function Alex() {
savings:400;
alert('I need some money');
}
}
}
Bank();
此时 Alex 的作用域链如下所示:[savings:400]+[mathew:300]+[loan:300];
概括:
作用域链用于解析 javascript 中变量名的值。如果没有范围链,如果在不同的范围内定义了多个,Javascript 引擎将不知道为某个变量名称选择哪个值。javascript中的作用域链是词法定义的,这意味着我们可以通过查看代码来了解作用域链是什么。
作用域链的顶部是全局作用域,它是window
浏览器中的对象(global
in NodeJS
)。除了全局范围之外,函数还有自己的变量范围。范围链可以通过查看函数的定义位置来确定。
解析变量时,内部函数首先查看自己的作用域。如果在自己的作用域中找不到变量,它将爬上作用域链并在定义函数的环境中查找变量名称。这看起来像这样:
因此,在我们的图像示例中,当innerFoo
使用变量时bar
,它首先尝试在 innerFoo 的范围内(函数体中的代码)找到它。然后,当它在这里找不到它时,它会爬上作用域链到foo
. 其中foo
也没有名为 的变量bar
。因此,它将爬上作用域链,现在查看全局作用域。在全局范围内是一个名为 bar 的变量,其值为 10,bar
将被解析为该变量。
例子:
let foo = 1;
let bar = 1;
function test (bar) {
return function innerTestFunc () {
let foo = 10;
console.log(foo, bar);
}
}
const innerTestFunc1 = test(5);
const innerTestFunc2 = test(20);
innerTestFunc1(); // logs 10, 5
innerTestFunc2(); // logs 10, 20
在上面的示例中,我们有一个返回函数的函数。我们首先将此函数存储在变量innerTestFunc1
和innerTestFunc2
中。这将创建一个闭包,它基本上是外部环境范围链的快照。
然后,当执行函数时,函数需要变量foo
和的值bar
。foo 的值可以在 the 的级别上解析,innerTestFunc
并且两者都是 10。10 已在 中找到innerFoo
,因此无需爬上 foo 的作用域链。
在bar
变量的情况下,函数无法在innerFoo
. 因此,它将爬上作用域链。它首先遇到bar
函数中的变量test
,因此它将值解析bar
为测试函数中的任何值(在我们的示例中为 5、20)。