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

IT技术 javascript scope closures
2021-01-17 19:30:14

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

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这是怎么回事?现在我已经注意到它一次,我会开始到处看到它吗?

6个回答

请参阅alistapart.com 上的这篇文章(Ed:文章自最初链接以来已更新)

selfthis即使上下文发生变化,也用于维护对原始文件的引用这是一种常用于事件处理程序(尤其是在闭包中)的技术。

编辑:请注意,self现在不鼓励使用,window.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"
});

@BobStein 谢谢。我会相应地更新答案。
2021-03-19 19:30:14
看来那篇文章变成了使用var that = this;
2021-03-26 19:30:14

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

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

我开始使用“我”:)
2021-03-21 19:30:14
直到现代浏览器开始提供全局变量 _this、that 或 me。
2021-03-21 19:30:14
@djheru +1。比“ that好得多(我的大脑永远不会习惯)。
2021-03-31 19:30:14
我通常使用 _this
2021-04-02 19:30:14
self只要您将其声明为variable,使用该名称绝对没有问题,它会影响全局。当然,如果您忘记了,var那么它也不适用于任何其他名称。
2021-04-08 19:30:14

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

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

self函数仍然可用的原因是,即使它们只能在Note()函数执行完毕后执行,也是由于闭包,内部函数获得了外部函数的上下文

@steve 同意,尽管我尽量避免使用 this/self 引用,因为它们在可维护性方面非常脆弱。
2021-03-29 19:30:14
对我来说,有说服力的一点是self没有特别的意义。我个人更喜欢使用以其他名称命名的 var,self因为它经常让我感到困惑,因为我希望“self”是一个保留字。所以我喜欢你的回答。在 OP 的示例中,我更喜欢var thisNote = this或类似。
2021-04-08 19:30:14

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

作为一个功能可以与特定背景下,通过使用被称为function.apply或者function.call,你可以写一个包装,返回与调用你的功能一个功能applycall使用给定的范围内。有关proxy此模式的实现,请参阅 jQuery 的函数。下面是一个使用它的例子:

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

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

正如其他人所解释的,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,只是承担封闭的作用域。

或者——震惊,恐怖!– 为什么不将实际相关的东西作为参数传递给你的函数(闭包)?你为什么要引用超出范围的状态,为什么有人像这样编程?从来没有任何真正的理由这样做。相反,.addEventListender("click", (x) => { console.log(x); });您已经非常清楚地解释了方法和原因,我同意使用箭头函数更有意义,但仍然......这只是可怕、懒惰、凌乱的编程。
2021-03-20 19:30:14
在 JavaScript 中,返回父作用域是非常常见和必要的。它是语言的基本组成部分。您建议将父作用域作为事件处理程序的参数传入实际上是不可能的。此外,在 ES6 中,箭头函数使用词法作用域——“this”指的是它当前的周围作用域,而不是进一步——它不是“引用超出作用域的状态”或类似的东西。
2021-03-23 19:30:14