javascript javascript对象变量在匿名函数中变为未定义

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21769460/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 21:38:59  来源:igfitidea点击:

javascript object variable becomes undefined inside anonymous function

javascriptundefinedanonymous-function

提问by kelibra

So I can't quite figure out why the variable this.tasksbecomes undefined inside of the add event listener I have inside of my goal object. I have a feeling it might have something to do with asynchronous programming(which I still don't fully understand). Sorry I'm a bit of a JS noob, but if you guys could explain to me what I'm doing wrong and what might be a better solution that would be awesome! Thanks.

所以我不太明白为什么变量this.tasks在我的目标对象中的 add 事件侦听器中变为 undefined 。我有一种感觉它可能与异步编程有关(我仍然不完全理解)。抱歉,我是个 JS 菜鸟,但如果你们能向我解释我做错了什么,以及什么可能是更好的解决方案,那就太棒了!谢谢。

function Goal(name) {
        this.gDiv =  document.createElement('div');
        this.name = name || "goal";
        this.tasks = document.createElement('ul');
        //Sets the styling and content and adds it to the parent element
        this.initialize = function() {
            this.gDiv.className = "default";
            this.gDiv.setAttribute("id", this.name);
            this.gDiv.innerHTML = this.name;
            elem.appendChild(this.gDiv);

            this.gDiv.parentNode.insertBefore(this.tasks, this.gDiv.nextSibling);
            this.tasks.style.display = "none";


        };  
        //Creates a list underneath the a dive associated with the Goal object
        this.addTask = function(task) {
            var newLi = document.createElement('li');
                newLi.innerHTML = task;
                this.tasks.appendChild(newLi);
        };

        this.gDiv.addEventListener('click', function(){
            alert(this.tasks);              
        });

    }

Thank you guys! You all answered my question! I'd been scratching my head at this for a while. Kudos to you all!

感谢你们!你们都回答了我的问题!我一直在挠头一段时间。向你们所有人致敬!

回答by Misha Nasledov

The scope changes when you enter that anonymous closure and 'this' changes. You can hack around it by doing

当您输入匿名闭包并且“this”发生变化时,范围会发生变化。你可以通过做来破解它

var self = this;

And then using self in place of this (eg):

然后使用 self 代替这个(例如):

function Goal(name) {
    var self = this;

    /* ... */

    this.gDiv.addEventListener('click', function(){
        alert(self.tasks);              
    });

If you're using jQuery you could do something nicer:

如果您使用 jQuery,您可以做一些更好的事情:

this.gDiv.addEventListener('click', $.proxy(function() {
    alert(this.tasks);
 }, this));

Either way works just fine.

无论哪种方式都可以正常工作。

EDIT: In ES6, arrow functions can be used instead as they don't bind their own "this", so it becomes even simpler:

编辑:在 ES6 中,可以使用箭头函数代替,因为它们不绑定自己的“this”,所以它变得更加简单:

this.gDiv.addEventListener('click', () => {
    alert(this.tasks);
 });

回答by Xotic750

Here is a comparison of some methods (including your problem), to give you a taster, and to try and explain things a little.

这是一些方法的比较(包括您的问题),给您一个品尝者,并尝试解释一些事情。

// This is the problem that you have,
// where `this` inside the anonymous function
// is a different scope to it's parent
function Test1(something) {
  // `this` here refers to Test1's scope
  this.something = something;
  setTimeout(function() {
    // `this` here refers to the anonymous function's scope
    // `this.something` is `undefined` here
    console.log(this.something);
  }, 1000);
};

new Test1('Hello');

// This solution captures the parent `this` as `test2This`,
// which can then be used inside the anonymous function
function Test2(something) {
  var test2This = this;

  this.something = something;
  setTimeout(function() {
    console.log(test2This.something);
  }, 1000);
}

new Test2('World');

// This solution captures `this` as `test3This` in an `IIFE closure`
// which can then be used in the anonymous function
// but is not available outside of the `IIFE closure` scope
function Test3(something) {
  this.something = something;
  (function(test3This) {
    setTimeout(function() {
      console.log(test3This.something);
    }, 1000);
  }(this));
}

new Test3('Goodbye');

// This method requires that you load an external library: jQuery
// and then use it's `$.proxy` method to achieve the basics of 
// Test3 but instead of being referred to as `test3This` the
// outer scope `this` becomes the inner scope `this`
// Ahh, that's much clearer?
function Test4(something) {
  this.something = something;
  setTimeout($.proxy(function() {
    console.log(this.something);
  }, this), 1000);
}

new Test4('Mum');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

// This is approximately what jQuery's `$.proxy` does
// but without having to load the whole library
function Test5(something) {
  this.something = something;
  setTimeout((function(func, context) {
    return function() {
      func.call(context);
    };
  }(function() {
    console.log(this.something);
  }, this)), 1000);
}

new Test5('Dad');

// Lets create the proxy method as a reuseable
function proxy(func, context) {
  var args = Array.prototype.slice.call(arguments, 2);

  return function() {
    return func.apply(
      context, 
      args.concat(Array.prototype.slice.call(arguments))
    );
  };
}

// and now using it
function Test6(something) {
  this.something = something;
  setTimeout(proxy(function() {
    console.log(this.something);
  }, this), 1000);
}

new Test6('Me want cookies');

Then we have Function#bind

然后我们有函数#bind

function Test7(something) {
  this.something = something;
  setTimeout(function() {
    // `this` was bound to the parent's `this` using bind
    console.log(this.something);
  }.bind(this), 1000);
};

new Test7('Num num');
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js"></script>

And most recently ES2015 Arrow functions

以及最近的ES2015 箭头函数

function Test8(something) {
  this.something = something;
  setTimeout(() => console.log(this.something), 1000);
};

new Test8('Whoop');

回答by Jon F.

In ES6, arrow functions were introduced, which do not bind their own this.

在 ES6 中,引入了箭头函数,它们不绑定自己的 this。

MDN for reference.

MDN 供参考

So creating an anonymous function using the arrow syntax is probably the easiest way to overcome this issue nowadays. It is supported by all major browsers currently, except IE.

因此,使用箭头语法创建匿名函数可能是当今解决此问题的最简单方法。目前除 IE 外,所有主流浏览器都支持它。

回答by Tim Kachko

the keyword 'this' changes in it's meaning for an event handler against a constructor

关键字“this”改变了它对于构造函数的事件处理程序的含义

please refer to the MDN

请参考 MDN

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#As_a_DOM_event_handler

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#As_a_DOM_event_handler