帮助理解 javascript 全局消除技术

发布于 2024-10-23 11:15:44 字数 728 浏览 3 评论 0原文

来自 DailyJS “让我们构建一个 JavaScript 框架” 我'我不太确定以下代码,显然用作全局抑制技术。

到目前为止,我的理解对 (function(){}) 犹豫不决。我理解设置图灵变量,将 global.turing 设置为图灵,并返回 window 或 this (如果不在浏览器中),但是 (function(global){})(this 或 window) 的事情让我感到困惑......我见过像

var mything = {} 这样的东西,并将所有代码设置在 mything 下,但这个习惯用法让我有点困惑。

我真的很想理解这里的推理,而不是记住它“有效”

(function(global) {
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window);

From the DailyJS "Let's build a JavaScript Framework" I'm not quite sure on the following code, obviously used as a global abatement technique.

My understanding so far balks at (function(){}) . I understand setting the turing var up, setting global.turing to turing, and return either window or this (if not in a browser), but the (function(global){})(this or window) thing confuses me...I've seen things like

var mything = {} and setting all your code up under mything, but this idiom confuses me a little.

I really want to understand the reasoning here vs memorizing that it "works out"

(function(global) {
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

心不设防 2024-10-30 11:15:44

(这个答案已有 4 年多了(截至 2015 年 4 月),虽然它仍然正确,但我认为它需要更一般的解释 - 见下文)

原始答案

将此视为:

(function (x) {
    // ...
})(y);

作为:

function functionName(x) {
    // ...
}
functionName(y);

但没有需要给它一个名称(如 functionName)。

所以这:

(function(global) {
    // ...
})(typeof window === 'undefined' ? this : window);

真的只是:

function functionName(global) {
    // ...
}
functionName(typeof window === 'undefined' ? this : window);

它是一个只有一个参数的函数(在函数内称为 global ),并且使用 typeof window === 'undefined' 调用它? this : window 与: 的含义相同,

function functionName(global) {
    // ...
}
if (typeof window === 'undefined') {
    functionName(this);
} else {
    functionName(window);
}

但使用更短的符号(并且不命名函数)。

更一般的解释

我在 4 年前写了这个答案,我认为是时候对这里涉及的概念添加一些更一般的解释了。

正如我上面所解释的, this:

(function (x) {
    // ...
})(y);

是 this: 的匿名版本,

function functionName(x) {
    // ...
}
functionName(y);

它(如果你只调用一次)通常(参见下面的例外情况)也与此相同:

function functionName() {
    var x = y;
    // ...
}
functionName();

立即返回匿名被调用的函数,this:

(function (x) {
    // ...
})(y);

和 this: 是一样的,

(function () {
    var x = y;
    // ...
})();

这对大多数人来说可能有更明显的含义。 (这里立即调用的函数没有参数,仅用于为变量和其他嵌套函数提供一个隔离的作用域,这样我们就不会污染外部或全局作用域 - 这也是在中使用参数的主要原因首先立即调用匿名函数。)

关于括号

顺便说一下,this:

(function () {
    // ...
})();

与 this: 相同:

(function () {
    // ...
}());

由于语言歧义,函数周围的括号是必需的,但它们可能包含 ()实际上调用该函数,也可能不调用该函数 - 尽管有些人认为这里的第二种形式看起来更清晰。请参阅Douglas Crockford 的解释了解更多详细信息以及为什么他认为第一个版本看起来像“狗球。”

并且

之前我说过 this:

(function (x) {
    // ...
}(y));

与 this: 相同,

(function () {
    var x = y;
    // ...
}());

对于一个参数来说,这在大多数情况下都是正确的(这不会在外部作用域中屏蔽同名变量,同时又取决于其值)并且通常对于多个参数都是正确的(如果它们也不相互依赖)。我希望通过示例可以更加清楚。

当我们有这段代码时:

(function (x) {
    // ...
}(x + 1));

那么我们不能将其翻译为:

(function () {
    var x = x + 1;
    // ...
}());

因为在第一个版本中,我们将 1 添加到 outer x 并将结果绑定到 inside x 一旦我们进入函数内部,我们就只有内部 x 可以使用(甚至是新的 let 语句对我们没有帮助)。

另一个例子:

(function (x, outer_x) {
    // ...
}(1, x));

在这里,您可以将外部作用域中的 old_x 设置为 x 的值,并将内部作用域中的 x 设置为新值 1 ,而且您不必担心订单。但如果你这样做了:

摘要

因此,正如你所看到的,在某些情况下你不能简单地将: 翻译

(function (x) {
    // ...
}(y));

成:

(function () {
    var x = y;
    // ...
}());

但我认为,如果它可以翻译成第二种形式,那么它应该是为了可读性。特别是对于较大的函数,您必须滚动到函数末尾才能知道函数顶部使用的变量的含义,这很不方便。

回到问题

这意味着我会将这段代码从问题:

(function(global) {
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window);

翻译成:

(function () {
  var global = typeof window === 'undefined' ? this : window;
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
}());

我希望这个答案解释了为什么这两个是等价的,甚至可以写成:

(function (global, turing) {
  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window,
   {VERSION: '0.0.1', lesson: 'Part 1: Library Architecture'});

并且它仍然意味着相同,虽然很多同时可读性较差。

另请参阅我的其他答案,其中我解释了类似的概念。

(This answer is over 4 years old (as of April, 2015) and while it's still correct I think it needs a more general explanation - see below)

Original answer

Think of this:

(function (x) {
    // ...
})(y);

as:

function functionName(x) {
    // ...
}
functionName(y);

but without the need to give it a name (like functionName).

So this:

(function(global) {
    // ...
})(typeof window === 'undefined' ? this : window);

is really just:

function functionName(global) {
    // ...
}
functionName(typeof window === 'undefined' ? this : window);

It is a function with one argument (called global within the function) and it is called with typeof window === 'undefined' ? this : window which means the same as:

function functionName(global) {
    // ...
}
if (typeof window === 'undefined') {
    functionName(this);
} else {
    functionName(window);
}

but using a shorter notation (and without naming the function).

More general explanation

I wrote this answer over 4 years ago and I think it's time to add some more general explanation of the concepts that are involved here.

As I explained above, this:

(function (x) {
    // ...
})(y);

is an anonymous version of this:

function functionName(x) {
    // ...
}
functionName(y);

which (if you call it only once) is usually (see below for exceptions) also the same as this:

function functionName() {
    var x = y;
    // ...
}
functionName();

Going back to the anonymous immediately invoked function, this:

(function (x) {
    // ...
})(y);

is the same as this:

(function () {
    var x = y;
    // ...
})();

which may be have a more obvious meaning for most people. (Here the immediately invoked function has no arguments and serves only the purpose of giving us an isolated scope for variables and other nested functions, so that we don't pollute the outer or global scope - which is also the main reason of using arguments in immediately invoked anonymous functions in the first place.)

On parentheses

By the way, this:

(function () {
    // ...
})();

is the same as this:

(function () {
    // ...
}());

The parentheses around the function are required because of a language ambiguity but they may include the () that actually invoke the function or they may not - though some people argue that the second form here looks more clear. See this explanation by Douglas Crockford for more details and why he thinks that the first version looks like "dog balls."

Exceptions

Previously I said that this:

(function (x) {
    // ...
}(y));

is the same as this:

(function () {
    var x = y;
    // ...
}());

and this is most of the time true for one argument (that doesn't mask the variable of the same name in the outer scope while depending on its value at the same time) and usually true for more than one argument (if they don't depend on each other as well). I hope it will get more clear on the examples.

When we have this code:

(function (x) {
    // ...
}(x + 1));

then we can't translate it into:

(function () {
    var x = x + 1;
    // ...
}());

because in the first version we add 1 to the outer x and bind the result to the inner x and as soon as we get inside the function we have only the inner x to work with (and even the new let statement will not help us with that).

Another example:

(function (x, outer_x) {
    // ...
}(1, x));

Here you can set old_x to the value of x from the outer scope and x in the inner scope to a new value of 1, and you don't have to worry about the order. But if you did:

Summary

So as you see there are some situations where you cannot simply translate:

(function (x) {
    // ...
}(y));

into:

(function () {
    var x = y;
    // ...
}());

but I would argue that if it can be translated into the second form then it should be for readability. Especially for larger functions it is inconvenient that you have to scroll to the end of the function to know what the variable used at the top of the function mean.

Back to the question

That means that I would translate this code from the question:

(function(global) {
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window);

into this:

(function () {
  var global = typeof window === 'undefined' ? this : window;
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
}());

I hope this answer explains why those two are equivalent, and that it could even be written as:

(function (global, turing) {
  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window,
   {VERSION: '0.0.1', lesson: 'Part 1: Library Architecture'});

and it would still mean the same, while being much less readable at the same time.

See also my other answer where I explain similar concepts.

也只是曾经 2024-10-30 11:15:44

这是一个匿名函数或 lambda 函数。大多数语言都支持这一点。

使用匿名函数实际上是作者的偏好问题。如果不设置匿名函数来处理先前调用的返回值,则必须通过初始化变量来包含返回的对象,然后在稍后将其传递给全局声明的函数,从而在客户端分配额外的内存。串行方式。

如果是1次函数,则节省空间、内存、时间。

作为旁注:通过谷歌搜索函数式编程背后的一些概念,您可能会对此有更好的感觉。 Lambda 函数最近似乎很流行,尤其是在 Python 中。

This is an anonymous or lambda function. Most languages support this.

Using an anonymous function is really a matter of preference for the author. Without setting up an anonymous function to deal with the return value of a prior call, you would have to allocate additional memory on the client side by initializing a variable to contain the returned object and then pass it to a globally declared function later on in a serial manner.

If it is a 1 time function, it saves space, memory, time.

As a side-note: You can probably get a better feeling for this by googling around for some of the concepts behind functional programming. Lambda functions seem to be all the rage lately, especially in Python.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文