使用此关键字和显示模块模式的严格违规
Posted
技术标签:
【中文标题】使用此关键字和显示模块模式的严格违规【英文标题】:Strict Violation using this keyword and revealing module pattern 【发布时间】:2011-09-12 03:46:27 【问题描述】:无法让以下内容通过 jslint/jshint
/*jshint strict: true */
var myModule = (function()
"use strict";
var privVar = true,
pubVar = false;
function privFn()
return this.test; // -> Strict violation.
function pubFn()
this.test = 'public'; // -> Strict violation.
privFn.call(this); // -> Strict violation.
return
pubVar: pubVar,
pubFn: pubFn
;
());
myModule.pubFn();
我知道这是由于在函数声明中使用 this
引起的,但我读了 Crockford 写的一些东西,他说违规是为了防止全局变量污染 - 但这里唯一的全局变量是我m 明确定义...myModule
。其他所有内容都保存在直接函数范围内,我应该能够使用this
来引用该模块。
有什么想法可以让这种模式通过吗?
更新:如果我使用函数表达式而不是声明,这似乎可行,即
var pubFn = function () ...
虽然我不喜欢这种格式,但我更喜欢函数名称和命名参数更接近,并且声明看起来/感觉更清晰。老实说,我不明白为什么会引发违规行为 - 这种模式没有理由这样做。
【问题讨论】:
听起来像是可以忽略 jslint 抱怨的情况之一。顺便说一句,pubVar
在以myModule.pubVar
访问时如何工作?它并没有真正让模型外部的代码访问模块中的变量,对吗?我会认为,如果您想实际获取/设置模块变量的当前值,则需要 getter 和 setter 函数。
你说得对,我觉得这看起来有点滑稽。如果您尝试myModule.pubVar = true
,您只需重写对象的属性。内部pubVar
将保持为false
更新:我更喜欢var foo = function()
而不是function foo()
,因为它有助于避免托管问题。此外,我喜欢它确实 使函数看起来更像其他变量,因为在 JS 中,函数或任何其他值之间没有区别——它们是一流的。个人喜好,我知道——但我想我会抛出一些想法。
伪题外话:如果你仍然想使用这种我个人不喜欢的模式......你可以使用“crockford”变体,即直接在返回对象中键入公共接口。它甚至更短,更容易维护。无论如何,为私有成员使用闭包是不值得的。
@ikaros45 “无论如何,对私有成员使用闭包是不值得的。”我想知道为什么
【参考方案1】:
这里真正的问题是,如果您从 模块上下文 内(从 IIFE 内)调用 privFn
,this
将是 @987654324 @ 在严格模式下; window
如果不是在严格模式下。唉,如果从 IIFE 中调用该函数将会失败。
这是因为从 IIFE 中调用函数时没有 所有者(对象),而 返回的模块对象是函数在调用时的所有者来自 IIFE 上下文之外,例如this === myModule
调用 myModule.pubFn()
时。
严格模式和 JSHint/JSLint 都在努力帮助你,你永远不应该忽略它们产生的错误/警告,而要弄清楚它们为什么警告你。
如果您 100% 确定 privFn
、pubFn
等不会在模块之外的任何地方被调用,只需在任何生成警告的函数中添加注释 /*jshint validthis: true */
。或者,IIFE 中的一条注释将阻止 JSHint 在模块内的任何函数上生成此错误。
众多可能的解决方案之一
存储this
的范围(在此示例中为self
)以显式引用模块。这将显示并确保您的意图。
/*jshint strict: true */
var myModule = (function()
"use strict";
var privVar = true,
pubVar = false,
self = this;
function privFn()
return self.test;
function pubFn()
self.test = 'public';
//privFn.call(this); // Will have no effect, as `privFn` does not reference `this`
privFn();
return
pubVar: pubVar,
pubFn: pubFn
;
());
myModule.pubFn();
【讨论】:
完全同意你的回答只是想再补充一件事。如果您在以大写字母开头的函数中使用“this”,它不会给您任何警告。因为函数以大写字母开头意味着您将使用它作为带有 new 关键字的构造函数。即使在严格模式下,您也允许在构造函数中使用它:) 我对在不同地方使用的数组映射(回调,上下文)回调有同样的问题。在这种情况下,“this”具有完全有效的用法,因为它由 map() 的第二个参数提供。顺便说一下,其他数组方法也是如此,例如 some()、every()、reduce()、reduceRight()。我认为 JSHint 和 JSLint 可以检查此类函数是否始终用作具有提供上下文的数组方法回调【参考方案2】:JSHint 有一个名为 validthis
的 option,它:
[...] 当代码在严格模式下运行并且您在非构造函数 [...] 中使用
this
时,当您确定使用 @987654324 时,会抑制有关可能的严格违规的警告@ 在严格模式下有效。
在 JSHint 抱怨的函数中使用它,在你的情况下,它看起来像这样:
function privFn()
/*jshint validthis: true */
return this.test; // -> No Strict violation!
function pubFn()
/*jshint validthis: true */
this.test = 'public'; // -> No Strict violation!
privFn.call(this); // -> No Strict violation!
在每个适用的函数中指定它似乎很痛苦,但是如果您在模块函数的顶部设置选项,您可能会隐藏 genuine 严格模式违规自己。
【讨论】:
【参考方案3】:不幸的是,这是此设置的预期错误,因为 jslint/jshint 不知道在全局上下文中声明的函数将在以后用作对象方法。
【讨论】:
但是这些函数没有在全局代码中声明。它们嵌套在您的函数表达式(用于包装模块代码)中。以上是关于使用此关键字和显示模块模式的严格违规的主要内容,如果未能解决你的问题,请参考以下文章