为什么' this '指向闭包中的全局对象?
why does `this` refer to the global object in closure
var num = 1;
var obj = {
num: 2,
getNum: function() {
return (function() {
return this.num;
})();
}
}
console.log(obj.getNum()); // 1
JavaScript代码的结果是1。所以this
指的是全局对象,而不是obj。
在其他条件相同的情况下,当直接在函数中使用时,当以obj.method()
的典型方式调用该函数时,this
指向作为方法(成员)的对象。Directly的意思是直接;在方法内嵌套的函数中使用,无论是匿名的还是立即调用的还是其他方式,都不符合的条件。
在你的情况下
return (function() {
return this.num;
})();
函数不是任何对象的成员,因此没有this
,因此this
是全局对象(或严格模式下为null)。
仅仅因为你使用this
的函数嵌套在一个函数中,这个函数是一个方法,所以不够。使用this
的函数必须是方法本身。
要得到你想要的行为,你有几个选择:
getNum: function() {
return (() => this.num)();
}
这可以工作,因为胖箭头函数使用词法this
。
另一个想法,已经在另一个答案中显示了:
getNum: function() {
var self = this;
return function() {
return self.num;
}();
}
顺便说一下,在这个上下文中,没有必要将函数用圆括号括起来,强制它成为一个可以立即调用的函数表达式。仅仅因为它在:
的右边,它就已经是一个表达式了。
还有第三种方法:
getNum: function() {
return function() {
return this.num;
}.call(this);
}
通过显式地使用call
,我们将匿名函数的this
强制为getNum
的this
。
要获得明确的答案,请参阅"如何"。关键字工作?。
关于术语"闭包"的说明
在你的问题中,你似乎使用术语"闭包"来表示"嵌套函数"。虽然您的嵌套的、匿名的、立即调用的函数在某种极其狭窄的技术意义上可能是闭包,但是以这种方式使用术语可能会混淆您自己和其他人。您的函数不满足以下两个被普遍接受的闭包标准中的任何一个:
它不会"关闭"(使用)周围作用域中的任何变量。
它不会作为一个函数值返回给外部世界,同时还会从周围的词法作用域携带对这些变量的引用。
因此,简单地将此函数称为"嵌套函数"会更清楚。
在函数内部this
取决于执行上下文,因此如何调用函数很重要。
如果调用上下文没有设置this
,在严格模式和非严格模式下是不同的。
在非严格模式下,它引用全局对象。在严格模式下,为undefined
。注意,undefined
实际上可以设置为其他值。
要设置上述上下文,需要将function作为对象的属性调用,就像在obj.getNum()调用中一样。In将给函数一个对象作用域,但它与您尝试实际访问this
的另一个函数调用没有任何关系。
下面的代码说明了它:
var num = 1;
var obj = {
num: 2,
getNum: function() {
var outerThis = this;
return (function() {
return {
innerThis: this,
outerThis: outerThis,
innerNum: this.num,
outerNum: outerThis.num
};
})();
},
getNumStrict:function() {
"use strict"
var outerThis = this;
return (function() {
return {
innerThis: this,
outerThis: outerThis,
outerNum: outerThis.num
};
})(outerThis.num);
}
}
console.log(obj.getNum());
// Object {innerThis: Window, outerThis: Object, innerNum: 1, outerNum: 2}
console.log(obj.getNumStrict());
// Object {innerThis: undefined, outerThis: Object, outerNum: 2}
你可以看到,this
在JavaScript中是一个有争议的概念,你可以很容易地没有它。
要使私有属性私有,可以在函数作用域中创建它们,并返回一个返回接口副本的函数,而不是对象引用:
var num = 1;
var createHaveNum = function(initial) {
var num = initial;
var getInterface;
var setNum = function(x) {
num = x;
console.log("setting num");
};
var getNum = function() {
console.log("getting num");
return num;
};
getInterface = function() {
return {
getNum: getNum,
setNum: setNum
};
};
console.log("Instance is initialized.");
return getInterface;
};
var obj = createHaveNum(2); // create an object, obtain a reference in form of a function
var i = obj(); // obtain an interface
var j = obj(); // do it again, interface to same object
j.setNum = undefined; // does not break internal state, object is intact
console.log(i.getNum());
i.setNum(3);
var getNum = i.getNum; // reference function
console.log(getNum()); // invoke without a scope, no problem
var other = {getNum: i.getNum}; // put in another object
console.log(other.getNum()); // call with another context, no problem - same scope as before.
/*
Instance is initialized.
getting num
2
setting num
getting num
3
getting num
3
*/
因为在定义对象文字时obj
不存在,所以不能关闭它。最重要的是,闭包在作用域上操作,在函数之外没有作用域。
在计算字面量时,没有obj
。在对该语句求值时,首先求对象字面值(必须先求=
操作符的右操作数),然后赋值给新声明的变量obj
。
更糟糕的是,ES中的闭包是在作用域中的,而ES5(及以下版本)只有函数作用域。除了全局作用域,没有外部作用域可以关闭。
要获得"期望"的结果,您必须重新定义getName
,如下所示:
getNum: function() {
var that = this; //the enclosing object
return (function() {
return that['num'];
})();
}
- 全局变量和全局对象的属性之间有什么区别吗
- javascript无法重新定义函数内部的全局对象
- Javascript,从静态函数中打印全局对象
- 为什么“this”指的是全局对象
- Do let语句在全局对象上创建属性
- underscore.js,名为“”的全局对象;出口;和livefyre javascript API-集成冲突
- 为什么“this”指的是对象“obj”而不是全局对象
- 从函数调用全局对象的方法
- 谷歌分析的全局对象
- AngularJS:避免使用“angular”全局对象
- Javascript Web Worker 修改全局对象
- 想要在回调中更新对象,给出正确的日志,但全局对象未更新
- 让函数中的接收器默认为全局对象背后的基本原理是什么?
- 蜘蛛猴:如何删除全局对象
- 为什么函数在全局对象中不可用
- 访问请求会在全局对象中生成
- 全局对象问题
- React Native 中全局对象的模式
- Expressjs - 全局对象
- 是否可以在 Javascript 中更改或删除全局对象的属性