【ES6】阮一峰ES6学习之编程风格
编程风格
- 1. 块级字符串
- 1. let 取代 var
- 2. 全局常量和线程安全
- 2. 字符串
- 3. 解构赋值
- 4. 对象
- 5. 数组
- 6. 函数
- 7. Map 结构
- 8. Class
- 9. 模块
1. 块级字符串
1. let 取代 var
ES6 提出了两个新的声明变量的命令:let
和const
。其中,let完全可以取代var
,因为两者语义相同,而且let
没有副作用。
'use strict';if (true) {let x = 'hello';
}for (let i = 0; i < 10; i++) {console.log(i);
}
上面代码如果用var
替代let
,实际上就声明了两个全局变量,这显然不是本意。变量应该只在其声明的代码块内有效,var
命令做不到这一点。
var
命令存在变量提升效用,let
命令没有这个问题。
'use strict';if (true) {console.log(x); // ReferenceErrorlet x = 'hello';
}
上面代码如果使用var
替代let
,console.log
那一行就不会报错,而是会输出undefined
,因为变量声明提升到代码块的头部。这违反了变量先声明后使用的原则。
所以,建议不再使用var
命令,而是使用let
命令取代。
2. 全局常量和线程安全
在let
和const
之间,建议优先使用const
,尤其是在全局环境,不应该设置变量,只应设置常量。
const
优于let
有几个原因。一个是const
可以提醒阅读程序的人,这个变量不应该改变;另一个是const
比较符合函数式编程思想,运算不改变值,只是新建值,而且这样也有利于将来的分布式运算;最后一个原因是 JavaScript
编译器会对const
进行优化,所以多使用const
,有利于提高程序的运行效率,也就是说let
和const
的本质区别,其实是编译器内部的处理不同。
// bad
var a = 1, b = 2, c = 3;// good
const a = 1;
const b = 2;
const c = 3;// best
const [a, b, c] = [1, 2, 3];
const
声明常量还有两个好处,一是阅读代码的人立刻会意识到不应该修改这个值,二是防止了无意间修改变量值所导致的错误。
所有的函数都应该设置为常量。
长远来看,JavaScript
可能会有多线程的实现(比如 Intel 公司的 River Trail 那一类的项目),这时let表示的变量,只应出现在单线程运行的代码中,不能是多线程共享的,这样有利于保证线程安全。
2. 字符串
静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。
// bad
const a = "foobar";
const b = 'foo' + a + 'bar';// acceptable
const c = `foobar`;// good
const a = 'foobar';
const b = `foo${a}bar`;
3. 解构赋值
使用数组成员对变量赋值时,优先使用解构赋值。
const arr = [1, 2, 3, 4];// bad
const first = arr[0];
const second = arr[1];// good
const [first, second] = arr;
函数的参数如果是对象的成员,优先使用解构赋值。
// bad
function getFullName(user) {const firstName = user.firstName;const lastName = user.lastName;
}// good
function getFullName(obj) {const { firstName, lastName } = obj;
}// best
function getFullName({ firstName, lastName }) {}
如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序。
// bad
function processInput(input) {return [left, right, top, bottom];
}// good
function processInput(input) {return { left, right, top, bottom };
}const { left, right } = processInput(input);
4. 对象
单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾。
// bad
const a = { k1: v1, k2: v2, };
const b = {k1: v1,k2: v2
};// good
const a = { k1: v1, k2: v2 };
const b = {k1: v1,k2: v2,
};
对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用Object.assign
方法。
// bad
const a = {};
a.x = 3;// if reshape unavoidable
const a = {};
Object.assign(a, { x: 3 });// good
const a = { x: null };
a.x = 3;
如果对象的属性名是动态的,可以在创造对象的时候,使用属性表达式定义。
// bad
const obj = {id: 5,name: 'San Francisco',
};
obj[getKey('enabled')] = true;// good
const obj = {id: 5,name: 'San Francisco',[getKey('enabled')]: true,
};
上面代码中,对象obj的最后一个属性名,需要计算得到。这时最好采用属性表达式,在新建obj的时候,将该属性与其他属性定义在一起。这样一来,所有属性就在一个地方定义了。
另外,对象的属性和方法,尽量采用简洁表达法,这样易于描述和书写。
var ref = 'some value';// bad
const atom = {ref: ref,value: 1,addValue: function (value) {return atom.value + value;},
};// good
const atom = {ref,value: 1,addValue(value) {return atom.value + value;},
};
5. 数组
使用扩展运算符(...)
拷贝数组。
// bad
const len = items.length;
const itemsCopy = [];
let i;for (i = 0; i < len; i++) {itemsCopy[i] = items[i];
}// good
const itemsCopy = [...items];
使用 Array.from
方法,将类似数组的对象转为数组。
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
6. 函数
立即执行函数可以写成箭头函数的形式。
(() => {console.log('Welcome to the Internet.');
})();
那些使用匿名函数当作参数的场合,尽量用箭头函数代替。因为这样更简洁,而且绑定了 this。
// bad
[1, 2, 3].map(function (x) {return x * x;
});// good
[1, 2, 3].map((x) => {return x * x;
});// best
[1, 2, 3].map(x => x * x);
箭头函数取代Function.prototype.bind
,不应再用 self/_this/that
绑定 this
。
// bad
const self = this;
const boundMethod = function(...params) {return method.apply(self, params);
}// acceptable
const boundMethod = method.bind(this);// best
const boundMethod = (...params) => method.apply(this, params);
简单的、单行的、不会复用的函数,建议采用箭头函数。如果函数体较为复杂,行数较多,还是应该采用传统的函数写法。
所有配置项都应该集中在一个对象,放在最后一个参数,布尔值不可以直接作为参数。
// bad
function divide(a, b, option = false ) {}// good
function divide(a, b, { option = false } = {}) {}
不要在函数体内使用 arguments
变量,使用 rest
运算符(...)
代替。因为rest
运算符显式表明你想要获取参数,而且 arguments
是一个类似数组的对象,而 rest
运算符可以提供一个真正的数组。
// bad
function concatenateAll() {const args = Array.prototype.slice.call(arguments);return args.join('');
}// good
function concatenateAll(...args) {return args.join('');
}
使用默认值语法设置函数参数的默认值。
// bad
function handleThings(opts) {opts = opts || {};
}// good
function handleThings(opts = {}) {// ...
}
7. Map 结构
注意区分 Object
和 Map
,只有模拟现实世界的实体对象时,才使用 Object
。如果只是需要key: value
的数据结构,使用 Map
结构。因为 Map
有内建的遍历机制。
let map = new Map(arr);for (let key of map.keys()) {console.log(key);
}for (let value of map.values()) {console.log(value);
}for (let item of map.entries()) {console.log(item[0], item[1]);
}
8. Class
总是用 Class
,取代需要 prototype
的操作。因为 Class
的写法更简洁,更易于理解。
// bad
function Queue(contents = []) {this._queue = [...contents];
}
Queue.prototype.pop = function() {const value = this._queue[0];this._queue.splice(0, 1);return value;
}// good
class Queue {constructor(contents = []) {this._queue = [...contents];}pop() {const value = this._queue[0];this._queue.splice(0, 1);return value;}
}
使用extends
实现继承,因为这样更简单,不会有破坏instanceof
运算的危险。
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function() {return this._queue[0];
}// good
class PeekableQueue extends Queue {peek() {return this._queue[0];}
}
9. 模块
ES6 模块语法是 JavaScript 模块的标准写法,坚持使用这种写法,取代 Node.js
的 CommonJS
语法。
首先,使用import
取代require()
。
// CommonJS 的写法
const moduleA = require('moduleA');
const func1 = moduleA.func1;
const func2 = moduleA.func2;// ES6 的写法
import { func1, func2 } from 'moduleA';
其次,使用export取代module.exports。
// commonJS 的写法
var React = require('react');var Breadcrumbs = React.createClass({render() {return <nav />;}
});module.exports = Breadcrumbs;// ES6 的写法
import React from 'react';class Breadcrumbs extends React.Component {render() {return <nav />;}
};export default Breadcrumbs;
如果模块只有一个输出值,就使用export default
,如果模块有多个输出值,除非其中某个输出值特别重要,否则建议不要使用export default
,即多个输出值如果是平等关系,export default
与普通的export
就不要同时使用。
如果模块默认输出一个函数,函数名的首字母应该小写,表示这是一个工具方法。
function makeStyleGuide() {}export default makeStyleGuide;
如果模块默认输出一个对象,对象名的首字母应该大写,表示这是一个配置值对象。
const StyleGuide = {es6: {}
};export default StyleGuide;
【ES6】阮一峰ES6学习之编程风格相关推荐
- 阮一峰es6电子书_ES6理解进阶【大前端高薪训练营】
一:面向对象:类class 面向对象三大特性之封装 封装是面向对象的重要原则,它在代码中的体现主要是以下两点: 封装整体:把对象的属性和行为封装为一个整体,其中内部成员可以分为静态成员(也叫类成员)和 ...
- 阮一峰ES6入门读书笔记(七):运算符的拓展
阮一峰ES6入门读书笔记(七):运算符的拓展 1. 指数运算符 ES6新增了一个指数运算符(**). 2 ** 2 // 4 2 ** 3 // 8 这个运算符的一个特点是右结合,而不是常见的左结合. ...
- 阮一峰ES6入门读书笔记(十六):Moudle
阮一峰ES6入门读书笔记(十六):Moudle 在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种.前者用于服务器,后者用于浏览器.ES6 在语言标准的层面上 ...
- 【ES6】阮一峰ES6学习之迭代器和for...of循环
迭代器和for...of循环 1. 迭代器 1. 概念 2. 工作原理 3. 默认 Iterator 接口 4. 调用 Iterator 接口的场合 (1)解构赋值 (2) 扩展运算符 (3) yie ...
- js -- ES6(一)-- 简介(根据阮一峰ES6标准入门整理)
目前正在学习ES6,根据阮一峰的ES6入门2,学到哪更新到哪里,都是基本的知识,复杂的目前还不会,涉及的代码都是亲自运行过的,若发现错误请指正. ES6 提供了许多新特性,但是并不是所有的浏览器都能够 ...
- 阮一峰 / ES6 数组的解构赋值
目录 一.定义 二.详情讲解 1.数组解构:数组解构时数组的元素是按次序排列的,变量的取值由它的位置决定 2.对象解构:对象解构时对象的属性没有次序,变量必须与属性同名,才能取到正确的值. 三.用途 ...
- 实现阮一峰ES6的顶部加载条效果
效果例子 阮一峰的ES6:http://es6.ruanyifeng.com/?search=s&x=13&y=3 html + css <style type="te ...
- 【ES6】阮一峰ES6学习之Class(一)
Class的基本用法 1. 类的由来 2. constructor() 方法 3. 类的实例 4. 取值函数(getter)和存值函数(setter) 5. 静态方法 6. 私有方法和私有属性 7. ...
- 【ES6】阮一峰ES6学习之Promise(一)
Promise 一.含义 1. 概念 2. 特点 3. 基本用法 4. 为什么要用 Promise 1. 指定回调函数的方式更加灵活 2. 支持链式调用,可以解决回调地狱的问题 用Promise实现A ...
最新文章
- 查理芒格+终身学习+你的认知就是你的财富的边界
- 技术团队,你欠了一屁股债你造吗?
- linux编译c++ 静态库,C/C++ 条件编译静态库
- 教育|仝卓高考舞弊案细节曝光:为“恢复高考成绩”已起诉1年多
- armbian php ldap,N1刷Armbian后刷Seafile7.1.5做家庭云盘提要
- Mysql 索引是如何实现的?
- linux,centos7环境下,安装RabbitMQ
- java实现文件压缩打包(zip打包)(文件相关二)
- sql server 2000 个人版怎么在win7下安装
- FPGA与ASIC对比
- 2022年后人工智能八大应用方向
- 新学期新FLAG,我与你共青春
- 字符串折叠、涂色问题
- 什么叫域名解析SSL证书?
- [转]科普 | 什么是宽表?
- MIXLAB_NASA_TICKET生成
- 网站运营活跃用户、流失用户、流失率、新用户流失率定义以及诠释
- 【英语做题】英语“八股文“学习
- 云数据库CynosDB有哪些常见问题?
- Java中StringBuffer的相关运用与实践