Javascript 验证我对范围链的理解
(问题1) 在Flanagan的JS权威指南中,他定义了Javascript 验证我对范围链的理解,javascript,scope-chain,Javascript,Scope Chain,(问题1) 在Flanagan的JS权威指南中,他定义了函数方法bind(),以防它不可用(在ECMAScript 3中不可用) 看起来是这样的: function bind(f, o) { if (f.bind) return f.bind(o); // Use the bind method, if there is one else return function() { // Otherwise, bind it like this
函数
方法bind()
,以防它不可用(在ECMAScript 3中不可用)
看起来是这样的:
function bind(f, o) {
if (f.bind) return f.bind(o); // Use the bind method, if there is one
else return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
他用一个例子来说明它的用法(我已经修改了这个例子,将第三行从f.bind(o)
)改为:
当我第一次看到这一点时,我想“arguments不是指我们正在定义的bind函数中的arguments变量吗?但是我们想要最终应用它的函数的arguments属性,就像上面例子中的g一样…”
我验证了他的示例是否确实有效,并推测在上面的var g=bind(f,o)
之前,不会对行return f.apply(o,arguments)
求值。也就是说,我想,当你返回一个函数时,你只是返回该函数的源代码,不是吗?直到它被评估?因此,我尝试了一个稍微不同的bind版本来测试这个理论:
function mybind2(f, o) {
var arguments = 6;
return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
如果它只是返回未赋值的函数源,那么在以后求值时它不可能存储arguments=6
,对吗?经过检查,我仍然得到了g(2)
=>3。但是后来我意识到——如果它只是返回未赋值的代码,那么returnf.apply(o,arguments)
中的o
是如何传递的
所以我决定必须发生的是:
o
和arguments
变量(即使arguments
等于6)也会传递给函数。只是当函数g
最终被调用时,arguments
变量被解释器重新定义为g
(在g(2)
中)的参数,因此我试图传递的参数的原始值被替换。但这意味着在此之前它是以文本形式存储函数的,因为否则o
和arguments
将只是程序中的数据,而不是可以覆盖的变量。这个解释正确吗
(问题2)在同一页的前面,他定义了以下函数,该函数使用apply
方法跟踪函数以进行调试:
function trace(o, m) {
var original = o[m]; // Remember original method in the closure.
o[m] = function() { // Now define the new method.
console.log(new Date(), "Entering:", m); // Log message.
var result = original.apply(this, arguments); // Invoke original.
console.log(new Date(), "Exiting:", m); // Log message.
return result; // Return result.
};
}
这里的this
不是指我们正在定义的函数,而不是对象o
?还是这两件事是一回事?问题1
对于您的第一个问题,让我们简化示例,以便清楚地了解正在执行的操作:
function bind(func, thisArg) {
return function () {
return func.apply(thisArg, arguments);
};
}
这里发生的事情是创建一个闭包,允许访问原始函数和传递的this
的值。返回的匿名函数将保持原始函数在其作用域中,其结果如下所示:
var func = function () {};
var thisArg = {};
func.apply(thisArg, [/*arguments*/]);
关于参数
的问题,该变量在创建的所有函数的作用域中都是隐式定义的,因此内部参数
将覆盖外部参数
,使其按预期工作
问题2
你的问题在于你对this
的后期绑定的误解——对于那些习惯于使用同样有自己的this
关键字的面向对象语言的人来说,这是关于JavaScript最令人困惑的事情之一。this
的值仅在调用时设置,调用该值的位置定义了调用该值时的this
的值。它只不过是调用函数时父对象所在位置的值,此值被覆盖的情况除外
例如,请参见以下内容:
function a() {return this;};
a(); // global object;
var b = {};
b.a = a;
b.a(); // object b
如果定义函数时设置了此
,则调用b.a
将生成全局对象,而不是b
对象。让我们也来简化给定的第二个函数:
function trace(obj, property) {
var method = obj[property]; // Remember original method in the closure.
obj[property] = function () { // Now define the new method.
console.log(1); // Log message.
// Invoke original method and return its result
return original.apply(this, arguments);
};
}
在这种情况下,原始方法存储在闭包中。分配给方法最初所在的对象不会覆盖方法
对象。与普通的方法赋值一样,这个
值的原理仍然是一样的——它将返回父对象,而不是您定义的函数。如果你做一个简单的作业:
var obj = {};
obj.foo = function () { return this; };
obj.foo(); // obj
它执行预期的操作,在调用时返回父对象。在这方面,将代码放在嵌套函数中没有任何区别
一些好资源
如果你想了解更多关于用JavaScript编写代码的知识,我强烈建议你看看Cody Lindley的文章——它详细介绍了这个关键字在不同上下文中的行为以及你可以使用它做的事情。问题1
对于您的第一个问题,让我们简化示例,以便清楚地了解正在执行的操作:
function bind(func, thisArg) {
return function () {
return func.apply(thisArg, arguments);
};
}
这里发生的事情是创建一个闭包,允许访问原始函数和传递的this
的值。返回的匿名函数将保持原始函数在其作用域中,其结果如下所示:
var func = function () {};
var thisArg = {};
func.apply(thisArg, [/*arguments*/]);
关于参数
的问题,该变量在创建的所有函数的作用域中都是隐式定义的,因此内部参数
将覆盖外部参数
,使其按预期工作
问题2
你的问题在于你对this
的后期绑定的误解——对于那些习惯于使用同样有自己的this
关键字的面向对象语言的人来说,这是关于JavaScript最令人困惑的事情之一。this
的值仅在调用时设置,调用该值的位置定义了调用该值时的this
的值。它只是调用函数时父对象所在位置的值,但o除外
var arguments = 42;
function foo() {
console.log(arguments);
}
foo(1, 2);