[译] You Might Not Use ES6

箭头函数

与函数表达式相比,箭头函数表达式(也称为胖箭头函数)的语法更简介,并且不会创建自己的 this
箭头函数相当于匿名函数。

ES6:

[1, 2, 3].map(n => n * 2);
// -> [ 2, 4, 6 ]

ES5 实现:

[1, 2, 3].map(function(n) { return n * 2; }, this);
// -> [ 2, 4, 6 ]

ES6:

var evens = [2, 4, 6, 8, 10];

// 表达式正文
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);

console.log(odds);
// -> [3, 5, 7, 9, 11]

console.log(nums);
// -> [2, 5, 8, 11, 14]

// 声明式正文
var fives = [];
nums = [1, 2, 5, 15, 25, 32];
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});

console.log(fives);
// -> [5, 15, 25]

// 作用域中的 this
var bob = {
  _name: 'Bob',
  _friends: [],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + ' knows ' + f));
  }
}

ES5:

'use strict';

var evens = [2, 4, 6, 8, 10];

// 表达式正文
var odds = evens.map(function (v) {
  return v + 1;
}, this);
var nums = evens.map(function (v, i) {
  return v + i;
}, this);

console.log(odds);
// -> [3, 5, 7, 9, 11]

console.log(nums);
// -> [2, 5, 8, 11, 14]

var fives = [];
nums = [1, 2, 5, 15, 25, 32];

// 声明式正文
nums.forEach(function (v) {
  if (v % 5 === 0) {
    fives.push(v);
  }
}, this);

console.log(fives);
// -> [5, 15, 25]

// Lexical this
var bob = {
  _name: 'Bob',
  _friends: [],
  printFriends: function printFriends() {
    this._friends.forEach(function (f) {
      return console.log(this._name + ' knows ' + f);
    }, this);
  }
};

块级作用域函数

块作用域绑定提供了函数和顶级作用域以外的作用域。
这确保你的变量不会超出他们定义的范围内。

ES6:

// let 声明一个局部块作用域,在 ES6 中可以任意的初始化一个值

'use strict';

var a = 5;
var b = 10;

if (a === 5) {
  let a = 4; // 作用域在 if 块中
  var b = 1; // 作用域在函数内部

  console.log(a);  // 4
  console.log(b);  // 1
}

console.log(a); // 5
console.log(b); // 1

ES5:

'use strict';

var a = 5;
var b = 10;

if (a === 5) {
  // 在实现上更像下面这样
  (function () {
    var a = 4;
    b = 1;

    console.log(a); // 4
    console.log(b); // 1
  })();
}

console.log(a); // 5
console.log(b); // 1

ES6:

// const 在 ES6 中创建只读的属性常量
'use strict';
// 将 favorite 定义为常量并且赋值为 7
const favorite = 7;
// 试图覆盖常量
try {
  favorite = 15;
} catch (err) {
  console.log('my favorite number is still: ' + favorite);
  // 仍然会输出 7
}

ES5:

'use strict';
// 将 favorite 定义为一个不可写的“常量”,并将其赋值为 7。
Object.defineProperties(window, {
  favorite: {
    value: 7,
    enumerable: true
  }
});
// 属性描述默认为 false,并且 const 是可枚举的
var favorite = 7;
// 试图覆盖常量
favorite = 15;
// 仍然会输出 7
console.log('my favorite number is still: ' + favorite);

模版字符串

ES6 模版字符串是可以包含嵌入表达式的字符串,有时也被叫做插值表达式

ES6:

// 表达式占位符的基本用法
var person = 'Addy Osmani';
console.log(`Yo! My name is ${person}!`);

// 表达式也可以用在对象中
var user = {name: 'Caitlin Potter'};
console.log(`Thanks for getting this into V8, ${user.name}.`);

// 插值表达式:作用之一可以用来计算
var a = 50;
var b = 100;
console.log(`The number of JS frameworks is ${a + b} and not ${2 * a + b}.`);

// 多行字符串不需要换行符
console.log(`string text line 1
string text line 2`);

// 函数内部表达式
function fn() { return 'result'; }
console.log(`foo ${fn()} bar`);

ES5:

'use strict';

// 表达式占位符的基本用法
var person = 'Addy Osmani';
console.log('Yo! My name is ' + person + '!');

// 表达式也可以用在对象中
var user = { name: 'Caitlin Potter' };
console.log('Thanks for getting this into V8, ' + user.name + '.');

// 插值表达式:作用之一可以用来计算
var a = 50;
var b = 100;
console.log('The number of JS frameworks is ' + (a + b) + ' and not ' + (2 * a + b) + '.');

// 多行字符串
console.log('string text line 1\nstring text line 2');
// 或者下面这种写法
console.log('string text line 1\n\
string text line 2');

// 函数内部表达式
function fn() {
  return 'result';
}
console.log('foo ' + fn() + ' bar');

计算属性

计算属性名允许你基于表达式在对象文本中指定属性

ES6:

var prefix = 'foo';
var myObject = {
  [prefix + 'bar']: 'hello',
  [prefix + 'baz']: 'world'
};

console.log(myObject['foobar']);
// -> hello
console.log(myObject['foobaz']);
// -> world

ES5:

'use strict';

var prefix = 'foo';
var myObject = {};

myObject[prefix + 'bar'] = 'hello';
myObject[prefix + 'baz'] = 'world';

console.log(myObject['foobar']);
// -> hello
console.log(myObject['foobaz']);
// -> world

解构赋值

解构赋值语法是一个JavaScript表达式,它可以使用数组映射和对象文本构造的语法从数组和对象中提取值,对变量进行赋值。

ES6:

var {foo, bar} = {foo: 'lorem', bar: 'ipsum'};
// foo => lorem and bar => ipsum

ES5:

'use strict';

var _ref = { foo: 'lorem', bar: 'ipsum' };

// foo => lorem and bar => ipsum
var foo = _ref.foo;
var bar = _ref.bar;

ES3:

with({foo: 'lorem', bar: 'ipsum'}) {
  // foo => lorem and bar => ipsum
}

ES6:

var [a, , b] = [1,2,3];

ES6 (shimming using Symbol.iterator):

'use strict';

var _slicedToArray = function (arr, i) {
  if (Array.isArray(arr)) {
    return arr;
  } else {
    var _arr = [];

    for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
      _arr.push(_step.value);

      if (i && _arr.length === i) {
        break;
      }
    }

    return _arr;
  }
};

var _ref = [1, 2, 3];

var _ref2 = _slicedToArray(_ref, 3);

var a = _ref2[0];
var b = _ref2[2];

ES5:

String.prototype.asNamedList = function () {
  return this.split(/\s*,\s*/).map(function (name, i) {
    return name ? ('var ' + name + '=slice(' + i + ', ' + (i + 1) + ')[0]') : '';
  }).join(';');
};

with([1,2,3]) {
  eval('a, , b'.asNamedList());
}

默认参数

默认参数允许函数具有可选参数,而不需要检查参数的长度或是否未定义。

ES6:

function greet(msg='hello', name='world') {
  console.log(msg,name);
}

greet();
// -> hello world
greet('hey');
// -> hey world

ES5:

'use strict';

function greet() {
  // 如果像这样访问 arguments[0],则可以简单地进行访问 msg 变量名
  var msg = arguments[0] === undefined ? 'hello' : arguments[0];
  var name = arguments[1] === undefined ? 'world' : arguments[1];
  console.log(msg, name);
}

function greet(msg, name) {
  (msg === undefined) && (msg = 'hello');
  (name === undefined) && (name = 'world');
  console.log(msg,name);
}

// 对未定义的参数进行检查的基本方法
function greet(msg, name) {
  console.log(
    defaults(msg, 'hello'),
    defaults(name, 'world')
  );
}

greet();
// -> hello world
greet('hey');
// -> hey world

ES6:

function f(x, y=12) {
  // y 的指是 12 如果没有接收(或者接收的是 undefined )
  return x + y;
}

f(3) === 15;

ES5:

'use strict';

function f(x, y) {
  if (y === undefined) {
    y = 12;
  }

  return x + y;
}

f(3) === 15;

Iterators 和 For-Of 循环

遍历器是可以遍历容器的对象。这是一种使类工作在for..of循环的有用方法。
接口类似于遍历器接口。
迭代一个for..of循环的形式如下。

ES6:

// 当前环境,将从数组中获取一个遍历器,并对其进行循环,从中获取值
for (let element of [1, 2, 3]) {
  console.log(element);
}
// => 1 2 3

ES6 (without using for-of, if Symbol is supported):

'use strict';

for (var _iterator = [1, 2, 3][Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
  var element = _step.value;
  console.log(element);
}

// => 1 2 3

ES5 (approximates):

// 使用 forEach()
// 不需要在包含的范围中声明索引和元素变量。它们被作为参数提供给遍历器,并被限定在遍历的范围内。
var a = [1,2,3];
a.forEach(function (element) {
    console.log(element);
});

// => 1 2 3

// 使用  for 循环
var a = [1,2,3];
for (var i = 0; i < a.length; ++i) {
    console.log(a[i]);
}
// => 1 2 3

注意Symbol的使用。ES5 需要一个正确的Symbol polyfill才能正常使用。

Class

class 实现了 ES6 规范草案中描述的类语法和语义。
class 是复用代码最好的方法。
一些 JS 库提供了类和继承,但它们并不相互兼容。

ES6:

class Hello {
  constructor(name) {
    this.name = name;
  }

  hello() {
    return 'Hello ' + this.name + '!';
  }

  static sayHelloAll() {
    return 'Hello everyone!';
  }
}

class HelloWorld extends Hello {
  constructor() {
    super('World');
  }

  echo() {
    alert(super.hello());
  }
}

var hw = new HelloWorld();
hw.echo();

alert(Hello.sayHelloAll());

ES5 ( 类似功能 ):

function Hello(name) {
  this.name = name;
}

Hello.prototype.hello = function hello() {
  return 'Hello ' + this.name + '!';
};

Hello.sayHelloAll = function () {
  return 'Hello everyone!';
};

function HelloWorld() {
  Hello.call(this, 'World');
}

HelloWorld.prototype = Object.create(Hello.prototype);
HelloWorld.prototype.constructor = HelloWorld;
HelloWorld.sayHelloAll = Hello.sayHelloAll;

HelloWorld.prototype.echo = function echo() {
  alert(Hello.prototype.hello.call(this));
};

var hw = new HelloWorld();
hw.echo();

alert(Hello.sayHelloAll());

更详细的介绍可以查看 Babel

Modules

模块功能大部分是实现了,一些加载api仍然在改进中。
模块试图解决依赖关系和部署中的许多问题,允许用户使用显式导出创建模块,从这些模块中导入特定的导出名称,并保持这些名称的独立性。

app.js - ES6

import math from 'lib/math';
console.log('2π = ' + math.sum(math.pi, math.pi));

app.js - ES5

var math = require('lib/math');
console.log('2π = ' + math.sum(math.pi, math.pi));

lib/math.js - ES6

export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;

lib/math.js - ES5

exports.sum = sum;
function sum(x, y) {
  return x + y;
}
var pi = exports.pi = 3.141593;

lib/mathplusplus.js - ES6

export * from 'lib/math';
export var e = 2.71828182846;
export default function(x) {
  return Math.exp(x);
}

lib/mathplusplus.js - ES5

var Math = require('lib/math');

var _extends = function (target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      target[key] = source[key];
    }
  }

  return target;
};

var e = exports.e = 2.71828182846;
exports['default'] = function (x) {
  return Math.exp(x);
};

module.exports = _extends(exports['default'], exports);

数字字面量

ES6:

var binary = [
  0b0,
  0b1,
  0b11
];
console.assert(binary === [0, 1, 3]);

var octal = [
  0o0,
  0o1,
  0o10,
  0o77
];
console.assert(octal === [0, 1, 8, 63]);

ES5:

'use strict';

var binary = [0, 1, 3];
console.assert(binary === [0, 1, 3]);

var octal = [0, 1, 8, 63];
console.assert(octal === [0, 1, 8, 63]);

属性赋值方法

对象中支持方法语法, 比如说 toString()

ES6:

var object = {
  value: 42,
  toString() {
    return this.value;
  }
};

console.log(object.toString() === 42);
// -> true

ES5:

'use strict';

var object = {
  value: 42,
  toString: function toString() {
    return this.value;
  }
};

console.log(object.toString() === 42);
// -> true

对象属性的简介表示

在对象中的属性名和属性值相同时可以忽略属性值。

ES6:

function getPoint() {
  var x = 1;
  var y = 10;

  return {x, y};
}

console.log(getPoint() === {
  x: 1,
  y: 10
});

ES5:

'use strict';

function getPoint() {
  var x = 1;
  var y = 10;

  return { x: x, y: y };
}

console.log(getPoint() === {
  x: 1,
  y: 10
});

Rest 参数

rest 参数允许函数在不使用 arguments 对象的情况下具有可变数量的参数。
rest 参数是数组的一个实例,因此所有的数组方法都可以使用。

ES6:

function f(x, ...y) {
  // y 是个数组
  return x * y.length;
}

console.log(f(3, 'hello', true) === 6);
// -> true

ES5:

'use strict';

function f(x) {
  var y = [];
  y.push.apply(y, arguments) && y.shift();

  // y 是个数组
  return x * y.length;
}

console.log(f(3, 'hello', true) === 6);
// -> true

扩展运算符

扩展运算符是和 rest 参数相反的。
它允许将数组展开为多个形式的参数。

ES6:

function add(a, b) {
  return a + b;
}

let nums = [5, 4];

console.log(add(...nums));

ES5:

'use strict';

var _toArray = function (arr) {
  return Array.isArray(arr) ? arr : [].slice.call(arr);
};

function add(a, b) {
  return a + b;
}

var nums = [5, 4];
console.log(add.apply(null, _toArray(nums)));

ES6:

function f(x, y, z) {
  return x + y + z;
}
// 传递数组的每一个参数
f(...[1,2,3]) === 6;

ES5:

'use strict';

function f(x, y, z) {
  return x + y + z;
}
// 传递数组的每一个参数
f.apply(null, [1, 2, 3]) === 6;

Proxy

ES6:

var target = function () {
  return 'I am the target';
};

var handler = {
  apply: function (receiver, ...args) {
    return 'I am the proxy';
  }
};

var p = new Proxy(target, handler);
console.log(p() === 'I am the proxy');
// -> true

ES5:

在 ES5 中没有 proxy, 没有类似的方法去拦截。

类数组

Array.from 使有着单一的参数类数组或者列表(像:arguments, NodeList, DOMTokenList(当做classList),NamedNodeMap(属性使用))返回一个新的数组实例。

ES6:

var listFriends = function() {
  var friends = Array.from(arguments);
  friends.forEach(friend => {
    console.log(friend);
  });
};
listFriends('ann', 'bob');
// -> 'ann'
// -> 'bob'

var divs = document.querySelectorAll('div');
Array.from(divs).forEach(node => {
    console.log(node);
});
// -> <div>...</div>
// -> <div>...</div>

ES5:

var listFriends = function() {
  var friends = [].slice.call(arguments)
  friends.forEach(function(friend) {
    console.log(friend);
  });
};
listFriends('ann', 'bob');
// -> 'ann'
// -> 'bob'

var divsArray = [].slice.call(document.querySelectorAll('div'));
divsArray.forEach(function(node) {
    console.log(node);
});
// -> <div>...</div>
// -> <div>...</div>

参考

重点

如果有错误或者错别字,还请给我留言指出,谢谢。

我们下期见。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • [TOC] 参考阮一峰的ECMAScript 6 入门参考深入浅出ES6 let和const let和const都...
    郭子web阅读 1,773评论 0 1
  • 一、ES6简介 ​ 历时将近6年的时间来制定的新 ECMAScript 标准 ECMAScript 6(亦称 ...
    一岁一枯荣_阅读 6,065评论 8 25
  • 本文为阮一峰大神的《ECMAScript 6 入门》的个人版提纯! babel babel负责将JS高级语法转义,...
    Devildi已被占用阅读 1,972评论 0 4
  • 第一章:块级作用域绑定 块级声明 1.var声明及变量提升机制:在函数作用域或者全局作用域中通过关键字var声明的...
    BeADre_wang阅读 825评论 0 0
  • 今天在上班的途中,接到我们家委会主任的电话让我和儿子一起准备开学后家长节表演的节目。 刚开始报名的时,我就想要儿子...
    心如大海建英阅读 151评论 0 0