尽管我在生产环境中使用 JavaScript 长达 8 年之久了,但是,直到最近 2 年,我才开始学习如何正确地编写 JavaScript 代码,根据我对人们的理解,很多开发者都有类似经历。我们有相当一部分人用 PHP、ASP 等语言做网站,貌似把 JavaScript 当成了一种补充。然而,随着 NodeJS 的流行以及浏览器的发展,JavaScript 已经冲到了现代前端 web 开发的最前线。

我想在本文分享一些东西,我觉得它们是当今每个开发者都应该充分发挥 JavaScript 优势的技术点。我不是要列出一份详尽的清单,而是尽量遵循我所认为的重要程度进行论述。

JavaScript 诞生于混乱的年代,因此一些好的和坏的特性就构成了这门语言。当你用 JavaScript 和其它语言开发软件时,你会尝到痛苦的教训,然后不得不回头维护(或扩展)所谓的应用程序。没有这个经历,你将很难理解我要说的内容。下面谈谈我所接受的惨痛教训。

1.改变头等函数

头等函数注1将一门编程语言变成了成年人的乐高积木。简而言之,有了头等函数,意味着 JavaScript 能够把函数做为参数传递,还能做为另一个函数的返回值、并赋给变量。这意味着你用很少的代码就能实现非常强大的功能,尤其在函数式编程中。举个实际例子:

1
2
3
4
5
6
7
8
9
10
11
var myArray = [1, 2, 3, 4, 5, 6]
     
var add = function (a, b) {
  return a + b;
};
     
var getTotal = function (arr) {
  return arr.reduce(add, 0);
};
     
getTotal(myArray); // => 21

在第 7 行,我们将一个匿名函数赋给了 getTotal 变量。在第 8 行,我们把 add 函数做为参数传给了 reduce 函数。我们就可以创建更高层次的通用函数,避免了不必要的重复(符合 DRY 原则注2)。我们还能实现复合函数注3,在例子中,我们把 add 函数做为 reduce 的参数,组成了复合函数。

2.学习 Array 的原生方法

我不单单要讨论 Array.prototype.push 或 Array.prototype.splice。映入脑海的还有一些更有用的函数:

和第一个例子一样,你可以在复合函数中使用它们,并组装出某些更加通用、但功能强大的、更高级的函数。大部分应用程序都要涉及数据集的操作,为了取得这些数据,你需要明白有哪些可用的工具,这是及其宝贵的。

3.使用 ES6(ES2015)

箭头函数、let & const、解构、尾调用优化和模板字符串,都属于 ES6 的一些不错的特性。我个人设法避免使用 class 关键字,因为它鼓励类和构造函数的继承,它们更容易引发误用和副作用。

ES6 特性为编写 JavaScript 引入了一种相当新颖的方式,多研究一些细节、探索这些特性,或许是本文的一个部分,我下周可能还会有后续文章。

在浏览器/NodeJS 环境(当写代码时)使用大部分的 ES6 特性,需要用到转码器,相应工具可以访问 https://babeljs.io/。做为一名 web 开发者,我习惯使用 babel 和 browserify,用一条简单命令将 ES6 风格的代码转换成 ES5 的风格:

1
2
npm install -g browserify babelify
browserify -t babelify es6code.js > es5code.js

如果我们用 ES6 重新编写第一个例子中的代码,可能是如下代码:

1
2
3
4
5
const myArray = [1, 2, 3, 4, 5, 6]
const add = (a, b) => a + b;
const getTotal = (arr) => arr.reduce(add, 0);
     
getTotal(myArray); // => 21

代码看起来简洁、直观,这应该足以引起你对 ES6 的兴趣了。但要牢记一点,某些和引擎相关的 ES6 特性,可能无法通过转码器。

4.理解绊脚石:作用域、闭包和类型转换

作用域

描述这个问题的最好方式就是借助一段代码,我打算借鉴 Douglass Crockfords 《JavaScript 语言精粹》上的一个类似例子,因为它非常贴切:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var foo = function () {
  var a = 2,
      b = 4;
    
  var bar = function () {
    var b = 9,
        c = 14;
    // Here: a is 2, b is 9 and c is 14
    
    a = a + b + c;
    // Here: a is 25, b is still 9 and c is still 14
  };
    
  // Here: a is 2, b is 4 and c is undefined
    
  bar();
  // Now: a is 21, b is still 4 and c is still undefined
};

可以看到,你声明变量的位置,和内部函数怎样被定义、以及内部函数怎样引起变量 a 改变其值,存在着关系。对变量声明保持清晰的认识,有助你编写更加可靠的软件。对于函数,要清晰地定义输入和可预期的输出,并尽可能明了。

闭包

闭包是 JavaScript 里保持私有变量的一种绝妙方式,不过,貌似也成了被误解的根源。基本上说,闭包支持你从内部函数去访问外部函数的作用域(又称作用域),类似于上面作用域例子中的 a。就这么简单。有意思的是,当你从外部函数返回一个函数、而内部函数可以访问外部函数的作用域时,内部函数将一直保留外部函数的作用域,哪怕过了整个外部函数的生命期。听起来有些复杂,举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
var outer = function () {
  var a = 1; // variables declared outside of the 'inner' function declaration
  var b = 2;
      
  return function inner() {
    return a; // return 'a' that was defined in the outer function.
    // return b; // We could also access 'b' if we felt like it.
  };
};
    
var inner = outer(); // the outer function returns the inner function
inner(); // => 1 // the inner functions still remembers that 'a' was defined as '1' from the outer function

类型转换

由于 JavaScript 貌似荒谬的类型转换,而带来了很多笑话。为了避免所有让人讨厌的地方,最好使用可信任的 ===,它会在你所期望的大部分情况下,做严格的对象比较。只有一种情况要不好使,当你比较独立的对象字面量时,即使它们具有完全相同的属性和结构,它们也不是相等的,因为它们具有两个完全独立的对象。对于这种情况,只比较对象的每个属性就可以了,像 Underscorejs 之类的资源库就提供了上述情况的深度比较的方法。

5.避免类继承

这或许存在争议,因为软件行业的现状就用到了类继承。我敢说,你用类继承写过某个不错的应用程序,但是,如果你这样做了,那么你可能没有发挥 JavaScript 的优势。借助更加有用的方法,你就能用 JavaScript 写出更加轻量、可维护的应用程序。应用程序逃不掉修改的命运,如果你使用类继承的模式,那么当你用到服务于另一个需求的某个对象时,你将不得不继承随之而来的所有东东。当你想做单元测试时,就更加恶心了,你最终不得不为基类模拟出一整套需求,而你的目标只是为了测试高于继承链之上的简单属性。最好扔掉设计蓝图,根据数据流和对象、而非种类,开始思考你的程序。用这种方式思考,可以极大改善程序的可测试性、可维护性和简洁性。

6.坚持学习,不要失去信心

很多人抱怨 JavaScript 发展太快,有太多的坑,不过,这只是因为人们没有学习这门语言,没有专注于框架。JavaScript 肯定有一些糟粕,但是它也有一些精华,如果你想拥抱正面的东西,那么你就能充分发挥它的优势。我主要做 C# 开发,但是自从我开始正确地学习 JavaScript之后,它就变成了我的首选语言,因为它具备高度灵活的特点。如果你打算一试,那么 JavaScript 就是踏入函数式编程的入门语言,尤其在和 ReactJS 一起使用时。老实讲,我强烈推荐使用 JavaScript 进行函数式编程。

我希望本文有助于传播 JavaScript 优秀的福音,鉴于 JavaScript 的成功,我也想说句公道话,希望其它语言能从中寻找灵感、而不只是维持现状。


传送门:阮一峰《ECMAScript 6简介

充分发挥 JavaScript 语言的优势的更多相关文章

  1. 《JavaScript语言精粹》学习笔记

    一.in的用法 for...in 枚举一个对象的所有可枚举属性 检测DOM/BOM属性 if ("onclick" in elem) { // 元素支持onclick } if ( ...

  2. JavaScript语言精粹 笔记05 正则表达式

    正则表达式 正则表达式以方法的形式被用于对字符串中的信息进行查找.替换画图提取操作.可处理正则表达式的方法有:regexp.exec, regexp.test,string.match, string ...

  3. <JavaScript语言精粹>-读书笔记(一)

    用object.hasOwnProperty(variable)来确定这个属性名是否为该对象成员,还是来自于原型链. for(my in obj){ if(obj.hasOwnProperty(my) ...

  4. 《JavaScript语言精粹》小记

    一.前言 以下内容均摘自<JavaScript语言精粹>一书,本人在读这本书时,发现作者诠释JavaScript很犀利,特别是数组部分,固记录下来,想和大家分享下. 随笔主要包含两大部分: ...

  5. javascript语言精粹

    内容选自:<javascript语言精粹> 1.6种值会为假(==false),分别是false,null,undefined,' ',0,NaN 2.typeof有6种值,分别是'num ...

  6. 前端学习 第三弹: JavaScript语言的特性与发展

    前端学习 第三弹: JavaScript语言的特性与发展 javascript的缺点 1.没有命名空间,没有多文件的规范,同名函数相互覆盖 导致js的模块化很差 2.标准库很小 3.null和unde ...

  7. Javascript 语言精粹 代码片段合集

    Javascript 语言精粹 代码片段合集 标签:Douglas-Crockford Javascript 最佳实践 原文链接 更好的阅读体验 使用一个method 方法定义新方法 Function ...

  8. (转)JavaScript二:JavaScript语言的基本语法要求

    摘自:http://blog.csdn.net/erlian1992 要学习好JavaScript,首先我们要懂JavaScript语言的一些基本语法要求: 一,区分大小写 JavaScript语言区 ...

  9. JavaScript语言精粹笔记

    JavaScript语言精粹笔记 掌握语言的每个特性可以让你出风头,但是并不推荐,因为一部分的特性带来的麻烦可能远超本身的价值.正如书中所言,坏的材料并不能雕刻出好的作品,要成为一名更好的程序员,要取 ...

随机推荐

  1. JS(一)

    循环还是很有意思的: 1) 安全数的作业: <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  2. 高速排序-c++(分别用数组和容器实现)

    /********************************************************************** *版权全部 (C)2014, cheng yang. * ...

  3. 百度之星资格赛 hdu 4826 Labyrinth 动态规划

    /********************* Problem Description 是一仅仅喜欢探险的熊.一次偶然落进了一个m*n矩阵的迷宫,该迷宫仅仅能从矩阵左上角第一个方格開始走,仅仅有走到右上 ...

  4. Android 基于Netty的消息推送方案之字符串的接收和发送(三)

    在上一篇文章中<Android 基于Netty的消息推送方案之概念和工作原理(二)> ,我们介绍过一些关于Netty的概念和工作原理的内容,今天我们先来介绍一个叫做ChannelBuffe ...

  5. jstl经典用法

    jstl的forEach使用和set变量实现自增: <body> <c:set var="index" value="0" /> < ...

  6. Tree( 树) 组件[1]

    本节课重点了解 EasyUI 中 Tree(树)组件的使用方法, 这个组件依赖于 Draggable(拖动)和 Droppable(放置)组件. 一. 加载方式//class 加载方式<ul c ...

  7. C# 无边框窗体移动代码

    C# 无边框窗体移动代码 Point _frmPoint = new Point(); //移动前窗体左上角坐标 Point _mousePoint = new Point(); //按下鼠标时坐标 ...

  8. angular 指令 要点解析

    指令可以删繁就简前端的js代码,杜绝重复的js代码和html代码. 下面就对指令的重要属性进行罗列 一.restrict  =  'AECM'  分别指该指令标识位于 attribute属性: < ...

  9. OC基础 代理和协议

    OC基础 代理和协议 1.协议 (1)oc语言中得协议:一组方法列表,不需要我们自己实现,由遵守协议的类来实现协议所定制的方法. (2)协议的使用步骤:制定协议-->遵守协议-->实现协议 ...

  10. 整理iOS开发常用的第三方资源

    一:第三方插件 1:基于响应式编程思想的oc 地址:https://github.com/ReactiveCocoa/ReactiveCocoa 2:hud提示框 地址:https://github. ...