JavaScript OOP 错误的 _this 值
JavaScript OOP wrong _this value
假设我们有以下代码:
var MyClass = (function(){
var _this;
function MyClass(inputVal){
_this = this;
this.value = inputVal;
}
MyClass.prototype.getValue = function(){
return this.value;
}
MyClass.prototype.getValue2 = function(){
return _this.value;
}
return MyClass;
})();
让我们创建两个实例 class:
var instance1 = new MyClass(10);
var instance2 = new MyClass(20);
现在如果我们 console.log() 我们看到的值:
instance1.getValue(); // 10
instance1.getValue2(); // 20
var MyClass = (function(){
var _this;
function MyClass(inputVal){
_this = this;
this.value = inputVal;
}
MyClass.prototype.getValue = function(){
return this.value;
}
MyClass.prototype.getValue2 = function(){
return _this.value;
}
return MyClass;
})();
var instance1 = new MyClass(10);
var instance2 = new MyClass(20);
console.log(instance1.getValue());
console.log(instance1.getValue2());
为什么会这样?看起来显然 _this
变量获取最新创建的实例属性。如何解决?我需要保留 this
的副本。谢谢!
编辑:
这是真实情况
var HoverEffects = (function(){
var _this;
function HoverEffects($nav){
_this = this;
this._$activeNav = $nav.siblings('.active_nav');
this._$hoverableLis = $nav.find('>li');
this._$activeLi = $nav.find('>li.active');
if(!$nav.length || !this._$hoverableLis.length || !this._$activeNav.length || !this._$activeLi.length) return;
if(this._$activeNav.hasClass('bottom')){
this._$activeNav.align = 'bottom';
this._$activeLi.cssDefault = {
left: this._$activeLi.position().left,
width: this._$activeLi.width()
};
}
else if(this._$activeNav.hasClass('left')){
this._$activeNav.align = 'left';
this._$activeLi.cssDefault = {
top: this._$activeLi.position().top,
height: this._$activeLi.height()
};
}
else{
return;
}
this._$hoverableLis.hover(
function(){
// How to set the correct this inside this function?
if(this._$activeNav.align === 'bottom'){
this._$activeNav.css({
left: $(this).position().left,
width: $(this).width()
});
}
else if(this._$activeNav.align === 'left'){
this._$activeNav.css({
top: $(this).position().top,
height: $(this).height()
});
}
},
function(){
// Same here, wrong this
this._$activeNav.css(this._$activeLi.cssDefault);
}
);
}
return HoverEffects;
})();
var sideNavHoverMagic = new HoverEffects($('#side-navigation'));
var primaryNavHoverMagic = new HoverEffects($('#primary-navigation'));
Why is that happening?
每次调用 new MyClass
,_this = this
都会得到 运行。第二次覆盖第一次。
因此 _this
指的是 new MyClass(20)
,这意味着当您从 any MyClass
实例调用 getValue2
时,20
将被返回,因为 all MyClass
个实例引用相同的 _this
值。
基于对问题的评论:
如果您试图传递绑定到适当上下文的函数,有多种方法可以确保 this
指向正确的对象。在继续之前,请阅读 "How does the 'this' keyword work?",因为我没有理由在这里重复所有内容。
如果您在构造函数中绑定事件回调:
function Example(something) {
something.addEventListener(..event.., this.callback, false);
}
Example.prototype.callback = function () {
this.doStuff();
this.doMoreStuff();
};
回调将有错误的 this
值,因为它没有被调用为 this.callback
,它只是被调用为:
fn = this.callback;
fn(); //no reference to this
您可以通过多种方式解决这个问题。
Function.prototype.bind
您可以在各自的实例上为每个实例绑定 callback
。这个很简洁:
function Example(something) {
//generate a new callback function for each instance that will
//always use its respective instance
this.callback = this.callback.bind(this);
something.addEventListener(..event.., this.callback, false);
}
Example.prototype.callback = function () {
this.doStuff();
this.doMoreStuff();
};
that = this
您可以在构造函数中创建回调(闭包)并在构造函数中引用变量。
function Example(something) {
//every Example object has its own internal "that" object
var that = this;
this.callback = function () {
//this function closes over "that"
//every instance will have its own function rather than
//a shared prototype function.
that.doStuff();
that.doMoreStuff();
}
something.addEventListener(..event.., this.callback, false);
}
() => {}
(Fat Arrow Syntax)
如果您使用的是 ES2015,则可以使用 "fat arrow" 语法来创建不创建新上下文的 lambda:
function Example(something) {
this.callback = () => {
//the callback function doesn't create a new "this" context
//so it referes to the "this" value from "Example"
//every instance will have its own function rather than
//a shared prototype function.
that.doStuff();
that.doMoreStuff();
}
something.addEventListener(..event.., this.callback, false);
}
假设我们有以下代码:
var MyClass = (function(){
var _this;
function MyClass(inputVal){
_this = this;
this.value = inputVal;
}
MyClass.prototype.getValue = function(){
return this.value;
}
MyClass.prototype.getValue2 = function(){
return _this.value;
}
return MyClass;
})();
让我们创建两个实例 class:
var instance1 = new MyClass(10);
var instance2 = new MyClass(20);
现在如果我们 console.log() 我们看到的值:
instance1.getValue(); // 10
instance1.getValue2(); // 20
var MyClass = (function(){
var _this;
function MyClass(inputVal){
_this = this;
this.value = inputVal;
}
MyClass.prototype.getValue = function(){
return this.value;
}
MyClass.prototype.getValue2 = function(){
return _this.value;
}
return MyClass;
})();
var instance1 = new MyClass(10);
var instance2 = new MyClass(20);
console.log(instance1.getValue());
console.log(instance1.getValue2());
为什么会这样?看起来显然 _this
变量获取最新创建的实例属性。如何解决?我需要保留 this
的副本。谢谢!
编辑:
这是真实情况
var HoverEffects = (function(){
var _this;
function HoverEffects($nav){
_this = this;
this._$activeNav = $nav.siblings('.active_nav');
this._$hoverableLis = $nav.find('>li');
this._$activeLi = $nav.find('>li.active');
if(!$nav.length || !this._$hoverableLis.length || !this._$activeNav.length || !this._$activeLi.length) return;
if(this._$activeNav.hasClass('bottom')){
this._$activeNav.align = 'bottom';
this._$activeLi.cssDefault = {
left: this._$activeLi.position().left,
width: this._$activeLi.width()
};
}
else if(this._$activeNav.hasClass('left')){
this._$activeNav.align = 'left';
this._$activeLi.cssDefault = {
top: this._$activeLi.position().top,
height: this._$activeLi.height()
};
}
else{
return;
}
this._$hoverableLis.hover(
function(){
// How to set the correct this inside this function?
if(this._$activeNav.align === 'bottom'){
this._$activeNav.css({
left: $(this).position().left,
width: $(this).width()
});
}
else if(this._$activeNav.align === 'left'){
this._$activeNav.css({
top: $(this).position().top,
height: $(this).height()
});
}
},
function(){
// Same here, wrong this
this._$activeNav.css(this._$activeLi.cssDefault);
}
);
}
return HoverEffects;
})();
var sideNavHoverMagic = new HoverEffects($('#side-navigation'));
var primaryNavHoverMagic = new HoverEffects($('#primary-navigation'));
Why is that happening?
每次调用 new MyClass
,_this = this
都会得到 运行。第二次覆盖第一次。
因此 _this
指的是 new MyClass(20)
,这意味着当您从 any MyClass
实例调用 getValue2
时,20
将被返回,因为 all MyClass
个实例引用相同的 _this
值。
基于对问题的评论:
如果您试图传递绑定到适当上下文的函数,有多种方法可以确保 this
指向正确的对象。在继续之前,请阅读 "How does the 'this' keyword work?",因为我没有理由在这里重复所有内容。
如果您在构造函数中绑定事件回调:
function Example(something) {
something.addEventListener(..event.., this.callback, false);
}
Example.prototype.callback = function () {
this.doStuff();
this.doMoreStuff();
};
回调将有错误的 this
值,因为它没有被调用为 this.callback
,它只是被调用为:
fn = this.callback;
fn(); //no reference to this
您可以通过多种方式解决这个问题。
Function.prototype.bind
您可以在各自的实例上为每个实例绑定 callback
。这个很简洁:
function Example(something) {
//generate a new callback function for each instance that will
//always use its respective instance
this.callback = this.callback.bind(this);
something.addEventListener(..event.., this.callback, false);
}
Example.prototype.callback = function () {
this.doStuff();
this.doMoreStuff();
};
that = this
您可以在构造函数中创建回调(闭包)并在构造函数中引用变量。
function Example(something) {
//every Example object has its own internal "that" object
var that = this;
this.callback = function () {
//this function closes over "that"
//every instance will have its own function rather than
//a shared prototype function.
that.doStuff();
that.doMoreStuff();
}
something.addEventListener(..event.., this.callback, false);
}
() => {}
(Fat Arrow Syntax)
如果您使用的是 ES2015,则可以使用 "fat arrow" 语法来创建不创建新上下文的 lambda:
function Example(something) {
this.callback = () => {
//the callback function doesn't create a new "this" context
//so it referes to the "this" value from "Example"
//every instance will have its own function rather than
//a shared prototype function.
that.doStuff();
that.doMoreStuff();
}
something.addEventListener(..event.., this.callback, false);
}