我对以下代码中为什么JSLint对我的this
使用感到惊讶感到困惑:
function testConstr (x) {
'use strict';
this.joker = "Whyyy sooo seriousss?";
this.x = x;
}
对于这两个属性分配,JSLint报告说:Unexpected 'this'。 我该如何纠正我的代码?
我对以下代码中为什么JSLint对我的this
使用感到惊讶感到困惑:
function testConstr (x) {
'use strict';
this.joker = "Whyyy sooo seriousss?";
this.x = x;
}
对于这两个属性分配,JSLint报告说:Unexpected 'this'。 我该如何纠正我的代码?
你的代码可能完全正确(也可能有问题,取决于你如何调用testConstr
)。
我的建议是:告诉JSLint别再管闲事了
或者干脆不使用JSLint。
new
关键字(即将其用作对象构造函数)。如果这不太清楚,我很抱歉。换句话说,JSLint 并不自动要求我使用构造函数模式?对像我这样的新手来说不是很有帮助... - jdwnew
,那应该是完全没问题的。JSLint 只是过于谨慎了。 - Oriol你知道吗,我认为你是对的。你的问题困扰了我,我加入了Crockford 的 JSLint 讨论组并且提出了问题。他回答了我,但忽略了我下面要介绍的解决方案,我认为这意味着没问题,就像 JSLint 不会抱怨某些情况一样。
(我还在等待更新版的《JavaScript高级程序设计》。)
除了这个警告之外,以下是我建议用于通过 Beta JSLint 的面向对象 JavaScript 的方法(至少截至今天)。
我将重写 MDN 页面中的示例,《介绍面向对象编程》,该示例本身广泛使用了this
。
this
以下是来自上面链接的 MDN 示例的原始未经 JSLint 处理的代码:
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
的功能,并且必须在我们的构造函数中包含所有我们希望所有 Peep
共享的对象方法。
/*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();
所以有一种可供检测的替代方案。除了 return peep;
和方法内部的内部定义之外,它使 JavaScript 的行为像你可能遇到的许多面向对象语言一样。至少它不是错误的。
没有访问 prototype
并不可怕;在不紧贴构造函数旁边改变 prototype
是非常糟糕的消息,因为你的代码会变得混乱。“某些 Person 具有 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.
编辑:请参考这个回答,其中提问者后来发现了Crockford建议的创建OO JavaScript的方法。我正在试图说服那个人删除那个Q&A并将A移动到这里。如果他不这样做,我可能会将他的东西添加到这里并将其变为社区wiki。
编辑:请看MDN上的这篇文章,解释为什么它能工作:
(通常构造函数不会返回值,但如果他们想要覆盖正常的对象创建过程,则可以选择这样做。)
'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;
}());
this
引用被设置为undefined
。因此,你的两个语句都将导致读取undefined
对象的属性,这将导致异常。如何更正代码?删除这两行即可。更新:我上面说的是JSLint如何处理你的代码,而不是我如何处理。this
指的是 window
,所以 window.joker
和 window.x
也是可能的……除非 this
指向一个事件目标或其他什么东西…… - Sebastian SimontestConstr
被称为 testConstr()
来调用,但考虑到它的名称,这不一定是情况。 - Oriolthis
选项是JSLint beta的新功能,该版本只有几周的历史。我也有点失望。我的意思是,Crockford的评论,“*[使用this
]就像与Abbott和Costello一起进行编程”并没有真正有助于指出在这种情况下什么是最佳实践。我现在给beta版以怀疑的好处,但请注意,原始代码按原样编写,在old.jslint.com上进行了语法检查,只需将“混乱的空格”指令设置为true即可。所以上个月更少的罪恶。 - ruffin/*jslint*/
指令的部分中,已经添加了一个"容忍this
"选项到可用选项表中。+---------------+------+---------------------------------+
| Tolerate this | this | true if this should be allowed. |
+---------------+------+---------------------------------+
this
的投诉,请在第一条语句之前将以下指令放入您的源文件中:/*jslint
this
*/
this
后面可以通过在选项之间插入逗号来添加其他/*jslint*/
选项。请参阅 JSLint 帮助页面。this
" 选项。我知道这是一个老问题,但如果有帮助的话,我观看了Douglas Crockford的演讲(大约在23分钟处),他说他将其删除是因为攻击者可以将一个方法作为函数运行,并使用“this”关键字访问全局范围。
他还表示这也意味着不再使用Object.create - 这是他帮助引入到语言中的一个特性!
this
不一定是错误的。testConstr
用作构造函数了吗?你使用call
还是apply
调用它? - OriolTestConstr
,会发生什么?警告是否仍然存在? - apsillersthis
。我是说,诚然,作用域确实是对于新(和老!)JavaScript 程序员最令人困惑的话题之一,但我不知道这是否足以成为默认禁止使用它的理由。他的理由是“在语言中使用this
使得谈论该语言更加困难”。我猜这并没有错。或许值得一试一段时间。 - ruffin