var num = 1;
var obj = {
num: 2,
getNum: function() {
return (function() {
return this.num;
})();
}
}
console.log(obj.getNum()); // 1
the JavaScript code's result is 1. So this
refers to global object rather than obj.
答案 0 :(得分:2)
在其他条件相同的情况下,this
在函数中直接使用 时指向函数为方法的对象(成员),当以obj.method()
的典型方式调用该函数时。直接意味着直接;在嵌套在方法中的函数中使用,无论是匿名的还是立即调用的,否则不符合条件。
在你的情况下
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);
}
我们通过明确使用this
强制匿名函数的this
为getNum
call
。
有关最终答案,请参阅How does the "this" keyword work?。
在你的问题中,你似乎正在使用术语"关闭"表示"嵌套功能"。虽然你的嵌套,匿名,立即调用的函数可能是一个非常狭隘的技术意义上的闭包,但使用这种术语可能会让你自己和其他人感到困惑。您的函数不满足以下两个通常接受的关闭条件:
它没有"关闭" (使用)来自周围范围的任何变量。
它不会作为一个带有它的函数值返回到外面的世界,而是从周围的词法范围引用这些变量。
因此,简单地将此函数称为"嵌套函数"会更清楚。
答案 1 :(得分:0)
函数this
内部取决于执行上下文,因此调用函数非常重要。
如果调用上下文未设置this
,则在严格和非严格模式下会有所不同。
在非严格模式下,它指的是全局对象。
在严格模式下,其undefined
。请注意,undefined
实际上可以设置为其他内容。
要设置所述上下文,您需要将函数作为对象的属性调用,如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
*/
答案 2 :(得分:-1)
Because obj
does not exist when the object literal is defined, so it can't be closed over. On top of that, closure operates on the scope, and you don't have a scope outside the function.
At the moment the literal is being evaluated, there is no obj
. When evaluating that statement, the object literal is evaluated first (the right-hand operand to the =
operator must be evaluated first), then assigned to the newly-declared variable obj
.
To make matters worse, closure in ES is on the scope and ES5 (and below) only have function-scope. You don't have an outer scope to close over, besides the global scope.
答案 3 :(得分:-1)
To get the "desired" result, you'd have to redefine getName
as below:
getNum: function() {
var that = this; //the enclosing object
return (function() {
return that['num'];
})();
}