初识ES6

106 阅读6分钟

1、let、var、const

let申明的变量只在其所在的代码块有效(适合申明代码块内的变量,代码块外注销,ex:for循环计数器)
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
const声明不能被重新赋值,但引用类型的值时指针不变的情况下可以正常修改起属性值(Object.freeze()禁止修改属性值)
立即执行函数(变量私有化):IIFE: Immediately Invoked Function Expression
(function(){声明变量})<=>{const 变量}
变量提升:var:undefine let(临时性死区):err
ES6 的块级作用域必须有大括号
ex:
var a = 2;
{
  let a = 3;
  console.log(a); // 3 
}
console.log(a); // 2
// const->let->var

2、箭头函数

隐式返回;函数中 this 总是绑定总是指向对象自身:()=>{}
function Person(){
  this.age = 0;
  setInterval(() => {
    // |this| 指向 person 对象
    this.age++;
  }, 1000);
}
var person = new Person();
  • 注1:不适合箭头函数的情况:
通常this会指定为Windows对象
(1)作为构造函数,一个方法需要绑定到对象
(2)绑定到指定对象:交互事件/绑定指定元素等
(3)需要使用argument对象
  • 注2:
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

3、函数默认值

function(a=2,b=3){}
与解构赋值默认值结合
function foo({x, y = 5}) {
  console.log(x, y);
}
foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined

4、模板字符串

const sentence = '${变量} is ${变量} years old'

=>   

${变量}

处理用户输入,净化非法输入内容

5、新增的字符串函数

// index位置,大小写敏感
  • .startsWith(string,index)
  • .endsWith(string,index)
  • .includes(string,index)<=>.indexOf() !== -1
  • .repeat(n)重复次数
  • .join()数组取消逗号;
  • .trim()字符串取消空格;
  • .padStart()/.panEnd()补全长度

6、函数的扩展

rest 参数(形式为...变量名)获取函数的多余参数,可代替arguments对象使用
// arguments(类数组)变量的写法
//Array.prototype.slice.call将其转为数组
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();

7、Symbol

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值,可以转换为字符串、布尔值,不能转换为数值
let s = Symbol('foo');//接受一个描述参数

typeof s
// "symbol"
s.description // "foo"

8、Set和Map

Set结构不会添加重复元素(可用于去重)
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
  console.log(i);
}
// 2 3 5 4

// 去除数组的重复成员
[...new Set(array)]
//去除字符串里面的重复字符
[...new Set('ababbc')].join('')
// "abc"

9、Promise(和Stream)

Promise 是异步编程的一个构造函数
三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
const promise = new Promise(function(resolve, reject) {
  // ... some code
//1、判断
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});
//2、回调
promise.then(function(value) {
  // success
}, function(error) {
  // failure
});
如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例
const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})
  • Promise.prototype.then():添加状态改变时的回调函数;
  • Promise.prototype.catch():指定发生错误时的回调函数
  • Promise.try():让同步函数同步执行,异步函数异步执行

(1)async

//f是同步的时候
const f = () => console.log('now');
(async () => f())();// 立即执行函数
console.log('next');
// now
// next

// f是异步时
(async () => f())()
.then(...)//异步执行下一步操作
.catch(...)//捕获错误

(2)new Promise()

const f = () => console.log('now');
(
  () => new Promise(
    resolve => resolve(f())
  )
)();
console.log('next');
// now
// next

//上述写法等价于
const f = () => console.log('now');
Promise.try(f)
  .then(...)
  .catch(...)
console.log('next');
// now
// next
注:Promise.try就是模拟try代码块,就像promise.catch模拟的是catch代码块

10、Generator 

语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态
形式上,Generator 函数是一个普通函数,但是有两个特征。
  • function关键字与函数名之间有一个星号;
  • 函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

//value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;
//done属性是一个布尔值,表示是否遍历结束。
和Iterator结合使用:
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

[...myIterable] // [1, 2, 3]
  • 函数的异步应用实现:
        a1(astart)——b——a2(aend)
(1)回调函数
fs.readFile('/etc/passwd', 'utf-8', function (err, data) {
  if (err) throw err;
  console.log(data);
});
//返回/etc/passwd之后开始执行function
(2)Promise
解决多个回调函数嵌套会造成“回调函数地狱”,新的写法
var readFile = require('fs-readfile-promise');

readFile(fileA)
.then(function (data) {
  console.log(data.toString());
})
.then(function () {
  return readFile(fileB);
})
.then(function (data) {
  console.log(data.toString());
})
.catch(function (err) {
  console.log(err);
});
(3)Generator
a、协程写法:
function* asyncJob() {
  // ...其他代码
  var f = yield readFile(fileA);
  // ...其他代码
}
//函数asyncJob是一个协程.yield命令表示执行到此处,执行权将交给其他协程
可等价于async:
function async asyncJob() {
  // ...其他代码
  var f = await readFile(fileA);
  // ...其他代码
}
asyncReadFile();
b、协程的Generator函数实现:
function* gen(x) {
  try {
    var y = yield x + 2;
  } catch (e){
    console.log(e);
  }
  return y;
}

var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }
g.next(2) // { value: 2, done: true }
g.throw('出错了'); // 出错了
// next接受一个参数,作为上个阶段异步任务的返回结果,被函数体内的变量y接收
  • 缺点:流程管理却不方便(即何时执行第一阶段、何时执行第二阶段)。
(4)Thunk函数(自动执行 Generator 函数的一种方法)// 不太懂
传值调用和传名调用的区分中将参数放到一个临时函数之中,再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数。
JavaScript 语言是传值调用,它的 Thunk 函数含义有所不同。在 JavaScript 语言中,Thunk 函数替换的不是表达式,而是多参数函数,将其替换成一个只接受回调函数作为参数的单参数函数
function f(a, cb) {
  cb(a);
}
const ft = Thunk(f);

ft(1)(console.log) // 1
基于Promise对象的自动执行,co模块(一个小插件),难奥