2012-04-09 128 views
2

退房这段JavaScript代码:的JavaScript代码片段解释

(function (w, d) { 
    var loader = function() { 
     var s = d.createElement("script"), tag = d.getElementsByTagName("script")[0]; 
     s.src = "https://example.org/script.js"; 
     tag.parentNode.insertBefore(s,tag); 
    }; 
    w.addEventListener ? w.addEventListener("load", loader, false) : 
         w.attachEvent("onload", loader); 
}) (window, document); 

为什么这段代码使用这种方法的作者,包括文档中的脚本? 什么是该行的用处:

w.addEventListener ? w.addEventListener("load", loader, false) : 
        w.attachEvent("onload", loader); 

最后一点:我是一个JavaScript初学者,什么是(window, document)在结束了吗?

+2

您最后一点的快速'n'简单解释:http://www.youtube.com/watch?v = i_qE1iAmjFg&t = 1m30s – 2012-04-09 01:00:31

+1

@Darragh - 我要去看那个。这看起来像是一个很好的解释! – jmort253 2012-04-09 01:11:53

回答

2

以下addEventListener行用于注册该函数,以便在页面加载完成时调用该函数。 Internet Explorer和Firefox(等)使用不同的功能来执行此操作。

w.addEventListener ? w.addEventListener("load", loader, false) : 
       w.attachEvent("onload", loader); 

在JavaScript中,函数本身就是一个对象。因此,它的'价值'可以被分配给一个变量或立即消费。要立即使用它,它必须包装在圆括号中(否则它不会做你想做的),然后把它称为常规函数。

(function (w, d) { ... }) (window, document); 

如果我们把它分解成两行,这就更加明显。

var a = function(w, d){ ... }; 
a(window, document); 

这样做是为了不污染具有临时值或功能的全局范围。更不用说不捣毁任何其他变量。这可以分为两部分:

  1. 通过将代码封装在闭包中,明确声明的任何内容都在闭包的范围内,而不是全局范围。 var loader在关闭范围内。
  2. 通过立即使用闭包,它不会被存储在全局范围的变量中。由于它是匿名声明的,它不会作为全局范围内的命名函数存在。
+0

因此,作者使用闭包,因为他可能不会污染全球范围,你的意思是不创建任何使用某个名字的函数? – 2012-04-09 01:20:42

+0

是的。如果它不在关闭中,那么'var loader'会出现在全局范围内,可能会被意外或恶意地再次调用。通过使用闭包,它只存在于闭包范围中。 – BlindWanderer 2012-04-09 01:37:06

3

第一个问题,代码检查是否定义了window.addEventListener。如果是,则使用它,否则使用window.attachEvent。这是为了浏览器的兼容性。

第二个问题,这个代码是一个匿名函数,它需要2个参数w和d。立即调用该函数,传递参数windowdocument

1

它看起来像作者正在等待页面被完全加载之前,附加脚本标记。 addEventListener(DOM级别2)和attachEvent(Microsoft stuff)是更灵活的附加事件方式。该代码类似于说w.onload = loader

最后一位是将参数传递到匿名函数中,它们被命名为wd。通过将()放在最后,即可立即调用匿名函数。

+0

什么是DOM级别2?另外,如果作者想等待页面完全加载,他也可以使用jQuery'$(document).ready()',对吧? – 2012-04-09 01:03:42

+0

@FredCollins dom 2级只是一个规范。如果作者使用jQuery,那会产生一个类似(但更快)的结果。 – tau 2012-04-09 04:57:45

1

所以这个函数被封装在一个闭包中。这又意味着w = windowd = document

当该方法被称为它创建一个名为loader功能这对于两个可能的事件监听器的触发器的一个回调(意思是,当loadonload事件被称为窗口上会调用)。

x ? y : z语法是简写if then else调用。

如果我们扩大了这一点,它会是这样的:

if (w.addEventListener) { 
    w.addEventListener("load", loader, false); 
} else { 
    w.attachEvent("onload", loader); 
} 

使用这种说法迎合IE和其他浏览器的方法。

2

首先,w.addEventListener ?确保浏览器是否支持窗口

其次的addEventListener方法,(window, document)是他function(w,d) {}

1

以前写过匿名函数只是参数调用这实际上是一样的:

function RegisterEventListener(w, d) { 
    var loader = function() { 
     var s = d.createElement("script"), tag = d.getElementsByTagName("script")[0]; 
     s.src = "https://example.org/script.js"; 
     tag.parentNode.insertBefore(s,tag); 
    }; 
    if (w.addEventListener) { 
     w.addEventListener("load", loader, false); 
    } else { 
     w.attachEvent("onload", loader); 
    } 
} 

RegisterEventListener(window, document); 

唯一真正的区别是:

  1. 如果您定义一个匿名函数(使用function() {};)而不将它分配给任何东西,它只能用于有限使用(因为没有办法引用它)。与此同时,匿名函数也允许立即执行(就像您的问题function(a, b) {}(a, b);中的代码中那样)。
  2. condition ? true : false(高级操作员)只是简写if语句的简写,因此它需要较少的输入才能写出,但也有人认为它的可读性较差。
+0

整洁。那么为什么很多用户使用闭包方式呢?哪个优势? – 2012-04-09 01:07:09

+0

用更清晰的差异定义更新答案。 – 2012-04-09 01:13:19

1

我可能是错的,但这是Google使用他们的分析脚本实现的。

这被称为闭包,是一个自动执行的函数,并将变量放在里面,所以它们不能混淆你的代码。

该代码实质上创建了一个脚本标记,并将其附加到DOM,然后在文档中找到第一个脚本标记。

第一个问题的答案是关于浏览器兼容性。一些浏览器使用addEventListener和其他attachEvent将事件附加到页面中的元素(在本例中为窗口),并且它将放在窗口的加载事件上(当所有内容被加载时,在文档准备好之后)。看看这个更详细的答案:window.onload vs $(document).ready()

第二个答案很简单。这是在封闭(自动调用函数)使用的参数,并可以以这种方式来阅读:

function anonymous(w, d) { 
    ... 
} 
anonymous(window, document); 
+0

谢谢。你能解释一下“(当所有的HTML被加载,但在文档准备好之前)”?它不等同于jQuery'$(document).ready()'? – 2012-04-09 01:09:49

+0

对不起,我交换了意思。 window.onload在document.ready之后触发,当所有内容完成加载时。我会更新答案。 – rcdmk 2012-04-09 01:14:35

1

这段代码的作者是用包裹在一个封闭的匿名函数来断火的功能,这注册一个加载事件。在窗口的onload事件触发之前,页面上的脚本实际上不会被加载。

作者可能会延迟脚本加载的原因可能是在实际加载其他脚本之前为网页提供更多时间进行渲染。这是一种很好的技术,可以在不延迟加载不需要的资源的情况下快速加载页面内容。

作者正在使用的技术是封装在一个封闭的匿名函数。拍下这一刻:

myFunction (window, document); 

现在,我要和一个匿名函数来代替函数调用:

function(w, d) { 
    // do stuff 
    alert("w = " + w); 
    alert("d = " + d); 
} 

现在我要去会导致功能立即运行,实际上并没有给它一个名字。我也要去两个参数传递到匿名函数:

(function(w, d) { 
     // do stuff 
     alert("w = " + w); 
     alert("d = " + d); 
}) ("1234", "5678"); 

此示例中的输出是:

w = 1234 
d = 5678 

如果你看括号搭配起来,第一外括号匹配字符2的最后一行的最后一个括号,即函数名称,下面的一组括号将传递给该函数的两个值作为参数进行包装。

这可能是一个很难理解的问题,在你看到它做了几次后,它开始变得更有意义。

+0

但是没有问题,页面可以加载,用户点击使用加载的脚本中包含的JavaScript代码的东西? – 2012-04-09 01:12:57

+1

绝对!所以作为一名开发人员,您必须确保资源不是立即需要的,因为这可能会导致问题。我的建议是只使用该脚本加载技术来处理不涉及用户发起行为的事情。有人使用了在后台默默运行的分析跟踪代码示例。这是该技术的完美人选。 – jmort253 2012-04-09 01:14:45

+0

感谢jmort253,所以不建议用于包含按钮,表单等行为的加载脚本。仅适用于默默“次要”行为。 – 2012-04-09 01:26:40

1
  1. 以这种方式添加脚本允许作者将该脚本包含在文档中而不直接编辑HTML文件。也可以用于仅在需要时动态加载脚本。 (即如果你有一堆代码在页面上编辑某些东西,你不想下载它,直到用户实际点击编辑按钮,这样当你不需要时,不会浪费带宽)。

  2. addEventListener和attachEvent是在页面加载完成时触发函数的方法。在这种情况下,有一个名为loader 的函数两者的原因是一些浏览器支持一个,另一个支持另一个。我一直在使用jQuery足够长的时间,我不记得哪个是哪个。

  3. (窗口,文档)是一种将范围内的变量封装和/或通过简写w和d引用它们的方法。作者正在创建一个函数,期望这些参数,然后将窗口和文档作为参数传递给它们。

关闭还可以帮助作者避免让他的脚本与页面上的其他脚本发生冲突。想想在这里声明的每个变量,就像它是其他语言的私有变量一样。

1

第一个代码块末尾的window, document是在代码块其余部分定义的匿名函数的参数。由于JavaScript几乎是一种功能性语言,程序员可以定义这些匿名函数,甚至可以在不给他们命名的情况下使用它们。

您用问号粘贴的代码块是中缀符号的一个例子,它是一种符合以下模式的语言结构:condition ? ifTrueExpression : ifFalseExpression。在condition为真的情况下,整个表达式将等于ifTrueExpression。否则,整个表达式将等于ifFalseExpression

您粘贴的中缀记法的使用在检测使用哪种类型的互联网浏览器时很常见。尽管我不确定这段代码试图检测哪个浏览器,但其目的是以浏览器特定方式实现事件处理程序。