我的问题是......在TestObj中的CallMeLaterTestObj函数中,“this”是窗口对象而不是TestObj。我如何重构这个,以便在CallMeLater函数中我不必将调用function() { v.CallMeLaterTestObj(); }
包装在一个闭包中或使用绑定函数,因为它对新浏览器的支持有限。两个目标:
为每个单独的对象维护“value”的单独值,使它们不共享相同的值。
//模拟公共api,私有方法,私有变量,公共字段。
//问题的新部分
重写以包含绑定功能和原型表示法。如何将Binding函数移动到所有新对象都可以获得的基础对象中?
这是我能够最好地利用这两个世界中最好的东西。我不知道这种方法的缺陷是什么
var BaseObject = function ()
{
_getBinding = function (method)
{
var _self = this;
return function ()
{
_self[method].apply(_self, arguments);
};
};
return {
CallInline: _getBinding
}
}();
var TestObj = function (value)
{
$.extend(this, BaseObject);
// public var
this._value = value;
};
TestObj.prototype = function()
{
var privateVar = false;
// these are private
_giveMe = function () {
return this._value;
},
_callMeLaterTestObj = function () {
console.log('I am ' + this.constructor.name + ' my value is ' + this._value);
};
// public API
return {
GiveMe : _giveMe,
CallMeLaterTestObj : _callMeLaterTestObj
}
}();
function CallMeLater(v, i)
{
setTimeout(v.CallInline('CallMeLaterTestObj'), 10);
}
var V1 = new TestObj(1);
var V2 = new TestObj(2);
var V3 = new TestObj(3);
console.log('V1= ' + V1.GiveMe());
console.log('V2= ' + V2.GiveMe());
console.log('V3= ' + V3.GiveMe());
console.log('---');
V1.CallMeLaterTestObj();
console.log('---');
答案 0 :(得分:1)
bind
method,以便它也可以在旧版浏览器中使用。
另一种方法是将闭包移动到原型方法中,如果你知道你总是需要绑定实际的函数:
TestObj.prototype.getCallMeLaterTestObj = function () {
var that = this;
return function() {
console.log('I am ' + that.constructor.name + ' my value is ' + that._value);
};
};
setTimeout(v.getCallMeLaterTestObj(), 10);
顺便说一句,您的原型没有constructor
属性,因此日志将无法按预期工作。
您唯一的机会是完全避免使用this
keyword:
TestObj = function() {
var privateVar = false; // these are private static
function TestObj(value) {
function giveMe() {
return value;
}
function callMeLaterTestObj() {
console.log('I am TestObj my value is ' + giveMe());
}
this._value = value;
this.giveMe = giveMe;
this.callMeLaterTestObj = callMeLaterTestObj;
/* you could do this as well:
return {
_value: value,
giveMe: giveMe,
callMeLaterTestObj: callMeLaterTestObj
}; */
}
return TestObj;
})();
var v = new TestObj;
setTimeout(v.callMeLater, 10);
但这不是很节省内存,因为它根本不使用原型继承。
答案 1 :(得分:1)
我认为您正在寻找的是:
function TestObj(value) {
var _value = value;
this.giveMe = function() {
return _value;
};
this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};
return this;
};
function callMeLater(v, i) {
setTimeout(function() {
v.callMeLaterTestObj();
}, 10);
}
var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);
console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');
callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);
要访问constructor.name,您需要使用function name()
语法声明该函数,而不是var name = function()
语法。
要保留私有变量并公开公共API,请将公共变量公开为函数中this
的属性。
请务必从构造函数返回this
以使其正常工作。
遵循CamelCase的命名约定(其中TestObj是一个)和lowerCamelCase的变量/方法/对象/等也是一个好习惯。有助于清楚哪些变量是实例,哪些是类
Test and see the console output expected here
注意强>
关于在setTimeout的闭包中包装v.callMeLaterTestObj()
,这种技术完全兼容跨浏览器。你不会有任何问题。
bind
方法较新,尽管有许多库会在旧版浏览器中为您提供内容。我个人最喜欢的是underscore。
注2
你不能在setTimeout中调用对象的方法而不将其包装在某个闭包中,但是如果你愿意,你可以在不使用泛型bind
函数的情况下抽象类中的闭包(由提供者提供) Underscore或jQuery和其他人)你可以像这样在类中“自己动手”:
function TestObj(value) {
var _value = value;
var _self = this;
this.giveMe = function() {
return _value;
};
this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};
this.getBinding = function(method) {
var _self = this;
return function() {
_self[method].apply(_self, arguments);
};
};
return this;
};
function callMeLater(v, i) {
setTimeout(v.getBinding('callMeLaterTestObj'), 10);
}
var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);
console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');
callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);
<强>解释强>
您需要使用某些类型的绑定,因为当您将方法传递给setTimeout
时,您可以通过引用传递它。所以所有setTimeout看到的都是一个函数 - 而不是它所在的对象,这就是你失去this
的上下文的原因。
因为setTimeout因此会在默认范围内执行函数 - 即浏览器窗口 - 你需要一种方法通过引用,通过内联匿名函数或通过返回一个使用的闭包来返回this
要{重置'apply
的{{1}}方法。
注3
如果您想拥有自己的绑定方法,并且不包含为您提供它的库或将其包含在每个类中,那么您可以使用Underscore中的这个,这与新浏览器中的本机方法一致:
this
然后像这样使用它:
function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};
这适用于所有浏览器。