PHP是我的第一门编程语言,之后通过像jQuery这样的库首次接触JavaScript。由于JavaScript与PHP的工作原理不同,开始时总有一些JavaScript问题困扰着我。即使现在,仍有让我感到疑惑的东西。我想分享一些开始使用JavaScript时我苦苦思考的问题。这些问题将涉及:全局命名空间、this、ECMAScript 3 和ECMAScript 5的区别、异步调用、原型以及 简单的JavaScript继承。
全局命名空间
在PHP中,特别地,当你在类(或命名空间块)之外声明一个函数变量时,你实质上往全局命名空间添加了一个函数。在JavaScript中,没有所谓的命名空间,然而所有的东西都附属于全局对象。在Web浏览器中,全局对象就是windows对象。另一个主要区别是:在JavaScript中,函数和变量均是全局对象的属性,即我们通常指代的properties。
因为,当你覆盖一个全局函数或属性,JavaScript不会给出任何警告,所以这会很麻烦,实际上是相当危险的。
1 2 3 4 5 6 7 8 9 10 11 12 |
function globalFunction() { console.log('I am the original global function'); } function overWriteTheGlobal() { globalFunction = function() { console.log('I am the new global function'); } } globalFunction(); //输出 "I am the original global function" overWriteTheGlobal(); //重写最初的全局函数 globalFunction(); //输出 "I am the new global function" |
JavaScript中的一种技术是立即执行函数表达式,一般称为自执行匿名函数。它对于保持变量和函数的独立性是非常有用的。通常,我通过传入对象方式将函数暴露给外界。这是模块模式的一个变种。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var module = {}; (function(exports){ exports.notGlobalFunction = function() { console.log('I am not global'); }; }(module)); function notGlobalFunction() { console.log('I am global'); } notGlobalFunction(); //输出 "I am global" module.notGlobalFunction(); //输出 "I am not global" |
在自执行匿名函数里,所有的全局作用域是封闭的,通过将之依附到module变量实现。从技术上讲,你可以直接把属性附加到module变量,但我们将它传递给函数的原因是:明确地表明函数所附加的地方。它允许我们给传入函数的对象起别名。这里的关键是:我们预先声明依赖于模块变量,而不依赖于全局变量。
你也许已经注意到了var关键字。如果你不知道如何使用它,基本的解释是:在声明变量前使用var,为离之最近的函数创建了一个属性。如果省略var关键字,那么意味着给现有变量分配一个新值,并提升了作用域链。这个作用域链可能是全局范围的。
1 2 3 4 5 6 7 8 9 10 |
var imAGlobal = true; function globalGrabber() { imAGlobal = false; return imAGlobal; } console.log(imAGlobal); //输出 "true" console.log(globalGrabber()); //输出 "false" console.log(imAGlobal); //输出 "false" |
正如你所看到的一样,在你的函数中依赖全局变量是相当危险的,因为可能产生副作用,造成难以预料的冲突。当你使用var关键字时,会发生什么呢?
1 2 3 4 5 6 7 8 9 10 |
var imAGlobal = true; function globalGrabber() { var imAGlobal = false; return imAGlobal; } console.log(imAGlobal); //输出 "true" console.log(globalGrabber()); //输出 "false" console.log(imAGlobal); //输出 "true" |
JavaScript将var声明变量提升到函数块顶部,接着初始化变量。这就是所谓的变量提升。
总结:所有变量的作用于一个函数内(函数本身就是一个对象),并使用var声明这些变量就确定它们的函数作用域,不使用var意味着声明一个全局变量。
让我们来看看使用变量提升的情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function variableHoist() { /">JBLOTUS。欢迎加入翻译组。 PHP是我的第一门编程语言,之后通过像jQuery这样的库首次接触JavaScript。由于JavaScript与PHP的工作原理不同,开始时总有一些JavaScript问题困扰着我。即使现在,仍有让我感到疑惑的东西。我想分享一些开始使用JavaScript时我苦苦思考的问题。这些问题将涉及:全局命名空间、this、ECMAScript 3 和ECMAScript 5的区别、异步调用、原型以及 简单的JavaScript继承。 全局命名空间在PHP中,特别地,当你在类(或命名空间块)之外声明一个函数变量时,你实质上往全局命名空间添加了一个函数。在JavaScript中,没有所谓的命名空间,然而所有的东西都附属于全局对象。在Web浏览器中,全局对象就是windows对象。另一个主要区别是:在JavaScript中,函数和变量均是全局对象的属性,即我们通常指代的properties。 因为,当你覆盖一个全局函数或属性,JavaScript不会给出任何警告,所以这会很麻烦,实际上是相当危险的。
JavaScript中的一种技术是立即执行函数表达式,一般称为自执行匿名函数。它对于保持变量和函数的独立性是非常有用的。通常,我通过传入对象方式将函数暴露给外界。这是模块模式的一个变种。
在自执行匿名函数里,所有的全局作用域是封闭的,通过将之依附到module变量实现。从技术上讲,你可以直接把属性附加到module变量,但我们将它传递给函数的原因是:明确地表明函数所附加的地方。它允许我们给传入函数的对象起别名。这里的关键是:我们预先声明依赖于模块变量,而不依赖于全局变量。 你也许已经注意到了var关键字。如果你不知道如何使用它,基本的解释是:在声明变量前使用var,为离之最近的函数创建了一个属性。如果省略var关键字,那么意味着给现有变量分配一个新值,并提升了作用域链。这个作用域链可能是全局范围的。
正如你所看到的一样,在你的函数中依赖全局变量是相当危险的,因为可能产生副作用,造成难以预料的冲突。当你使用var关键字时,会发生什么呢?
JavaScript将var声明变量提升到函数块顶部,接着初始化变量。这就是所谓的变量提升。 总结:所有变量的作用于一个函数内(函数本身就是一个对象),并使用var声明这些变量就确定它们的函数作用域,不使用var意味着声明一个全局变量。 让我们来看看使用变量提升的情况:
|