第 1 条:了解你使用的 JavaScript 版本

story 发布于:2015-10-23 10:57 栏目:转载 浏览:602 评论:1
Effective JavaScript:编写高质量JavaScript代码的68个有效方法
       像大多数成功的技术一样,JavaScript已经发展了一段时间。最初JavaScript作为Java在交互式网页编程方面的补充而推向市场,但它最终完全取代了Java成为主流的Web编程语言。JavaScript的普及使得其于1997年正式成为国际标准,其官方名称为ECMAScript。目前许多JavaScript的竞争实现都提供了ECMAScript标准的各种版本的一致性。

        1999年定稿的第3版ECMAScript标准(通常简称为ES3),目前仍是最广泛采用的JavaScript版本。下一个有重大改进的标准是2009年发布的第5版,即ES5。ES5引入了一些新的特性,并且标准化了一些受到广泛支持但之前未规范的特性。由于ES5目前还未得到广泛支持,所以我会适时指出本书中的条款或建议是否特定于ES5。

        除了ECMAScript标准存在多个版本之外,还存在一些JavaScript实现支持非标准特性,而其他的JavaScript实现却并不支持这些特性的情况。例如,许多JavaScript引擎支持const关键字定义变量,但ECMAScript标准并没有定义任何关于const关键字的语义和行为。此外,在不同的实现之间,const关键字的行为也不一样。在某些情况下,const关键字修饰的变量不能被更新。
const PI = 3.1415926;
PI = 'modified';
PI;// 3.1415926
而其他的实现只是简单地将 const 视为 var 的代名词
const PI = 3.1415926;
PI = 'modified';
PI;// 'modified'
       由于JavaScript历史悠久且实现多样化,因此我们很难确定哪些特性在哪些平台上是可用的。而令事态更加严峻的事实是JavaScript的主要生态系统——Web浏览器,它并不支持让程序员指定某个JavaScript的版本来执行代码。由于最终用户可能使用不同Web浏览器的不同版本,因此,我们必须精心地编写Web程序,使得其在所有的浏览器上始终工作如一。

        另外,JavaScript并不只是针对客户端Web编程。JavaScript的其他应用包括服务器端程序、浏览器扩展以及针对移动和桌面应用程序的脚本。某些情况下你可能需要一个特定的JavaScript版本。对于这些情况,利用特定平台支持的JavaScript特定实现的额外特性是有意义的。

        本书主要关注的是JavaScript的标准特性,但是也会讨论一些广泛支持的非标准特性。当涉及新标准特性或非标准特性时,了解你的应用程序运行环境是否支持这些特性是至关重要的。否则,你可能会面临这样的困境——应用程序在你自己的计算机或者测试环境上运行良好,但是将它部署在不同的产品环境中时却无法运行。例如,const关键字在支持非标准特性的JavaScript引擎上测试时运行良好,但是,当将它部署在不识别const关键字的Web浏览器上时就会出现语法错误。

        ES5引入了另一种版本控制的考量——严格模式(strict mode)。此特性允许你选择在受限制的JavaScript版本中禁止使用一些JavaScript语言中问题较多或易于出错的特性。由于其语法设计向后兼容,因此即使在那些没有实现严格模式检查的环境中仍然可以执行严格代码(strict code)。在程序中启用严格模式的方式是在程序的最开始增加一个特定的字符串字面量(literal)。
'use strict';
       同样,你也可以在函数体的开始处加入这句指令以启用该函数的严格模式。
function f(X){
    'use strict';
    //...
}
       使用字符串字面量作为指令语法看起来有点怪异,但它的好处是向后兼容。由于解释执行字符串字面量并没有任何副作用,所以ES3引擎执行这条指令是无伤大雅的。ES3引擎解释执行该字符串,然后立即丢弃其值。这使得编写的严格模式的代码可以运行在旧的JavaScript引擎上,但有一个重要的限制:旧的引擎不会进行任何的严格模式检查。如果你没有在ES5环境中做过测试,那么,编写的代码运行于ES5环境中就很容易出错。
function f(X){
    'use strict';
    var arguments = [];// error :reddfinition of arguments
    //...
}
       在严格模式下,不允许重定义arguments变量,但没有实现严格模式检查的环境会接受这段代码。然而,这段代码部署在实现ES5的产品环境中将导致程序出错。所以,你应该总是在完全兼容ES5的环境中测试严格代码。

        “use strict”指令只有在脚本或函数的顶部才能生效,这也是使用严格模式的一个陷阱。这样,脚本连接变得颇为敏感。对于一些大型的应用软件,在开发中使用多个独立的文件,然而部署到产品环境时却需要连接成一个单一的文件。例如,想将一个文件运行于严格模式下:
//file1.js
'use strict';
function f(){
    var arguments = [];// error :reddfinition of arguments
    //...
}
而另一个文件不是运行于严格模式下
//file2.js
//no strict-mode directive
function g(){
    var arguments = [];
    //...
}
我们怎样才能正确地连接这两个文件呢?如果我们以file1.js文件开始,那么连接后的代码运行于严格模式下:
//file1.js
'use strict';
function f(){
    //...
}
   
//file2.js
//no strict-mode directive
function g(){
    var arguments = [];// error :reddfinition of arguments
    //...
}
如果我们以 file2.js 文件开始,那么连接后的代码运行于非严格模式下:

//file2.js
//no strict-mode directive
function g(){
    var arguments = [];
    //...
}
//file1.js
'use strict';
function f(){
    //...
}
       在自己的项目中,你可以坚持只使用“严格模式”或只使用“非严格模式”的策略,但如果你要编写健壮的代码应对各种各样的代码连接,你有两个可选的方案。

        第一个解决方案是不要将进行严格模式检查的文件和不进行严格模式检查的文件连接起来。这可能是最简单的解决方案,但它无疑会限制你对应用程序或库的文件结构的控制力。在最好的情况下,你至少要部署两个独立的文件。一个包含所有期望进行严格检查的文件,另一个则包含所有无须进行严格检查的文件。

        第二个解决方案是通过将其自身包裹在立即调用的函数表达式(Immediately Invoked Function Expression, IIFE)中的方式连接多个文件。第13条将对立即调用的函数表达式进行深入的讲解。总之,将每个文件的内容包裹在一个立即调用的函数中,即使在不同的模式下,它们都将被独立地解释执行。基于此方案,上面例子的连接版本如下:
(function(){
    //file1.js
    'use strict';
    function f(){
        //...
    }
})()
   
   
(function(){
    //file2.js
    //no strict-mode directive
    function f(){
        var arguments = [];
        //...
    }
})()
       由于每个文件的内容被放置在一个单独的作用域中,所以使用严格模式指令(或者不使用严格模式指令)只影响本文件的内容。但是这种方式会导致这些文件的内容不会在全局作用域内解释。例如,var和function声明的变量不会被视为全局变量(更多关于全局概念的内容参见第8条)。这恰好与流行的模块系统(module system)类似,模块系统通过自动地将每个模块的内容放置在单独的函数中的方式来管理文件和依赖。由于所有文件都放置在局部作用域内,所以每个文件都可以自行决定是否要使用严格模式。

        编写文件使其在两种模式下行为一致。想要编写一个库,使其可以工作在尽可能多的环境中,你不能假设库文件会被脚本连接工具置于一个函数中,也不能假设客户端的代码库是否处于严格模式或者非严格模式。要想构建代码以获得最大的兼容性,最简单的方法是在严格模式下编写代码,并显式地将代码内容包裹在本地启用了严格模式的函数中。这种方式类似于前面描述的方案——将每个文件的内容包裹在一个立即调用的函数表达式中,但在这种情况下,你是自己编写立即调用的函数表达式并且显式地选择严格模式,而不是采用脚本连接工具或模块系统帮你实现。
(function(){
    'use strict';
    function f(){
        //...
    }
})()
       要注意的是,无论这段代码是在严格模式还是在非严格模式的环境中连接的,它都被视为是严格的。相比之下,即使一个函数没有选择严格模式,如果它连接在严格代码之后,它仍被视为是严格的。所以,为了达到更为普遍的兼容性,建议在严格模式下编写代码。
  • 决定你的应用程序支持JavaScript的哪些版本 。
  • 确保你使用的任何JavaScript的特性对于应用程序将要运行的所有环境都是支持的。
  • 总是在执行严格模式检查的环境中测试严格代码。
  • 当心连接那些在不同严格模式下有不同预期的脚本。
沙发#
发布于:2015-11-07 09:59
不错,点个赞
游客

返回顶部