以下是一个带有公共和私有方法的简单Javascript类的示例(小提琴:http://jsfiddle.net/gY4mh/)。
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction();
}
}
ex = new Example;
ex.publicFunction();
从公共部门调用私有函数会导致“this”成为窗口对象。我应该如何确保使用类上下文而不是窗口调用我的私有方法?这会不合适吗?
答案 0 :(得分:8)
使用闭包。基本上,在函数中声明的任何变量仍然可用于该函数内的函数:
var Example = (function() {
function Example() {
var self = this; // variable in function Example
function privateFunction() {
// The variable self is available to this function even after Example returns.
console.log(self);
}
self.publicFunction = function() {
privateFunction();
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
答案 1 :(得分:3)
另一种方法是使用" apply"明确设置方法"这个"应该受到约束。
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.apply(foo, null);
// => foo
另一种方法是使用" call":
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.call(foo, null);
// => foo
两者"申请"并且"打电话"拿你要绑定的对象"这个"作为第一个参数和一个参数数组传递给您调用的方法作为第二个arg。
答案 2 :(得分:3)
值得了解除了让别人告诉你代码修复之外,如何确定javascript中this
的值。在javascript中,this
通过以下方式确定:
如果您通过object.method()
中的对象属性调用函数,则this
将设置为方法内的对象。
如果直接调用函数而没有任何对象引用(例如function()
),则this
将设置为全局对象(浏览器中的window
)或严格模式,它将设置为undefined
。
如果使用new
运算符创建新对象,则将调用该对象的构造函数,并将this
的值设置为新创建的对象实例。您可以将此视为与上面的第1项相同,创建对象,然后调用其上的构造函数方法。
如果您使用.call()
中的.apply()
或function.call(xxx)
调用函数,那么您可以通过您传递的参数确切地确定this
设置的内容到.call()
或.apply()
。您可以在MDN上详细了解.call()
here和.apply()
here。
如果使用function.bind(xxx)
,则会创建一个小的存根函数,以确保使用所需的this
值调用函数。在内部,这可能只是使用.apply()
,但它是一个快捷方式,当你想要一个回调函数时,它被调用时具有正确的值this
(当你不是直接调用者的时候)功能)。
在回调函数中,回调函数的调用者负责确定this
的所需值。例如,在事件处理程序回调函数中,浏览器通常将this
设置为处理事件的DOM对象。
对这些不同的方法here on MDN进行了很好的总结。
因此,在您的情况下,当您致电privateFunction()
时,您正在进行正常的函数调用。因此,正如预期的那样,this
的值设置为上面的选项2中。
如果你想在你的方法中明确地将它设置为this
的当前值,那么你可以这样做:
var Example = (function() {
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction.call(this);
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
当您不是函数的调用者并因此不能使用1-4时,其他方法(如使用闭包和定义的var that = this
)最适用于回调函数的情况。在您的特定情况下,没有理由这样做。我会说使用.call()
是一种更好的做法。然后,您的函数实际上可以使用this
,并且可以表现为私有方法,这似乎是您寻求的行为。
答案 3 :(得分:2)
我想最常用的方法就是将缓存(存储)this
的值放在本地上下文变量中
function Example() {
var that = this;
// ...
function privateFunction() {
console.log(that);
}
this.publicFunction = function() {
privateFunction();
}
}
更方便的方法是调用Function.prototype.bind
将上下文绑定到函数(永远)。但是,这里唯一的限制是,这需要一个支持ES5的浏览器,并且绑定功能稍慢。
var privateFunction = function() {
console.log(this);
}.bind(this);
答案 4 :(得分:1)
我想说正确的方法是使用原型,因为它毕竟是Javascript的设计方式。所以:
var Example = function(){
this.prop = 'whatever';
}
Example.prototype.fn_1 = function(){
console.log(this.prop);
return this
}
Example.prototype.fn_2 = function(){
this.prop = 'not whatever';
return this
}
var e = new Example();
e.fn_1() //whatever
e.fn_2().fn_1() //not whatever
这是一个小提琴http://jsfiddle.net/BFm2V/
答案 5 :(得分:0)
如果您不使用EcmaScript5,我建议您使用Underscore(或LoDash)bind功能。
答案 6 :(得分:0)
除了这里给出的其他答案之外,如果您没有ES5就绪的浏览器,您可以使用以下代码创建自己的“永久绑定功能”:
function boundFn(thisobj, fn) {
return function() {
fn.apply(thisobj, arguments);
};
}
然后像这样使用它:
var Example = (function() {
function Example() {
var privateFunction = boundFn(this, function() {
// "this" inside here is the same "this" that was passed to boundFn.
console.log(this);
});
this.publicFunction = function() {
privateFunction();
}
}
return Example;
}()); // I prefer this order of parentheses
Voilà - this
神奇地是外在语境this
而不是内在语境!
如果您的浏览器中缺少类似ES5的功能,您甚至可以获得类似ES5的功能(如果您已经拥有它,则无效):
if (!Function.prototype.bind) {
Function.prototype.bind = function (thisobj) {
var that = this;
return function() {
that.apply(thisobj, arguments);
};
}:
}
然后以完全相同的方式使用var yourFunction = function() {}.bind(thisobj);
。
可以在mozilla Function.prototype.bind找到完全符合(尽可能),检查参数类型等类似ES5的代码。如果您正在使用函数执行一些不同的高级操作,那么可能会有一些差异,如果您想要使用这些路径,请在链接上阅读。
答案 7 :(得分:0)
我想说将self
分配给this
是一种常用技巧:
function Example() {
var self = this;
function privateFunction() {
console.log(self);
}
self.publicFunction = function() {
privateFunction();
};
}
使用apply
(正如其他人所建议的那样)也有效,但我认为它有点复杂。
这可能超出了这个问题的范围,但我还建议您考虑使用不同的JavaScript方法,而实际上根本不使用this
关键字。我在ThoughtWorks的一位前同事Pete Hodgson写了a really helpful article, Class-less JavaScript,解释了一种方法。