- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我知道我可以像这样创建一个自调用的嵌套函数
(function ns(){
(function Class(){
alert('ns.Class fired');
})();
})();
但是它很丑,而且看起来不太对。
我的 js排骨不是他们应该的样子,我希望有人能告诉我一种更好的方法来构建我的命名空间应用程序,并且仍然能够利用“一些”自调用函数。
// THIS DOESN'T WORK
// because I haven't called "ns"
function ns(){
(function Class(){
alert('fired');
})();
};
为了我的目的,我问这个的原因是为了更好地命名我的 JS 与 jQuery 的结合。
所以我希望能够做这样的事情(这确实有效)
var ns = ns || {};
ns.Class = function(){};
ns.Class.Navigation = (function() {
$('#element').on('click', function() {alert('element clicked');});
})();
但我不确定这是否是构建更大(阅读:js 重)应用程序的正确方法?!?!
最佳答案
好吧,首先:您调用“主”IIFE ns
这一事实表明您将其视为命名空间对象,这并不完全正确。命名空间通常使用 IIFE 创建,因为它们具有闭包作用域的额外好处。但归根结底,命名空间只是 Object(文字)的一个花哨的词。
拿最流行的 lib/toolkit/framework 来说:jQuery。基本上,它是一个巨大的 IIFE,它构造了一个同样庞大的对象,并为其分配了许多方法和属性(好吧,无论如何都是对函数对象的引用)。在该 IIFE 中创建了一些其他对象和变量,但它们要么根本不暴露给全局对象,要么(非常)间接地暴露给全局对象。
请允许我澄清一下:
var myNameSpace = (function()
{
var invisibleVar = 'can\'t touch this';
var objectLiteral = {sing: function()
{
return invisibleVar;//exposed, albeit indirectly
},
property: 'Hammertime'
};
var semiExposed;
objectLiteral.getSemi = function(newVal)
{
return semiExposed;//change closure var
};
objectLiteral.changeSemi = function(newVal)
{
semiExposed = newVal;//change closure var
};
objectLiteral.restoreSemi = (function(initVal)
{
return function()
{
semiExposed = initVal;//restore to value set when main IIFE was executed
//don't worry about what this references: use the force... of the scope
return objectLiteral.getSemi();//<-- return init val
};
}(semiExposed));//pass initial value to this scope
var notExposedAtAll = function()
{//can't be called but inside the main IIFE scope (and subsequent scopes)
objectLiteral.foo = 'But it adds a public property';
};
objectLiteral.changeMe = function()
{
notExposedAtAll();//called in default context (either null or global, but it doesn't matter here)
};
return objectLiteral;//direct exposure
}());
这使用了所有工具包/库的一些基本原则,实际上所有体面的 JS 脚本共享:使用函数作为一流对象,使用它们作为表达式来创建临时范围等...)
IMO,它是 IIFE 的一个很好的例子:作用域让您有足够的时间将任何对象分配给变量,因此无论如何您创建方法(使用或没有 IIFE),您不必担心 this
在任何给定时间引用的内容,只需使用变量即可。
您也可以实现一些基本的数据隐藏。在此示例中,semiExposed
的初始值被传递给 IIFE,并保留在其范围内。没有什么可以解决这个问题(好吧,目前这不是完全正确的),所以您总是可以恢复到任何属性的初始值。
但是,我承认,随着代码的增长,IIFE 会使您的代码更难阅读,而且我完全理解为什么您不想过多地使用它们。您可以查看 bind
,它会帮助您减少许多 IIFE,但有一个缺点。有些人还在使用 IE8,例如,它不支持 bind
。
但另一种选择是:创建一个简单的 IIFE factory 函数:
function giveScope(varsFromScope,toFunction)
{
return function()
{
var passArguments = Array.prototype.slice.apply(arguments,[0]);//get args from call
passArguments.push({scope:varsFromScope});
toFunction.apply(this,passArguments);
};
}
var pseudoClosure = giveScope({scopeContext: this, something:'else'},function(arg1,arg2)
{
//function body here
arguments[arguments.length - 1].currentContext;//<== "closure scope"
this;//called context
});
那样的话,您可以通过将对象传递给一个简单的函数调用来替换它们,从而摆脱一些 IIFE。简单,与 X 浏览器兼容。
最后,您的第一个片段是我倾向于在事件委托(delegate)中使用的内容:
var target = e.target || e.srcElement;
var parentDiv = (function(targetRef)
{
while(targetRef.tagName.toLowerCase() !== 'div')
{
targetRef = targetRef.parentNode;
}
return targetRef;
}(target));
这样,我就不必在同一范围内创建另一个可验证对象,当找到 div 时,我的 targetRef 被分配给 parentDiv
,并且 targetRef 被 GC,我完成了有了它,所以没有必要让那个变量留在范围内。
现在已经很晚了,我不知道我说的有没有道理。底线是:您可能讨厌 IIFE,但您真的离不开它们。
如果困扰您的是大量括号,您可能会很高兴知道您必须使用它们。任何强制 JS 引擎将函数声明解释为表达式的运算符都将执行:
(function()
{
}());
//can be written as:
!function()
{
}();
//or
~function()
{
}();
//or when assigning the return value, you don't even need anything at all:
var foo = function()
{
return 'bar';
}();
console.log(foo);//logs bar
也许您更喜欢其他符号?但老实说:您可能不喜欢语法,但恐怕您将不得不忍受它,或者切换到 coffeescript 或其他东西。
关于javascript - 如何在命名空间应用程序的更大范围内正确构造自调用嵌套函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13706986/
谁能解释一下原因: (define a (lambda() (cons a #f))) (car (a)) ==> procedure ((car (a))) ==> (procedure . #f)
这是 PyBrain 网站的摘录。我了解大部分正在发生的事情,但是一行让我完全难住了。我以前从未在 python 代码中看到过这样的东西。这是整个循环,对于上下文: for c in [0,
我是gradle / groovy的新手。我想创建将做一些事情的自定义任务。我的第一个问题是任务完成时该如何做?我可以覆盖doFirst / doLast闭包吗?也许我可以重写某些在开始和结束时都会执
我刚刚开始评估 MS 企业库。他们使用以下指令来获取实例: var customerDb = EnterpriseLibraryContainer.Current.GetInstance("C
这是我的 if else Ansible 逻辑.. - name: Check certs exist stat: path=/etc/letsencrypt/live/{{ rootDomain
我正在使用construct 2.8 对一些失传已久的 Pascal 程序创建的一些文件的 header 进行逆向工程。 header 由许多不同的记录组成,其中一些是可选的,我不确定顺序是否固定。
我在将 getchar() 的输入放入 char *arr[] 数组时遇到问题。我这样做的原因是因为输入数据(将是一个带有命令行参数的文件)将存储在一个 char 指针数组中以传递给 execvp 函
通常我们不能约束类型参数 T派生自密封类型(例如 struct 类型)。这将毫无意义,因为只有一种类型适合,因此不需要泛型。所以约束如下: where T : string 或: where T :
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve th
#include using namespace std; class A { private: int m_i; friend int main(int argc, char cons
这个问题在这里已经有了答案: Are there legitimate uses for JavaScript's "with" statement? (33 个答案) 关闭 9 年前。 我有这个代
在this answer我看到了下一个 Bash 结构。 yes "$(< file.txt)" 什么意思 "$(< file.txt)" ? 我明白了 命令替换 - $(command)用命令的结
if (a == 1) //do something else if (a == 2) //do something else if (a == 3) //do somethi
关于构造的快速简单的问题。 我有以下用于将项目添加到 ListView 的代码。 ListViewItem item = new ListViewItem(); item.Text = file; i
我想使用 std::vector 来控制给定的内存。首先,我很确定这不是好的做法,但好奇心占了上风,无论如何我都想知道如何做到这一点。 我遇到的问题是这样的方法: vector getRow(unsi
下面显示了一段简单的javascript: var mystring = ("random","ignored","text","h") + ("ello world") 这个字符串会生成 hello
在 Java 中,创建对象的标准方法是使用 MyClass name = new MyClass(); 我也经常看到构造 new MyClass() { /*stuff goes in here*/
我正在编写 C++ ndarray 类。我需要动态大小和编译时大小已知的数组(分别分配自由存储和分配堆栈)。我想支持从嵌套的 std::initializer_list 进行初始化。 动态大小的没问题
我正在将一个项目从 Visual Studio 2005 转换为 Visual Studio 2008,并提出了上述结构。 using Castle.Core.Resource; using Cast
我想知道我在这里的想法是否正确,我主要针对接口(interface)进行编程,所以我想知道下面的类是否应该通过 DI 注入(inject),或者我应该自己实例化一个类... 注意:这些服务保存在我的核
我是一名优秀的程序员,十分优秀!