这个 JavaScript 成语的基础是什么:var self = this?

What underlies this JavaScript idiom: var self = this?

提问人:Thomas L Holaday 提问时间:6/7/2009 最后编辑:DanManThomas L Holaday 更新时间:11/1/2019 访问量:173548

问:

我在 WebKit HTML 5 SQL Storage Notes 演示的源代码中看到了以下内容:

function Note() {
  var self = this;

  var note = document.createElement('div');
  note.className = 'note';
  note.addEventListener('mousedown', function(e) { return self.onMouseDown(e) }, false);
  note.addEventListener('click', function() { return self.onNoteClick() }, false);
  this.note = note;
  // ...
}

作者在某些地方(函数体)使用 self,在其他地方(方法参数列表中定义的函数体)使用 this。这是怎么回事?现在我已经注意到它一次了,我会开始到处看到它吗?

JavaScript 作用域 闭包

评论

6赞 subZero 12/7/2013
这是一个称为“词法闭包”的 JS 语言功能。
2赞 DavidRR 6/17/2015
可能的重复项:var self = this?
0赞 AL-zami 9/11/2017
这里明确解释了 THIS 的概念 scotch.io/@alZami/understanding-this-in-javascript
2赞 FluxLemur 6/19/2018
此答案中的相关示例 stackoverflow.com/a/20279485/5610569(对于“如何访问正确的内部回调?this

答:

450赞 Jonathan Fingland 6/7/2009 #1

请参阅这篇关于 alistapart.com 的文章。(编辑:本文自最初链接以来已更新)

self用于保持对原始内容的引用,即使上下文正在更改。这是事件处理程序(尤其是在闭包中)中经常使用的一种技术。this

编辑:请注意,现在不建议使用,因为 window.self 存在,如果您不小心,可能会导致错误。self

你怎么称呼变量并不是特别重要。 很好,但这个名字没有什么魔力。var that = this;

在上下文中声明的函数(例如回调、闭包)将有权访问在同一范围或更高范围内声明的变量/函数。

例如,一个简单的事件回调:

function MyConstructor(options) {
  let that = this;

  this.someprop = options.someprop || 'defaultprop';

  document.addEventListener('click', (event) => {
    alert(that.someprop);
  });
}

new MyConstructor({
  someprop: "Hello World"
});

评论

0赞 Bob Stein 10/26/2019
似乎该文章演变为var that = this;
0赞 Jonathan Fingland 11/1/2019
@BobStein 谢谢。我会相应地更新答案。
9赞 Mehrdad Afshari 6/7/2009 #2

该变量由方法中定义的内联函数捕获。 在函数中将引用另一个对象。这样,您可以使函数在外部作用域中保留对 的引用。thisthis

38赞 Nosredna 6/7/2009 #3

是的,你会在任何地方看到它。它通常是.that = this;

看看事件调用的函数内部是如何使用的?这些将有自己的上下文,因此用于保存进入的 .selfselfthisNote()

尽管函数只能在函数完成执行后才能执行,但函数仍然可用的原因是内部函数由于闭包而获取外部函数的上下文。selfNote()

评论

12赞 steve 1/7/2014
对我来说,令人信服的观点是它没有特别的意义。我个人更喜欢使用一个名为 something else 的 var,因为它经常让我感到困惑,因为我希望“self”是一个保留词。所以我喜欢你的回答。在 OP 的例子中,我更喜欢或类似。selfselfvar thisNote = this
0赞 mattLummus 3/8/2015
@steve同意,尽管我尽量避免使用这个/自我引用,因为它们在可维护性方面非常脆弱。
28赞 Max 11/23/2011 #4

还应该注意的是,如果您不喜欢这个习语,还有一种替代代理模式用于在回调中维护对原始的引用。thisvar self = this

由于可以使用 或 使用给定上下文调用函数,因此您可以编写一个包装器,该包装器返回一个函数,该函数使用给定上下文或使用给定上下文调用您的函数。有关此模式的实现,请参阅 jQuery 的函数。以下是使用它的示例:function.applyfunction.callapplycallproxy

var wrappedFunc = $.proxy(this.myFunc, this);

wrappedFunc然后可以调用,并将你的版本作为上下文。this

101赞 Duan Yao 9/24/2013 #5

我认为变量名称“self”不应该再以这种方式使用,因为现代浏览器提供了一个全局变量 self,指向普通窗口或 WebWorker 的全局对象。

为避免混淆和潜在冲突,您可以改写 或。var thiz = thisvar that = this

评论

47赞 djheru 3/21/2014
我通常使用_this
6赞 o_o_o-- 7/20/2014
@djheru +1。比“”好多了(我的大脑永远不会习惯)。that
9赞 Mopparthy Ravindranath 6/28/2015
我开始使用“我”:)
3赞 Beejor 7/3/2015
直到现代浏览器开始提供全局变量 _this、that 或 me。
10赞 Bergi 8/17/2015
使用这个名字绝对没有问题,只要你把它声明为一个 iable,它就会遮蔽全局。当然,如果您忘记了,那么它也不适用于任何其他名称。selfvarvar
5赞 SorinN 5/22/2014 #6

实际上 self 是对 window() 的引用,因此当你说你覆盖窗口对自身的引用时 - 因为 self 存在于 window 对象中。window.selfvar self = 'something'

这就是为什么大多数开发人员更喜欢var that = thisvar self = this;

无论如何; 不符合良好做法......假设您的代码稍后会被其他开发人员修改/修改,您应该使用开发人员社区中最常见的编程标准var that = this;

因此,您应该使用类似 var / / 之类的东西 - 以便在您的范围内清楚 // ..不是那么多,但会节省几秒钟和几个大脑周期oldThisvar oThis

评论

2赞 miphe 11/11/2014
@prior我认为直到最后一段都是有道理的。
0赞 Cyprien 12/28/2014 #7

如上所述,“self”只是用于在进入功能之前保持对“this”的引用。一旦进入函数,“this”指的是其他东西。

评论

0赞 GreenAsJade 1/3/2015
@JohnPaul......这确实提供了一个答案。这可能不是正确的答案,但你怎么能说“它被用于......“不是对”他为什么要这样做“的回答吗?
10赞 kombat 3/17/2015 #8

这是一个 JavaScript 怪癖。当函数是对象的属性时,更恰当地称为方法,这是指对象。在事件处理程序的示例中,包含对象是触发事件的元素。调用标准函数时,这将引用全局对象。当您具有示例中的嵌套函数时,这与外部函数的上下文完全无关。内部函数确实与包含函数共享范围,因此开发人员将使用 的变体,以便在内部函数中保留他们需要的 thisvar that = this

24赞 Elliot B. 1/30/2018 #9

正如其他人所解释的,允许闭包中的代码引用父范围。var self = this;

然而,现在是 2018 年,ES6 被所有主要的 Web 浏览器广泛支持。这个成语不像以前那么重要了。var self = this;

现在可以通过使用箭头函数来避免。var self = this;

在我们将使用以下情况的情况下:var self = this

function test() {
    var self = this;
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", function() {
        console.log(self.hello); // logs "world"
    });
};

我们现在可以使用箭头函数,而无需:var self = this

function test() {
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", () => {
        console.log(this.hello); // logs "world"
    });
};

箭头函数没有自己的函数,只是假设封闭范围。this

-4赞 ht zhao 8/2/2018 #10
function Person(firstname, lastname) {
  this.firstname = firstname;

  this.lastname = lastname;
  this.getfullname = function () {
    return `${this.firstname}   ${this.lastname}`;
  };

  let that = this;
  this.sayHi = function() {
    console.log(`i am this , ${this.firstname}`);
    console.log(`i am that , ${that.firstname}`);
  };
}

let thisss = new Person('thatbetty', 'thatzhao');

let thatt = {firstname: 'thisbetty', lastname: 'thiszhao'};

this.sayHi.call(thatt);

评论

3赞 Farhana Naaz Ansari 8/2/2018
你应该用代码添加一些解释,说明你做了什么特别。
0赞 Nithin B 4/8/2022
在这里进行一些解释会有所帮助。如果你执行 var temp = this.sayHi 然后调用 temp(),你可以看到差异。现在 this.firstname 将给出 undefined,而 that.firstname 将给出值,因为该变量创建了闭包。