本文来自这里,翻译过程中加入了译者的理解并作了适当的筛减。
在过去的几年中,JavaScript应用程序在规模和复杂性方面都越来越大。市场上出现了越来越多的单页面应用,并且对这种体验的需求已经达到了促使Google最终决定在爬行页面的过程中考虑支持JavaScript。
对单页面应用的需求,也促使JavaScript架构变得越来越重要。而对于作为动态语言的JavaScript来说,为了保证代码的可维护性、避免代码混乱,你需要做很多额外的工作。
过去很长一段时间中,在一个单一的文件中使用jQuery选择器以及事件处理并没有什么不好。然而,这种方式并不是一种可持续的模式。在23世纪中面临的现代Web,我们需要更多的思考,并且需要通过架构的方式来解决这样的问题。
架构模式
架构模式不是坐下来就能写出来的。不可能坐在那里就能想出如何写出一个很好的模式。模式是在解决问题的过程中发现的。许多问题可以使用同样的方式解决,而模式是从这些解决方案中抽取出来的。
构造器
首先,让我们先看看已存在多年的JavaScript内置的功能——构造器模式
function Starship() {}
在JavaScript声明的所有函数都可以用作构造函数来创建一个实例。这样,就可以创建可重用的函数了。
var enterprise = new Starship(), IKSBuruk = new Starship();
可以修改上面这个函数,给函数传一些参数从而实现更好地描述实例。可以将参数赋值到this的属性上,this将指向由这个构造函数创建的实例。
function Starship(owner, operator, type) { this.owner = owner; this.operator = operator; this.type = type; } var enterprise = new Starship('Federation', 'Star Fleet', 'Class 1 Heavy Cruiser'), birdOfprey = new Starship('Klingon Empire', 'Klingon Imperial Fleet', 'Klingon Warship');
除此之外,还可以使用JavaScript构造函数的一个内置特性——prototype。简单地说,prototype是一个对象。在这个对象上,可以定义一些属性和方法,而这些属性和方法会添加到由该构造函数创建出来的每个实例上。
function Starship(owner, operator, type, weapons) { /* ... */ this.weapons = weapons; } Starship.prototype.fire = function(weapon) { this.weapons[weapon].launch(); }; function PhotonTorpedoSystem() {} PhotonTorpedoSystem.prototype.launch = function() { console.log('launching torpedos'); }; var torpedos = new PhotonTorpedoSystem(), var weaponSystem = { torpedos: torpedos; }; var enterprise = new Starship( 'Federation', 'Star Fleet', 'Class 1 Heavy Cruiser', weaponSystem ); enterprise.fire('torpedos') // launching torpedos;
JavaScript的prototype体系真正重要的是它可以帮助你创建一个继承体系。JavaScript中的继承与其他语言有些许的不同,但通过实践其也不难理解。
function ConstitutionClass(captain, firstOfficer, missionDuration) { this.captain = captain; this.firstOfficer = firstOfficer; this.missionDuration = missionDuration; Starship.apply(this, ['Federation', 'Star Fleet', 'Class 1 Heavy Cruiser', weaponSystem]); } ConstitutionClass.prototype = Object.create(Starship.prototype); ConstitutionClass.prototype.constructor = ConstitutionClass; ConstitutionClass.prototype.warp = function(speed) { console.log('warping at: ' + speed); }; var enterprise = new ConstitutionClass('Kirk', 'Spock', 5); enterprise.fire('torpedos'); // Launching Torpedos enterprise.warp(14.1); // warping at: 14.1
这里,我们创建了ConstitutionClass构造函数。该构造函数接收三个参数captain,firstOfficer和missionDuration。在函数中调用了Starship.apply方法并且传了一个数组参数。这确保了父级构造函数将被调用。
JavaScript中每个函数都有一个call和apply方法,这两个方法允许你通过传入一个上下文来修改函数执行时的上下文,而使用apply方法的话,还需要同时传入一个数组,这个数组包含函数执行时所需的参数。
接下来,为了正确地让ConstitutionClass继承自Starship,我们简单地使用了object.create来赋值给ConstitutionClass的prototype。
这里所做的是告诉ConstitutionClass,将Starship的prototype中所有的属性和方法加到ConstitutionClass的prototype上。
这就是原型链继承。
IIFE避免全局泄漏
需要注意的一点是,上面的代码中存在几个全局泄漏的问题。当你在一个JavaScript文件中简单地声明函数或变量时,这些函数或变量会被添加到全局命名空间上(在浏览器中指的是window)。
下面的代码会创建好几个全局变量:
function PhotonTorpedoSystem() {} PhotonTorpedoSystem.prototype.launch = function() { console.log('launching torpedos'); }; var torpedos = new PhotonTorpedoSystem(), var weaponSystem = { torpedos: torpedos; };
执行这段代码后,会创建window.PhotonTorpedoSystem,window.torpedos,以及window.weaponSystem。这是不好的情形。
为了避免这个问题,一个重要的模式是使用立即执行函数表达式(IIFE,Immediately Invoked Function Expression):
(function(global) { function PhotonTorpedoSystem() {} PhotonTorpedoSystem.prototype.launch = function() { console.log('launching torpedos'); }; var torpedos = new PhotonTorpedoSystem(), var weaponSystem = { torpedos: torpedos; }; /* Create instance of enterprise etc */ global.PhotonTorpedoSystem = PhotonTorpedoSystem; // Export just this to the window }(window));
这里可以看到前面的(function(global) {和后面的}(window));。这就创建了一个匿名的函数并且该函数将被立即执行,同时将global的值设为window。这些都是有效的,因为IIFE创建了一个闭包。在IIFE中定义的一切只包含在那个函数中,除非它被输出到我们定义的global上。
现在,可以显性地在window上设置内容以便在其他的JavaScript文件中也可以使用。
这种方式已经在模式的方向上迈出了正确的一步,但另外一个更好的模式是使用命名空间的模式:
// weaponSystems.js (function(global, NS) { NS.Weapons = NS.Weapons || {}; function PhotonTorpedoSystem() {} PhotonTorpedoSystem.prototype.launch = function() { console.log('launching torpedos'); }; /* ... */ NS.Weapons.PhotonTorpedoSystem = PhotonTorpedoSystem; // Export just this to the NS.Weapons namespace }(window, window.NS = NS || {});
注意到这里我们将前面IIFE的最后一行的代码改成了}(window, window.NS = NS || {});。这样就会给函数传入window和NS对象。这里稍微有点怪的写法是说,“如果NS存在则直接传进入,如果NS还不存在则为它创建一个新的对象”。
你也可以这样使用这种语法,如NS.Weapons = NS.Weapons || {};
它跟下面的if语句是一样的,只不过这种写法更加简洁:
if (!NS.Weapons) { NS.Weapons = {}; }
你可以向命名空间上添加任何对象和函数。这种方式使你避免了添加太多的全局变量到window上。
(function(global, NS) { NS.Ships = NS.Ships || {}; function Starship(owner, operator, type, weapons) { /* ... */ } function ConstitutionClass(captain, firstOfficer, missionDuration) { /* ... */ } /* ... */ NS.Ships.Starship = Starship; NS.Ships.ConstitutionClass = ConstitutionClass; }(window, window.NS = NS || {});
相关推荐
世纪高等学校计算机规划教材JavaScript正则表达式PPT学习教案.pptx
效果展示: ... 现在,虽然仍在game文件夹中,但在同一位置打开另一个终端会话。键入并运行npm run dev:node.... 如果要调试,请键入npm run ndb....强烈推荐一个更轻松的时间。...更多详情、使用方法,请下载后阅读README.md...
在20世纪90年代,也就是早期的WEB站点上,所有的网页内容都是静态的,所谓静态是指,除了点击超链接,你无法通过任何方式同页面进行交互,比 如让页面元素接受事件,修改字体等。人们于是迫切的需要一种方式来打破这...
下载后 cd game npm install npm run serve 当仍在游戏文件夹中时,在同一位置打开另一个终端会话。键入并运行npm run dev:node。启动节点。js游戏服务器。 如果要调试,请键入npm run ndb。ndb是Google Chrome的...
此参考是依照 JavaScript 语言的功能组织的。有时你已经知道了某个对象或方法的名称,但是不太清楚要在哪里能够找到它。这一章包含了解决此种情况的链接表。 轻松上手 本书是 JavaScript 语言的参考手册,包括核心...
利肯精简 Javascript 实现。 这是前阿尔法的方式。 只是在胡闹。
该课程体系通过结合先进的多模式教学法,使学习者在掌握理论知识与工具的同时,具备良好的自我学习能力和个人素质,成为符合21世纪企业要求的IT人才。 ACCP 6.0是北大青鸟APTECH推出的最新软件工程师职业教育课程...
javascript农历,支持自定义日期、默认当前日期、自定义格式输出,内附说明文档及示例代码
使用JavaScript和HTML5的在线2D中世纪游戏。 入门 首先,派生存储库。 然后,进入您喜欢的终端。 git clone git@github.com:YOUR_USERNAME/game.git cd game npm install npm run serve npm run serve将启动开发...
1. 什么是JSON JSON—Javascript Object Notation,前两个单词大家应该都认识,最后一个notation...在21世纪初,Douglas Crockford(Web开发领域最知名的技术权威之一,ECMA JavaScript2.0标准化委员会委员,被JavaScr
想象一个中世纪的世界,其中的魔法由…… JavaScript 组成。 一个魔法的世界,其中包括无休止地改变宇宙的密码。 Spegularo 旨在成为一款类似 rogue 的游戏,您将在其中更改自己的代码来完成自己的命运。 与 ...
上古世纪官网jquery焦点图代码,兼容 IE 789 及其它主流浏览器 ,因 IE 6 不支持CSS透明属性(opacity)故在IE 6下无图片淡入淡出效果
P4wn,一个小巧的Javascript国际象棋引擎P4wn既是一个在线网页又是一个离线HTML移动和平板电脑应用程序,都可以下棋。 它很小,可以很好地发挥作用,而且很容易嵌入到您的页面中。 默认界面易于替换,引擎简单易用。...
JS.project.medieval-meme.matcher:使用JavaScript,CSS和HTML的中世纪Meme记忆游戏
上古世纪jQ焦点图 腾讯上古世纪jQuery焦点图代码下载.zip
创世纪JS /没有JS 根据是否启用JavaScript,使Genesis Framework上的子主题的前端样式更容易。 描述 如果您查看WordPress后端页面的源代码,则会看到它的主体类为no-js 。 在开始body标签之后紧随其后的是一个小脚...
这就是21世纪负载测试的外观。 菜单 特征 ES6 JS中的脚本:支持以帮助组织中的代码重用 一切都作为代码:测试逻辑和都在JS中,以实现版本控制的友好性 自动化友好:(如断言)和以轻松灵活地配置CI! , , 和协议...
世纪项目用的日期控件很好用,在前台使用的JAVASRIPT,可以适应各种项目
strftime() JavaScript端口,用于格式化日期和时间的函数。支持的转换规格: 顺序描述%a 星期几的缩写名称。 %A 星期几的全名。 %b 缩写的月份名称。 %B 完整的月份名称。 %c 当前语言环境的首选日期和时间(UTC)...
WordPress创世纪儿童主题设置可使用Bootstrap 3,Sass和Grunt。 贡献者 , , , CSS不见了 我收到很多用户的来信,“嘿,我尝试使用您的主题,但是没有CSS。” 快速解决 下载最新的并使用它。 长版 这是我用于...