我在Javascript中阅读范围链但它对我没有任何意义,任何人都可以告诉我什么是范围链以及它如何与图形或甚至白痴能够理解的东西一起工作。我用谷歌搜索,但我找不到可理解的东西:(
提前致谢。
答案 0 :(得分:57)
要了解范围链,您必须了解闭包的工作原理。
当你嵌套函数时会形成一个闭包,即使在它们的父函数已经执行之后,内部函数也可以引用它们的外部封闭函数中存在的变量。
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
}());
}());
}());
推荐读物:
答案 1 :(得分:17)
ECMAScript中的任何函数调用(JS所基于的核心语言)都会生成一个单独的执行上下文,它们彼此独立运行。在每个执行上下文中,this
引用有问题的对象,默认为附加到函数的任何内容。
function foo() {
alert(this===window)
}
警告是真的,因为窗口是拥有'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
标识符未在同一上下文中定义,因此它必须沿作用域链向上移动到定义name的外部函数,并且它会警告全局。
参考:
答案 2 :(得分:5)
这是关闭。您可以在内部范围中使用范围外部的变量:
function get_inner_scope () {
var outer = 'Outer variable value';
return function () {
alert(outer);
}
}
f = get_inner_scope();
f(); // alerts Outer variable value
通过第一个谷歌链接获取更多与其他样本相关的信息: http://blogs.msdn.com/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx
答案 3 :(得分:5)
我知道这是一篇旧帖子,但对开发人员来说仍然有用。我想做一些不同的方式,因为初学者更容易理解范围链。这是我修改过的代码版本:
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();
答案 4 :(得分:3)
Scope chain in Javascript explained in layman terms
亚历克斯是一个快乐的人,有一个美好的一天,他手里拿着月薪走在路上被抢劫。 后来他意识到明天是支付他女儿1000美元学费的最后一天 他跑回家,发现他的积蓄为400美元,担心其余的(600美元)。眼前闪过的想法是从他父亲马修那里借一些。 这个可怜的木匠Mathew没有任何钱卖掉他继承的手镯300美元并借给他的儿子亚历克斯。 回到Javascript中的范围链:
Alex-A函数在javascript中
Mathew-即时功能,Alex嵌套在。
Mathews父母 - Mathew的直接功能嵌套在。
银行全局变量。
let myURL = NSURL(string: SERVER_URL);
let request = NSMutableURLRequest(URL:myURL!);
request.HTTPMethod = "POST";
let postString = ""
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{
data, response, error in
if error != nil {
print("error=\(error)")
return
}
dispatch_async(dispatch_get_main_queue(),{
var json = JSON(data: data!)
let someInt = json["someInt"].int
let message = json["message"].stringValue
此时Alex的范围链看起来像: [节约:400] + [马修:300] + [贷款:300];
答案 5 :(得分:1)
作用域链用于解析javascript中变量名的值。如果没有作用域链,那么如果在不同作用域中定义了多个变量,那么Javascript引擎将不知道为某个变量名选择哪个值。 javascript中的作用域链是按词法定义的,这意味着我们可以通过查看代码来了解作用域链。
作用域链的顶部是全局作用域,它是浏览器中的window
对象(global
中的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
中。这将创建一个 closure ,它基本上是外部环境范围链的快照。
然后,在执行功能时,功能需要变量foo
和bar
的值。可以在innerTestFunc
级别解析foo的值,并且两者均为10。在innerFoo
中已经找到10个,因此无需爬到foo的作用域链。
对于bar
变量,函数无法在innerFoo
中找到它。因此,它将爬上范围链。它首先在函数bar
中遇到变量test
,因此它将bar
的值解析为测试函数中的值(在我们的示例中为5、20)。