`

为现代 JavaScript 开发做好准备

 
阅读更多
http://blog.jobbole.com/66135/
今天无论是在浏览器中还是在浏览器外,JavaScript世界正在经历翻天覆地地变化。如果我们谈论脚本加载、客户端的MVC框架、压缩器、AMD、Common.js还有Coffeescript……只会让你的脑子发昏。对于那些已经早就熟知这些技术的人而言,或许很难想象到现在为止还有很多JS开发者还不熟悉这些工具,甚至事实上,他们很可能现在还不想去尝试这些工具。

这篇文章将会介绍一些很基础的JS知识,以及当开发者想要尝试Backbone.js和Ember.js之类的工具之前需要知道一些内容。当你理解了这篇文章中的大部分内容的时候,你会更有信心去学习其他高级JavaScript知识的时候。这篇文章是假设你曾经使用过JavaScript的,所以如果你从没有接触过它,也许你需要先了解下更基础的知识。现在我们开始吧!



模块

有多少人在一个文件中写的JS像下面的代码块一样?(注意:我可没有说内嵌在HTML文件中哦):
var someSharedValue = 10;
var myFunction = function(){ //do something }
var anotherImportantFunction = function() { //do more stuff }

如果你做到了这一点,那么很有可能你正在写这样的代码。我不是在给你下定义,因为在相当长的一段时间里我也曾这么写程序。事实上这段代码有很多毛病,不过我们会专注在讨论全局命名空间的污染问题上。这样的代码代码会把方法和变量都暴露在了全局中,我们需要将让这些数据与全局命名空间独立开来,我们将会采用模块模式(Module Pattern)来实现这个目的。模块中可以有很多不同的形式达到我们的目标,我会从最简单的方法开始说:立即调用的函数表达式(Immediately Invoked Function Expression,简写为:IIFE)。

名字听起来很高大上,不过它的实现其实很简单:
(function(){
    //do some work
})();

如果在此之前你从未接触过这种函数,可能现在你会觉得它很怪 — 怎么会有这么多括号!它是会立即执行的函数,你可以这么理解:一个函数被创建了后又立刻被调用。它应该是一个表达而不是一个语句:一个函数语句是一定要有一个名字的,但是大家也看到了,立即执行函数是没有名字的。在函数定义的外部还有一组括号,这一点也能很好地帮助我们在代码中轻易找到匿名函数的身影。

现在我们知道要怎么写一个立即执行函数了,那就来聊聊为什么要使用它吧。在JS中我们都是在和各种作用域之中的函数打交道,所以如果我们想要创建一个作用域,就可以使用函数。匿名函数中的变量和方法的作用域仅仅在匿名函数中,就不会污染全局的命名空间,那么现在还需要考虑的一个问题是,我们要如何从外部取得那些在匿名函数作用域中的变量和方法呢?答案就是全局命名空间:将变量放入全局命名空间中,或者至少将作用变量与全局命名空间关联起来

想要在立即执行函数外部调用方法,我们可以将window对象传入立即执行函数,再将函数或变量值赋值到这个对象上。为了保证这个window对象的引入不会造成什么混乱,我们可以将widow对象作为一个变量传入我们的立即执行函数中。当做函数传入参数的方法同样适用于第三方库,甚至undefined这样的值。现在我们的立即执行函数看起来是这样的:
(function(window, $, undefined){
    //do some work
})(window, jQuery);

正如你所看到的,我们将window和jQuery传入函数中(’$'符号表示的就是’jQuery’,把它用在这的原因是防止其他库也定义了’$'),但是这个函数其实是接收了3个参数。如果我们没有传入第三个参数,形参undefined 的值会保持这个状态,而不会由于其他代码把全局的undefined改变了它也跟着改变。其实在函数内我们也是可以直接使用这些值,能这么做的原理是,JS的闭包会覆盖他们所处的上下文。对于这个话题,我曾写过一篇关于C#的文章以解释这个概念,这两者是互通的。

现在我们有了一个会立即执行的方法,还有一个相对安全的执行上下文,其中还包含有window、$和undefined变量(这几个变量还是有可能在这个脚本被执行前就被重新赋值,不过现在的可能性要小的多了)。现在我们已经做得很好了:把我们的代码从全局环境下的一团混乱的局面中拯救了出来;降低了与其他在同一应用中使用的脚本的冲突可能性。

任何我们想要从模块中获取的东西都可以通过window对象拿到。但是通常我不会直接将模块中的内容直接复制到window对象上,而是会用更有组织性地将模块中的内容。在大部分语言中,我们将这些容器称为“命名空间”,在JS中我们可以用“对象”的方式来模拟。



命名空间

如果我们想要声明一个命名空间,将一个函数放进这个空间中,代码可以写成这样:
window.myApp = window.myApp || {};
window.myApp.someFunction = function(){
    //so some work
};

我们是在全局环境中创建了一个对象,它是用于查看另外的某个对象是否已经存在,如果已经存在了,那么我们就可以直接使用;不然就需要用’{}’来创建一个新的对象。接着,我们可以开始添加这个命名空间的内容,将各种函数放入这个空间中,就像上面的代码片段所做的那样,但是我们又不希望这些函数就随便的放在那里,而是希望将模块和命名空间联系在一起,就像下面这样:
(function(myApp, $, undefined){
    //do some work
}(window.myApp = window.myApp || {}, jQuery));

还可以这么写:
window.myApp = (function(myApp, $, undefined){
    //do some work
    return myApp;
})(window.myApp || {}, jQuery);

现在,我们不再是将window传入我们的模块中,我们将一个和window对象联系在一起的命名空间传入模块中。之所以使用’||’的原因是我们可以重复使用同一个命名空间,而不是每次需要使用命名空间的时候我们又要重新创建一个。许多包含有命名空间方法的库会帮你创建好空间的,或者你可以使用一些想namespace.js这样的工具来构建嵌套的命名空间。由于在JS中,每一个在命名空间中的项你都不得不指定它的命名空间,所以通常我都尽量不会去创建深度嵌套的命名空间。如果你在MyApp.MyModule.MySubModule中创建了一个doSomething方法,你需要这么引用它:
MyApp.MyModule.MySubModule.doSomething();

每次你要调用它,或者你可以在你的模块中给这个命名空间一个别名:
var MySubModule = MyApp.MyModule.MySubModule;

这样定义以后,如果你想用doSomething这个方法可以用MySubModule.doSomething()来调用。不过这个方式其实是不必要的,除非你有非常非常多的代码,不然这么做只会将问题复杂化。



揭秘模块模式

在创建模块时你也常会看到另一种设计模式:揭秘模块模式(Revealing Module Pattern)。它和模块模式有一些不同:所有定义在模块中的内容都是私有的,然后你可以把所有要暴露到模块外部的内容放在一个对象中,再返回这个对象。你可以这么做:
var myModule = (function($, undefined){
     var myVar1 = '',
     myVar2 = '';
 
     var someFunction = function(){
         return myVar1 + " " + myVar2;
     };
 
     return {
         getMyVar1: function() { return myVar1; }, //myVar1 public getter
         setMyVar1: function(val) { myVar1 = val; }, //myVar1 public setter
         someFunction: someFunction //some function made public
     }
})(jQuery);

一次就建立一个模块,然后返回一个包含有需要公有化的模块片段的对象,同时模块中需要保持私有的变量也不会被暴露。myModule变量会包含有两个共有的项,不过其中Somefunction中的myVar2是从外部获取不到的。



创建构造器(类)

在JS中没有“类”这个概念,但是我们可以通过创建构造器来创建“对象”。假设现在我们要创建一系列Person对象,还需要传入姓、名和年龄,我们可以将构造器定义成下面这样(这部分代码应该放在模块之中):
var Person = function(firstName, lastName, age){
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
}
 
Person.prototype.fullName = function(){
    return this.firstName + " " + this.lastName;
};

现在先看第一个函数,你会看到我们创建了一个Person构造器。我们用它来构造新的person对象。这个构造器需要3个传入参数,然后将这3个参数赋值到执行上下文中。我们也是通过这种方式获取到公有实例变量。这里也可以创建私有变量:将传入参数赋值到这个构造器中的局部变量。但是这么做以后,公有的方法就没法获取这些私有的变量了,所以你最好还是把它们都变成公有的。也可以把方法放在构造器中同时还能从外部获取到它,这样方法就能拿到构造器里的私有变量了,不过这么做的话又会出现一系列新的问题。

第二个方法中我们使用了Person构造器的”原型”(prototype)。一个函数的原型就是一个对象,当你需要在某个实例上解析它所调用到的字段或者函数时你需要遍历这个函数上所有的实例。所以这几行代码所做的就是创建一个fullName方法的实例,然后所有的Person的实例都能直接调用到这方法,而不是对每个Person实例都添加一个fullName方法,造成方法的泛滥。我们也可以在构造器中用
this.fullName = function() { …

的方式定义fullName,但这样每一个Person实例都会有fullName方法的副本,这不是我们希望的。

如果我们想要创建一个Person实例,我们可以这么做:
var person = new Person("Justin", "Etheredge");
alert(person.fullName());

我们也可以创建一个继承自Person的构造器:Spy构造器,我们会创建Spy的一个实例,不过只会声明一个方法:
var Spy = function(firstName, lastName, age){
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
};
Spy.prototype = new Person();
 
Spy.prototype.spy = function(){
    alert(this.fullName() + " is spying.");   
}
 
var mySpy = new Spy("Mr.", "Spy", 50);
mySpy.spy();

正如你所看到的,我们创建了一个和Person很相似的构造器,但是它的原型是Person的一个实例。现在我们又添加上一些方法,使得Spy的实例又可以调用到Person的方法,同时还能直接取得Spy中的变量。这个方法比较复杂,不过一旦你明白怎么使用了,你的代码就会变得很优雅。



结语

看到这里,希望你已经学到了一些东西。不过这篇文章里并没有介绍多少关于“现代”JS的开发。这篇文章中涉及的还是旧知识,在过去几年里它们的使用面相当广。希望你看完这篇文章以后,找到了学习JS的正确的方向。现在可能你把代码放到了不同的模块不同的文件中(你应该做到这一点!),那么下一步你要开始着手研究如何将JS结合和压缩。如果你是使用Rails 3的开发者,可以在asset pipeline上免费获取这些信息或者工具。如果你是.NET开发者,你可以看看SquishIt框架,我就是从这里开始的。如果你是ASP.NET MVC 4的开发者,也有相关的资源。
分享到:
评论

相关推荐

    [jQuery.JavaScript与CSS开发入门经典].(约克).施宏斌等.扫描版

    《jQuery、JavaScript与CSS开发入门经典》是一本旨在引导初学者进入前端开发领域的权威指南,由施宏斌等专家合著。这本书详细介绍了这三种关键技术的基础知识和实践应用,为读者构建坚实的Web开发基础。 首先,...

    javascript开发的玛丽医生游戏

    JavaScript开发的玛丽医生游戏是一种利用Web技术重构的经典FC游戏,旨在让玩家在现代设备上重温童年乐趣。这个游戏的实现基于JavaScript编程语言,这是一种广泛应用于网页交互和动态内容生成的脚本语言。JavaScript...

    roc:JavaScript现代JavaScript开发生态系统

    使用现代库轻松构建JavaScript项目。 快速创建由 , 和类的库提供支持的产品,只需最少的额外设置即可在生产中部署。 和等工具为构建过程提供了动力。 由内部的团队进行维护和生产。 当前使用Node4 +和npm3支持Linux...

    javascript做的谷歌吃豆游戏

    【标题】"javascript做的谷歌吃豆游戏" 描述了一款完全使用JavaScript开发的电子游戏,模仿了经典的“吃豆人”玩法。JavaScript是一种广泛应用于网页和互联网应用开发的编程语言,以其灵活性和强大的功能在创建交互...

    javascript音乐播放器(可二次开发)

    下面将详细讨论JavaScript音乐播放器的核心知识点及其在实际开发中的应用。 1. HTML5 Audio API JavaScript音乐播放器的基础是HTML5的Audio API。这个API提供了创建和控制音频元素的能力,包括播放、暂停、停止、...

    几个JavaScript做的导航条源码

    9. **模块化与组件化**:现代JavaScript开发倾向于使用模块化工具,如ES6的import/export语法,这有助于将导航条代码封装为可复用的组件。 10. **测试与调试**:编写JavaScript代码后,应确保在各种浏览器和设备上...

    最流行的编程语言JavaScript能做什么? - OPEN 开发经验库1

    而React Native则是Facebook推出的框架,它允许开发者用JavaScript开发原生性能的移动应用,提供了更接近原生体验的用户界面。 在服务端,JavaScript通过Node.js平台实现了后端开发。Node.js利用非阻塞I/O和事件...

    JavaScript_学习全栈开发代码的终极指南,可以让你很快找到一份工作.zip

    在前端部分,现代JavaScript开发离不开React、Vue或Angular这样的库或框架。React以其组件化和虚拟DOM的概念引领了前端开发的新潮流;Vue则以其易学易用和全面的文档受到开发者喜爱;Angular则是Google推出的强大...

    Web开发者的javascript

    - 本书旨在教授读者如何开始使用JavaScript进行实践:了解JavaScript是什么,如何工作,以及可以用来做什么。 - 从基础语法开始,然后学习如何创建强大的Web应用。 Beginning CSS, 2nd Edition - 本书介绍了CSS的...

    2. Javascript全栈-廖雪峰-打印版

    Javascript全栈-廖雪峰-打印版"的压缩包,显然是为那些希望通过阅读纸质版或者PDF版教程来深入学习JavaScript全栈开发的读者准备的。根据描述,打印版特别优化了排版,加入了页边距和页码,这不仅提高了阅读的舒适...

    精通javascript 源代码

    8. **ES6及以后的新特性**:包括箭头函数、模板字符串、解构赋值、类(class)、模块(import/export)、生成器(generator)和async/await等,这些都是现代JavaScript开发的重要组成部分。 9. **前端框架与库**:...

    JavaScript 全部实例代码

    JavaScript,作为全球最广泛...通过深入研究和运行这些实例,你不仅可以提升对JavaScript的理解,还能提升实际开发技能,为成为一名出色的网页开发者做好准备。无论是初学者还是经验丰富的开发者,都能从中受益匪浅。

    用javascript做的51job网站

    8. ES6新特性:现代JavaScript(ES6及以后版本)引入了许多新特性,如箭头函数、模板字符串、let和const声明、解构赋值等,这些都可能在51job网站的源代码中得到应用,提高代码可读性和效率。 9. 轻量级框架或库:...

    零基础学javascript教程附带光盘

    最后,ES6(ECMAScript 2015)及后续版本引入了许多新特性,如模板字符串、解构赋值、类和模块等,这些都是现代JavaScript开发的标准。学习这些新特性,可以使代码更加简洁、易读。 通过这个教程,初学者将逐步掌握...

    javascript做的ui

    JavaScript是一种广泛应用于网页和网络应用开发的脚本语言,它主要负责处理用户交互、操作DOM(文档对象模型)以及...随着技术的不断进步,JavaScript在UI领域的应用只会越来越广泛,成为现代Web开发不可或缺的一部分。

    Qt5与Javascript交互

    这个版本引入了对ES6(ECMAScript 6)的更好支持,包括类、模板字符串、箭头函数等新特性,使得JavaScript代码更加简洁和现代。此外,QtWebEngine还提供了API,使得C++和JavaScript之间可以方便地进行通信,比如使用...

    使用HTML5和JavaScript开发的Canvas Pokémon(宝可梦)游戏(附源码)+可做作业毕设等参考

    使用HTML5和JavaScript开发的Canvas Pokémon游戏(附源码) 项目简介 Canvas Pokémon游戏是使用HTML5、CSS和JavaScript开发的。关于游戏玩法,这是一个使用箭头键控制角色的街机游戏。这个Pokémon游戏的主要...

    vbscript和javascript互相调用方法

    例如,如果你想从VBScript调用一个名为`myFunc`的JavaScript函数,你可以这样做: ```vbscript Dim myObj Set myObj = Server.CreateObject("Scripting.Dictionary") myObj.Language = "JScript" myObj.Add "myFunc...

    javascript学习

    8. **JavaScript工具链**:了解和掌握构建工具(如Webpack、Gulp、Babel)、测试工具(如Jest)、代码质量检查工具(如ESLint)以及模块化系统(如CommonJS、ES模块)是现代JavaScript开发的必备技能。 9. **浏览器...

Global site tag (gtag.js) - Google Analytics