gpt4 book ai didi

javascript - 如何在命名空间应用程序的更大范围内正确构造自调用嵌套函数?

转载 作者:行者123 更新时间:2023-11-29 17:19:52 25 4
gpt4 key购买 nike

我知道我可以像这样创建一个自调用的嵌套函数

(function ns(){

(function Class(){

alert('ns.Class fired');

})();

})();​

但是它很丑,而且看起来不太对。

我的 排骨不是他们应该的样子,我希望有人能告诉我一种更好的方法来构建我的命名空间应用程序,并且仍然能够利用“一些”自调用函数。

// 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com