你的位置:首页 > Java教程

[Java教程]ES6扫盲


 原文阅读请点击此处

一、let和const

复制代码
{  // let声明的变量只在let命令所在的代码块内有效  let a = 1;  var b = 2;}console.log(a);   // 报错: ReferenceError: a is not definedconsole.log(b);
复制代码

// for循环的技术器就很适合let命令for (let i = 0; i < 3; i++) {  console.log(i);}console.log(i); // ReferenceError: i is not defined

复制代码
// 这里的i是var声明的,在全局范围内有效,素偶一每一次循环,新的i值都会覆盖旧值,导致最后输出的是最后一轮的i值for (var i = 0; i < 10; i++) {  a[i] = function() {    console.log(i);  }}a[6](); // 10var b = [];// 使用let声明的变量尽在块级作用域内有效,所以每一次循环的j其实都是一个新的变量,于是最后输出6for (let j = 0; j < 10; j++) {  a[j] = function() {    console.log(j);  }}b[6]();
复制代码

复制代码
// let不像var那样会发生"变量"提升的现象// 但是经过babel转换器转换之后,还是存在变量提升的现象// ES6明确规定,如果区块中存在let和const命令,则这个区块中对这些命令声明的变量从一开始就形成封闭作用域.只要在声明这些变量之前就使用这些变量,就会报错{  console.log(foo);  // ReferenceError  let foo = 2;}// 块级作用域{  // 块级作用域的出现使得获得广泛应用的立即执行匿名函数(IIFE)不再必要了  // IIFE写法  (function() {    var tmp = 'a';    // ...  })();  // 块级作用域写法  {    let tmp = 'a';    // ...  }  // 因此,我们可以使用块级作用域来划分业务模块,以及避免全局变量}{  let a = 'secret';  function f() {    return a;  }}f();  // 报错
复制代码

// const声明的常量不得改变值// const一旦声明常量,就必须立即初始化,不能留到以后赋值// const的作用域与let命令相同:只在声明所在的块级作用域内有效// const命令声明的变量也不提升,只能声明后使用const foo = 'AAA';foo = 'BBB';  // 编译不通过

复制代码
{  // 跨模块常量  // constants.js  //export const A = 1;  //export const B = 2;  //export const C = 3;  // test1.js模块  //import * as constants from 'constants';  }
复制代码

// 全局对象的属性var a = 1;console.log(window.a); // 1let b = 2;console.log(window.b); // undefined

 

二、字符串

复制代码
{  // 使用for of循环字符串  for (let c of 'foo') {    console.log(c);  }  let s = 'Hello world!';    // 使用字符串的startsWidth/endsWidth/includes方法  console.log(s.startsWith('Hello')); // true  console.log(s.endsWith('!'));  // true  console.log(s.includes('e'));  // true  // 这三个方法都支持第二个参数,表示开始搜索的位置  s.startsWith('world', 6);  // true  let person = {    name: 'king',    age: 20  };    // 模板字符串  // 所有的空格和缩进都会被保留在输出中  let str = (`    The name is ${person.name}.    The age is ${person.age}.  `);  console.log(str);}
复制代码

 

三、函数

复制代码
// 函数参数的默认值function log(x, y = 'world') {  console.log(x, y);}log('hello');  // 可以省略尾部参数的默认值function f(x = 1, y) {  return [x, y];}f();  // [1, undefined]f(2);  // [2, undefined]f(, 1); // 报错, 编译无法通过// rest参数function add(...values) {  let sum = 0;  for (let val of values) {    sum += val;  }  return sum;}console.log(add(2, 5, 3));  // 10const sortNumbers = function() {  let arr = Array.prototype.slice.call(arguments);  return arr.sort();};const sortNumbers = function (...numbers) {  return numbers.sort();};sortNumbers(3, 1, 2);// rest参数必须是参数列表中的最后一个const push = function(array, ...items) {  items.forEach(function(item) {    array.push(item);  });};let a = [];console.log(push(a, 3, 1, 2));
复制代码

 

四、对象

复制代码
// Object.assign方法用来将源对象的所有可枚举属性复制到目标对象let target = {  a: 1};// 后边的属性值,覆盖前面的属性值Object.assign(target, {  b: 2,  c: 3}, {  a: 4});console.log(target);// 用处1 - 为对象添加属性class Point {  constructor(x, y) {    Object.assign(this, {x, y});  }}//let p = new Point(1, 2);////console.log(p); // Point {x: 1, y: 2}// 用处2 - 为对象添加方法Object.assign(Point.prototype, {  getX() {    return this.x;  },  setX(x) {    this.x = x;  }});let p = new Point(1, 2);console.log(p.getX()); // 1// 用处3 - 克隆对象function clone(origin) {  return Object.assign({}, origin);}
复制代码

 

五、Set和Map

复制代码
  // Set里面的成员的值都是唯一的,没有重复的值,Set加入值时不会发生类型转换,所以5和"5"是两个不同的值.  let s = new Set();  [2, 3, 5, 4, 5, 2, 2].map(function(x) {    s.add(x);  });  //for (let i of s) {  //  console.log(i);  //}  console.log([...s]);  console.log(s.size);  // 数组去重  function dedupe(array) {    return Array.from(new Set(array));  }  console.log(dedupe([1, 2, 2, 3])); // 1, 2, 3
复制代码

复制代码
{  // Map类似于对象,也是键值对的集合,但是"键"的范围不限于字符串,各种类型的值(包括对象)都可以当做键.  // 也就是说,Object结构提供了"字符串--值"的对应,Map的结构提供了"值——值"的对象,是一种更完善的Hash结构实现.  var m = new Map();  var o = {    p: 'Hello World'  };  m.set(o, 'content');  m.get(o);  // content  m.has(o);  // true  m.delete(o);  // true  m.has(o);  // false  m.set(o, 'my content').set(true, 7).set('foo', 8);  console.log(m);  // Map/数组/对象 三者之间的相互转换  console.log([...m]);}
复制代码

 

六、Iterator和Generator

复制代码
{  // 是一种接口,为各种不同的数据结构提供统一的访问机制.任何数据结构,只要不输Iterator接口,就可以完成遍历操作.  // 可供for...of循环消费  const arr = ['red', 'green', 'blue'];  let iterator = arr[Symbol.iterator]();  for (let v of arr) {    console.log(v); // red green blue  }  for (let i of iterator) {    console.log(i);  }  // for of 循环可以代替数组对象的forEach方法, 同样可以替代对象的for in循环}
复制代码

复制代码
{  function * foo() {    yield 1;    yield 2;    yield 3;    yield 4;    yield 5;    return 6;  }  for (let v of foo()) {    console.log(v);  }}
复制代码

 

七、Promise和async

复制代码
{  let getJSON = function (path, param) {    return new Promise(function(resolve, reject) {      let async = typeof param.async == 'undefined' ? true : param.async;      //let deferred = $.Deferred();      param = param || {};      param.data.auth_token = lib.getToken();      window.loading();      $.ajax({        url: path,        data: param.data,        type: 'POST',        dataType: 'json',        async: async,        timeout: 15000,        success: function (data) {          window.unloading();          if (data.code == 0) {            resolve.apply(this, [data]);          } else {            reject.apply(this, [data]);            lib.alert(data.msg, '我知道了');          }        },        error: function (xhr, type) {          window.unloading();          reject.apply(this, ['网络异常, 请稍候再试']);          lib.alert('网络异常, 请稍候再试');        }      });    });  };  getJSON('/xxx.json').then(function(rep) {  }).catch(function(rep) {  });}
复制代码

复制代码
{  function timeout(ms) {    return new Promise(function(resolve) {      setTimeout(resolve, ms);    });  }  async function asyncPrint(value, ms) {    let promise = await timeout(ms);    console.log(value);  }  asyncPrint('Hello world !', 1000);}
复制代码

 

八、class

复制代码
{  class Point {    static classMethod() {      return 'classMethod...';    }    // constructor方法是类的默认方法,通过new命令生成对象实例时自动调用该方法.    // 一个类必须有constructor方法,如果没有显示定义,一个空的constructor方法会被默认添加    constructor(x, y) {      this.x = x;      this.y = y;    }    toString() {      return '(' + this.x + ', ' + this.y + ')';    }    get prop() {      return 'getter';    }    set prop(value) {      console.log('setter:' + value);    }  }  // 静态属性的处理,只能用下面这种方式  Point.foo = 1;  console.log(Point.foo); // 1  // 继承  class ColorPoint extends Point {    constructor(x, y, color) {      // super方法必须被调用, 否则编译不通过      // 如果super在赋值属性this.xx = xx,后边调用,会报错'this' is not allowed before super()      super(x, y);      this.color = color;    }    toString() {      return 'The color is ' + this.color + ' and the point is ' + super.toString();    }  }  var p = new ColorPoint(1, 2, 'red');  console.log(p.toString());  p.prop = 1;  p.prop;  console.log(Point.classMethod());  // 父类的静态方法可以被子类继承  console.log('ColorPoint.classMethod(): ' + ColorPoint.classMethod());}
复制代码

 

 九、Module

复制代码
{  // module  /**   * 优势:   * 1. ES6可以在编译时就完成模块编译,效率要比commonJs模块的加载方式高   * 2. 不再需要UMD模块格式,将来服务器端和浏览器都会支持ES6模块格式.目前,通过各种工具库其实已经做到了这一点   * 3. 将来浏览器的新API可以用模块格式提供,不再需要做成全局变量或者navigator对象的属性   * 4. 不再需要对象作为命名空间(比如Math对象),未来这些功能可以通过模块提供   */}
复制代码

复制代码
// profile.jsexport var firstName = 'Michael';export var lastName = 'Jackson';export var year = 1958;// profile.jsvar firstName = 'Michael';var lastName = 'Jackson';var year = 1958;export {firstName, lastName, year};// export命令除了输出变量,还可以输出函数或类(class)。export function multiply (x, y) {  return x * y;};// export输出的变量就是本来的名字,但是可以使用as关键字重命名。function v1() {  //...}function v2() {  //...}export {  v1 as streamV1,  v2 as streamV2,  v2 as streamLatestVersion};// import// main.jsimport {firstName, lastName, year} from './profile';// 重命名import { lastName as surname } from './profile';// import命令具有提升效果,会提升到整个模块的头部,首先执行。foo();import { foo } from 'my_module';// 仅仅执行lodash模块,但是不输入任何值。import 'lodash';// export default// 为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。// export-default.jsexport default function () {  console.log('foo');}// import-default.js// 需要注意,这时import命令后面,不使用大括号。import customName from './export-default';customName(); // 'foo'// export default命令用在非匿名函数前,也是可以的。// export-default.jsexport default function foo() {  console.log('foo');}// 或者写成function foo() {  console.log('foo');}export default foo;
复制代码

 

十、编程风格
复制代码
// 1. let取代var


// 2. 全局常量// 在let和const之间,建议优先使用const,尤其是在全局环境,不应该设置变量,只应设置常量。// const声明常量还有两个好处,一是阅读代码的人立刻会意识到不应该修改这个值,二是防止了无意间修改变量值所导致的错误。// 所有的函数都应该设置为常量。// badvar a = 1, b = 2, c = 3;// goodconst a = 1;const b = 2;const c = 3;// bestconst [a, b, c] = [1, 2, 3];


// 3. 字符串// 静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。


// 4. 对象//对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用Object.assign方法。// badconst a = {};a.x = 3;// if reshape unavoidableconst a = {};Object.assign(a, { x: 3 });// goodconst a = { x: null };a.x = 3;// 对象的属性和方法,尽量采用简洁表达法,这样易于描述和书写。var ref = 'some value';// badconst atom = { ref: ref, value: 1, addValue: function (value) { return atom.value + value; },};// goodconst atom = { ref, value: 1, addValue(value) { return atom.value + value; },};


// 5. 数组//使用扩展运算符(...)拷贝数组。// badconst len = items.length;const itemsCopy = [];let i;for (i = 0; i < len; i++) { itemsCopy[i] = items[i];}// goodconst itemsCopy = [...items];//使用Array.from方法,将类似数组的对象转为数组。const foo = document.querySelectorAll('.foo');const nodes = Array.from(foo);



// 6. 函数//不要在函数体内使用arguments变量,使用rest运算符(...)代替。因为rest运算符显式表明你想要获取参数,而且arguments是一个类似数组的对象,而rest运算符可以提供一个真正的数组。// badfunction concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join('');}// goodfunction concatenateAll(...args) { return args.join('');}//使用默认值语法设置函数参数的默认值。// badfunction handleThings(opts) { opts = opts || {};}// goodfunction handleThings(opts = {}) { // ...}



// 7. 模块//首先,Module语法是JavaScript模块的标准写法,坚持使用这种写法。使用import取代require。// badconst moduleA = require('moduleA');const func1 = moduleA.func1;const func2 = moduleA.func2;// goodimport { 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';const Breadcrumbs = React.createClass({ render() { return <nav />; }});export default Breadcrumbs//如果模块只有一个输出值,就使用export default,如果模块有多个输出值,就不使用export default,不要export default与普通的export同时使用。//不要在模块输入中使用通配符。因为这样可以确保你的模块之中,有一个默认输出(export default)。// badimport * as myObject './importModule';// goodimport myObject from './importModule';//如果模块默认输出一个函数,函数名的首字母应该小写。function makeStyleGuide() {}export default makeStyleGuide;//如果模块默认输出一个对象,对象名的首字母应该大写。const StyleGuide = { es6: { }};export default StyleGuide;