【问题标题】:JSLint Error: Unexpected 'this'JSLint 错误:意外的“这个”
【发布时间】:2015-07-30 15:37:02
【问题描述】:

无法理解为什么 JSLint 对我在以下代码中使用 this 感到惊讶:

function testConstr (x) {
    'use strict';
    this.joker = "Whyyy sooo seriousss?";
    this.x = x;
}

对于这两个属性分配,JSLint 都说:意外的“this”。如何更正我的代码?

【问题讨论】:

  • 您的this 不一定是坏事。 testConstr 是否用作构造函数?你是用call 还是apply 调用它?
  • 如果你发现 JSLint 有太多的任意警告,你想看看 JSHint。
  • 如果你把它大写成TestConstr会发生什么?警告是否仍然存在?
  • @apsillers 是的,这也是我的第一步。还是被打了。新的 JSLint 希望鼓励您完全停止使用 this。我的意思是,诚然,对于新的(和旧的!)JavaScript 编码人员来说,范围确实是最令人困惑的话题之一,尽管我不知道这是否足以在默认情况下禁止使用它。他的rationale 是“在语言中使用this 会使谈论该语言变得更加困难”。我猜这并没有。可能值得尝试一段时间。
  • JSLint 现在提供了抑制此投诉的选项。请参阅my answer

标签: javascript constructor jslint


【解决方案1】:

在严格模式下,this 引用设置为 undefined

所以你的两个语句都会导致读取undefined对象的属性,这会导致异常。

如何更正我的代码?

删除这两行。

UPD:我上面所说的是 JSLint 如何处理您的代码,而不是我如何处理。

【讨论】:

  • 或者:因为在非严格模式下,this 指的是 windowwindow.jokerwindow.x 也是可能的……除非 this 指的是事件目标或其他东西…
  • 您假设testConstr 被称为testConstr()。鉴于它的名字,情况可能并非如此。
  • @Oriol 我不假设任何事情——它是 JSLint。我个人认为 JSLint 的破坏性大于实用性。
  • Re: 破坏性的:值得指出的是 this 选项是 JSLint 测试版的新选项,它只有几周的历史。我也有点失望。我的意思是,Crockford's comment,“[使用this] 就像与 Abbott 和 Costello 的结对编程”对于指出什么是 最佳实践并没有真正的帮助正是这种情况。我暂时给测试版提供了怀疑的好处,但请注意,所写的原始代码在 old.jslint.com 中进行 lints,只是将“混乱的空白”指令设置为 true。 所以上个月不那么邪恶了。
【解决方案2】:

您的代码可能完全正确(也可能有问题,具体取决于您如何调用testConstr)。

我的建议是:让 JSLint 闭嘴

或者根本不使用 JSLint。

【讨论】:

  • 我会使用 new 关键字来调用它(即将它用作对象构造函数)。抱歉,如果不清楚。所以换句话说,JSLint 不会自动期望我使用构造函数模式?对像我这样的人没有帮助。 . .
  • @jdw 如果你使用new 应该没问题。 JSLint 不仅仅是偏执狂。
  • 是的,这也是一种选择,但如果我不想通过使用此 JSLint 指令来抑制此警告怎么办。
【解决方案3】:

So in other words, JSLint doesn't automatically expect me to use a constructor pattern?

你知道,我认为你是对的。你的问题困扰着我,我注册了Crockford's JSLint discussion groupasked。他回答了,但忽略了我将在下面介绍的解决方案,我认为这意味着没关系,就像 JSLint 不会抱怨通过集合时一样。

(不过,我仍在等待更新的Good Parts。)

除此之外,我建议对通过 Beta JSLint 的 OO JavaScript 执行以下操作(无论如何,从今天开始)。

我将重写 MDN 页面“Introduction to Object Oriented Programming”中的一个示例,该页面本身大量使用this

this

这是上面链接部分中原始的、unlinted MDN 示例:

var Person = function (firstName) {
  this.firstName = firstName;
};

Person.prototype.sayHello = function() {
  console.log("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");

// call the Person sayHello method.
person1.sayHello(); // logs "Hello, I'm Alice"
person2.sayHello(); // logs "Hello, I'm Bob"

这遵循我们熟悉和喜爱的惯例。

没有this

很容易弄清楚如何制作不遵循该模式的“构造函数”,但如果我没有遗漏任何内容,我们将不再使用prototype,并且必须将所有对象的方法包含在我们希望所有我们的Peeps 共享的构造函数。

/*jslint white:true, devel:true */
var Peep = function(firstName) {
    "use strict";
    var peep = {};
    peep.firstName = firstName;

    peep.innerSayHello = function() {
        console.log("Hello, I'm " + peep.firstName + ".");
    };

    return peep;
};

var peep1 = new Peep("Bob");
var peep2 = new Peep("Doug");

peep1.innerSayHello();
peep2.innerSayHello();

所以有一个 lintable 替代方案。除了return peep; 和方法的内部定义之外,这确实使 JavaScript 的行为类似于您可能遇到的许多面向对象优先的语言。至少没有

无法访问prototype 并不可怕;在构造函数旁边不正确的地方更改prototype 确实是个坏消息,因为您的代码会变成意大利面条。 “有些Persons 有sayGoodbye(),有些没有,这取决于我们是否在构造它们时修改了原型。” 这太糟糕了。因此,这种替代约定有其优势。

当然,稍后您仍然可以将函数添加到 Peep 的单个实例化中,但我不确定您如何在不使用 this 的情况下访问 firstName,所以也许他希望我们停止修改构建后的对象。

person1.sayGoodbye = function (other) { 
    console.log("Goodbye, " + other + "."); 
};

(我的意思是,我们仍然可以给 Peep 打猴子补丁以在进程中更改它,但那是可怕的、愚蠢的编程。通常。

继承(不带this

我认为继承很容易。

var PeepWithGoodbye = function (firstName) {
    "use strict";
    var peepWithGoodbye = new Peep(firstName);

    peepWithGoodbye.innerSayGoodbye = function (otherPeep) {
        if (undefined === otherPeep) {
            otherPeep = { firstName: "you" };
        }
        console.log("This is " + firstName 
            + " saying goodbye to " + otherPeep.firstName + ".");
    };

    return peepWithGoodbye;
};

var pwg1 = new PeepWithGoodbye("Fred");
pwg1.innerSayHello();           // Hello, I'm Fred.
pwg1.innerSayGoodbye(peep1);    // This is Fred saying goodbye to Bob.
pwg1.innerSayGoodbye();         // This is Fred saying goodbye to you.

编辑: 另请参阅this answer,提问者后来发现 Crockford 建议的创建 OO javascript 的方法。我试图说服那个人删除 Q&A 并将 A 移到这里。如果他没有,我可能会在此处添加他的资料和社区 wiki。


编辑:请参阅 this from MDN 了解其工作原理:

(通常构造函数不返回值,但他们可以选择这样做 所以如果他们想覆盖正常的对象创建过程。)

【讨论】:

    【解决方案4】:

    JSLint 说:意外的“这个”。如何更正我的代码?

    无需更正您的代码。

    help page for JSLint/*jslint*/ 指令部分中,已将“Tolerate this”选项添加到可用选项表中:

    +---------------+------+---------------------------------+
    | Tolerate this | this | true if this should be allowed. |
    +---------------+------+---------------------------------+
    

    因此,为了抑制对使用 this 的投诉,请将以下指令放入源文件中的第一条语句之前:

    /*jslint
        this
    */
    

    (请注意,其他 /*jslint*/ 选项可以在 this 之后通过在选项之间插入逗号。请参阅 JSLint 帮助页面。)

    另请参阅the answer by @Oriol 以在 JSLint 的用户界面中启用 "Tolerate this" 选项。

    【讨论】:

      【解决方案5】:
      'use strict';
      
      var SudoConstructor = (function () {
      
          /* We need bind, < IE9 needs a (tiny) polyfill */
      
          function protoEsqDeclare(sudoThis) {
              return sudoThis;
          }
      
          function protoEsqSet(sudoThis, newValA, newValB) {
              sudoThis.valA = newValA;
              sudoThis.valB = newValB;
          }
      
          function instanceCreator(valA, valB) {
              var sudoThis = {
                  valA: valA,
                  valB: valB
              };
      
              return {
                  declare: protoEsqDeclare.bind(null, sudoThis),
                  set: protoEsqSet.bind(null, sudoThis)
              };
      
          }
      
          return instanceCreator;
      
      }());
      

      【讨论】:

        【解决方案6】:

        我知道一个老问题,但如果它对任何人有帮助,我正在观看 Douglas Crockford 的 talk,他说(大约 23 分钟)他把它拿出来,因为攻击者可以将方法作为函数运行并使用“this”关键字访问全局范围。

        他说这也意味着不再使用 Object.create ——他帮助引入了该语言的一个功能!

        【讨论】:

          猜你喜欢
          • 2012-02-29
          • 2016-03-01
          • 2014-01-09
          • 2015-02-09
          • 2012-10-21
          • 2011-03-01
          • 1970-01-01
          • 2018-06-21
          相关资源
          最近更新 更多