let与var

  • let不可以重复申明变量,但是var可以
  • let有块级作用域,var没有
{
  let name = "LLC";
}
  • 在{}外部是拿不到name的
  • let不存在变量提升
  • let不影响作用域链
    {
      console.log(sex);  //undifined
      let name = "LLC";
      function() 
      {
    	console.log(name);  //LLC
    	let sex = "男";
      }
    }

rest形参

位置变量个数,...args必须放最后
function demo(a, b, ...args) {
  console.log(a);  //1
  console.log(b);  //2
  console.log(args);  //[3,4,5,6,7]
  console.log(arguments);  //arguments其实是个伪数组,实际是对象:[Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5, '5': 6, '6': 7 }
}
demo(1,2,3,4,5,6,7);

扩展运算符

tfBoys = ['王元', '易烊千玺', '王俊凯'];
function tf() {
  console.log(arguments);  //[Arguments] { '0': '王元', '1': '易烊千玺', '2': '王俊凯' }
}
tf(...tfBoys);

数组克隆

是一种浅拷贝
const x = ['e', 'g', 'm'];
const y = [...x];
console.log(y);  //['e', 'g', 'm']

伪数组转真数组

<div></div>
<div></div>
<div></div>
<script>
  let divs = document.querySelectAll('div');
  let divArray = [...divs];
  console.log(divArray); //[div, div, div], 每个div都是一个对象
</script>

Symbol变量

  • 不能参与任何运算(包括同类型变量之间),不能和其他类型数据进行对比(能和同类型比)

两种赋值方法

  let s1 = Symbol("LLC");
  let s2 = Symbol.for("LGR");

比较
  console.log(s1 === s2); //true

运用场景:为对象添加不参加运算的属性或方法

  let game = {
    name: "狼人杀",
    [Symbol("say")]: function() {
      console.log("我可以发言");
    },
    [Symbol('zibao')]: function() {
      console.log("我要自爆");
    }
  }

Symbol还可以向上面那样为别的对象添加新属性

  let demo = {
    name: "123"
  };
  demo[Symbol.hasInstance] = function() {  //hasInstance是Symbol的内置接口并非自定义,除此之外还有其他接口
    console.log("正在对比");  //新添加属性,当demo对象与别的对象进行比较时会触发该函数
  }
  let demo2 = {
    name: "456"
  };
  console.log(demo);  //{ name: '123', [Symbol(Symbol.hasInstance)]: [Function (anonymous)] }
  console.log(demo2 instanceof demo);  // -> 正在对比  false

迭代器(我感觉像遍历器)

  • 实现自定义的遍历,需求:必须用of遍历,打印所有name
  const banji = {
    name: ["LLC", "LGR", "XQL", "ZZQ"];
    [Symbol.iterator]: function() {
      let index = 0;
      let that = this;
      return 
      {
        next: function() 
        {
          if (index < that.name.length) {
            //迭代器的next方法必须返回一个对象,且对象必须包含value和done属性,如果done属性值为false则迭代还会继续
            const result = {value: that.name[index], done; false};
            index++;
            return result;
          } 
          else {
            const result = {value: undefine, done; true};
            return result;
          }
        }
      };
    }
  }
  
  for (let item of banji) {
    console.log(item);
  }

生成器(针对异步编程提供的一种解决函数)

  • ES6提供的异步编程函数
  • 在此之前要实现异步编程都是通过回调函数实现(缺点:嵌套太复杂、回调地狱)
  • 让方法分块运行
  function * gen() {
    console.log(111);  //第1块被执行的代码
    yield '第1块执行完了';  //第1块执行完返回值

    console.log(222);  //第2块被执行的代码
    yield '第2块执行完了';  //第2块执行完返回值

    console.log(333);  //第3块被执行的代码
    yield '第3块执行完了';  //第3块执行完返回值
  }
  //执行方式
  let iter = gen();
  //iter.next();按顺序执行,每次只执行一块,要执行完gen()方法要3次iter.next()
  console.log(iter.next());  //{value: '第1块执行完了', done: false}
  console.log(iter.next());  //{value: '第2块执行完了', done: false}
  console.log(iter.next());  //{value: '第3块执行完了', done: false}
  console.log(iter.next());  //{value: 'undefined', done: true}

生成器案例:

  • 需求:1s后输出111,再过2s后输出222,再过3s后输出333
  • 不用生成器:(嵌套过多,回调地狱)
setTimeout(() => {
        console.log(111);
        setTimeout(() => {
          console.log(222);
          setTimeout(() => {
            console.log(333);
          }, 3000);
        }, 2000);
      }, 1000);
  • 用生成器:(代码简约明了,没有回调地狱)
      function one() {
        setTimeout(() => {
          console.log(111);
          iter.next();
        }, 1000);
      }
      function two() {
        setTimeout(() => {
          console.log(222);
          iter.next();
        }, 2000);
      }
      function three() {
        setTimeout(() => {
          console.log(333);
          iter.next();
        }, 3000);
      }
      function* gen() {
        yield one();
        yield two();
        yield three();
      }
      let iter = gen();
      iter.next();
  • 生成器调用next方法
function one() {
        setTimeout(() => {
          console.log(111);
          iter.next("第1个已完成");  //此处穿的参数会作为执行完这一块的返回值
        }, 1000);
      }
      function two() {
        setTimeout(() => {
          console.log(222);
          iter.next("第2个已完成");
        }, 2000);
      }
      function three() {
        setTimeout(() => {
          console.log(333);
          iter.next("第3个已完成");
        }, 3000);
      }
      function* gen() {
        let fir = yield one();
        console.log(fir);  //第1个已完成
        let sec = yield two();
        console.log(sec);  //第2个已完成
        let thi = yield three();
        console.log(thi);  //第3个已完成
      }
      let iter = gen();
      iter.next();

Promise(解决回调地狱问题的函数)

  • 实例化Promise对象
const p = new Promise(function(resolve, reject) {
      setTimeout(function() {
        let data = "数据库中用户数据";
        resolve(data);  //当使用resolve之后,p实例的状态会变成true
        reject(data);  //当使用reject之后,p实例的状态会变成false
      }, 1000);
    });

    p.then(function(value){
      console.log(value);  //当p实例的状态为true时调用的方法
    }, function(reson){
      console.error(reson);  //当p实例的状态为false时调用的方法,可以省略
    });

Promise读取文件内容:

const fs = require("fs");

fs.readFile('./前言.md', (err, data) => {
  if (err) throw err;
  console.log(data.toString());
});

//使用Promise封装

const p = new Promise(function(resolve, reject){
  fs.readFile('./前言.md', (err, data) => {
    if (err) reject(err);
    resolve(data);
  });
});

p.then(function(value){
  console.log(value.toString());
}, function(reson){
  console.error(reson);
});

then方法的返回结果是 Promise 对象,对象的状态由回调函数的执行情况决定

then方法可以链式调用,避免回调地狱且美观

  const p = new Promise(function(resolve, reject){
    fs.readFile('./前言.md', (err, data) => {
      if (err) reject(err);
      resolve(data);
    });
  });
  p.then(value => {  //value接收的就是上一个 then 的resolve
    fs.readFile('./前言.md', (err, data) => {
      if (err) reject(err);
      resolve([value, data]);
    });
  }).then (value => {
    fs.readFile('./前言.md', (err, data) => {
      if (err) reject(err);
      value.push(data);
      resolve(value);
    });
  }).then(value => {
    fs.readFile('./前言.md', (err, data) => {
      if (err) reject(err);
      value.push(data);
      resolve(value);
    });
  });
  • 上面代码等同于
fs.readFile('./前言.md', (err, data) => {
  if (err) reject(err);
  let value = data;

  fs.readFile('./前言.md', (err, data) => {
    if (err) reject(err);
    let value1 = [data, value];

    fs.readFile('./前言.md', (err, data) => {
      if (err) reject(err);
      let value2 = value1.push(data);

      fs.readFile('./前言.md', (err, data) => {
        if (err) reject(err);
        let value3 = value2.push(data);
      });
    });
  });
});

新API —— set 集合(像数组,但是每个值是唯一的)

//申明
let s = new Set([1,1,2,3,5,5]);
console.log(s); //[1,2,3,5]自动去重
//长度
s的长度不用length,而是s.size
//检测
console.log(s.has(1)); //true
//清空
s.clear();
//删除
s.delete(1);
//遍历
for (let v of s) { console.log(v); }
Set + 扩展运算符实现数组去重
let s1 = new Set([1,1,2,3,3]);
console.log(s1); //{1,2,3}
let arr = [...s1];
console.log(arr);  //[1,2,3]

新api:Map() (对象的加强版)

let m = new Map();
//增加属性
m.set("name", "LLC");
//删除属性
m.delete("name");
//获取属性的值
m.get("name");
//遍历(对象不可以,但Map可以)
m.set('name1', "LLC");
m.set('name2', "LGW");

for (let v of m) {
  console.log(v);  //打印结果:[ 'name1', 'LLC' ] ['name2', 'LGR' ]
}

class类

  • ES5中也可以通过构造函数来实现和类一样的效果,ES6中class的出现相当于是个语法糖

  • ES5实现类的效果

function Phone(brand, price) {
    this.brand = brand;
    this.price = price;
  }
  //外部添加新属性
  Phone.prototype.call = function() {
    console.log("我可以打电话");
  }
  //创建实例
  let Huawei = new Phone("华为", 4599);
  Huawei.call();  //我可以打电话
  console.log(Huawei);  //Phone { brand: '华为', price: 4599 }
  • ES6实现类
class Phone {
    constructor(brand, price) {
      this.brand = brand;
      this.price = price;
    }
    call(){
      console.log("我可以打电话");
    }
  }
  let Huawei = new Phone("华为", 4599);
  Huawei.call();
  console.log(Huawei);

类的继承

  • ES5通过构造函数实现
function Phone(brand, price) {
  this.brand = brand;
  this.price = price;
}
Phone.prototype.contact = function () {
  console.log("我可以联系别人");
}

function SmartPhone(brand, price, color) {
  //继承属性
  Phone.call(this, brand, price);
  this.color = color;
}
//继承原型链
SmartPhone.prototype = new Phone;

SmartPhone.prototype.playMusic = function() {
  console.log("我可以放歌");
}

let Huawei = new SmartPhone('华为', 4599, '黑色');
Huawei.contact();
Huawei.playMusic();
console.log(Huawei);  //SmartPhone { brand: '华为', price: 4599, color: '黑色' }
  • ES6实现继承
class Phone {
  constructor(brand, price) {
    this.brand = brand;
    this.price = price;
  }
  contact() {
    console.log("我可以联系别人");
  }
}
class SmartPhone extends Phone {
  constructor(brand, price, color) {
    super(brand, price);
    this.color = color;
  }
  playMusic() {
    console.log("我可以放歌");
  }
}
let Huawei = new SmartPhone('华为', 4599, '黑色');

子类重写

  • 只能完全重写一个方法

class SmartPhone extends Phone {
....
contact() {
console.log("我是子类重写的方法");
}
}

setter与getter

  • 用来动态改变某个属性
class Phone {
  constructor() {
    this.dish = [];
  }
  //getter
  get menu() {
    return this.dish
  }
  //setter
  set menu(dish) {  //必须有参数
    this.dish.push(dish)
  }
}
let Huawei = new Phone('华为', 4599, '黑色');
Huawei.menu = "nana";  //必须赋值(参数)
console.log(Huawei.menu);  //[ 'nana' ]
Huawei.menu = "java";
console.log(Huawei.menu);  //[ 'nana', 'java' ]

数值扩展

  • Number.EPSILON 是JS能表示的最小精度

  • Number.parseFloat("3.14符号159") //3.14

  • Number.parseInt("123符号45") //123

  • Number.isInteger(1) //true 判断是否为整数

判断value是否为NaN Number.isNaN(value)

为什么不用if(value === NaN){}

NaN是一个与所有数不等的数字,即使if(NaN == NaN)也为false,所以需要Number.isNaN()

  • Math.trunc(3.64) //3 抹掉小数

  • Math.sign(正数) //返回1

  • Math.sign(0) //返回0

  • Math.sign(负数) //返回-1

对象方法扩展

合并对象属性Object.assign(obj1, obj2);

let obj1 = {name: "LLC"}, obj2 = {sex: "meal"}
Object.assign(obj1, obj2);  //obj1变成{name: "LLC", sex: "meal"}
  • 第一个参数会变成所有参数(包括自己)的并集
  • 相同属性:后面参数的属性值会覆盖前面参数的属性值
  • 可以有若干参数

设置原型对象 Object.setPrototypeOf()

let obj1 = {
  n: "LLC"
}
let obj2 = {
  f: function() {
    console.log("xi");
  }
}

Object.setPrototypeOf(obj1 , obj2 );
console.log(obj1 );  //{ n: 'LLC' }
console.log(Object.getPrototypeOf(obj1 ));  //{ f: [Function: f] }

模块化

别名

import {func1 as f1, func2} from './JS/func.js';

对于识别不了ES6语法的浏览器需要babel

  • 安装 bable-cli babel命令行工具
  • 安装 babel-preset-env 预设包,把ES6语法转为ES5
  • 安装 browserify(也可以用webpack等)打包工具