ES6学习笔记

2018-12-05  本文已影响0人  豪秋

1. 变量的解构赋值

let [a, b, c] = [1, 2, 3] // a = 1, b = 2, c = 3
let {foo, bar} = {foo: 'foo', bar: 'bar'}; // foo = 'foo', bar = 'bar'

2. 箭头函数,rest参数

var sum = (num1, num2) => num1 + num2;
var getObj = id => ({id: id, name: 'bob'}) // 如果返回的是个对象,需要用圆括号包起来
function add(...values) {
  let sum = 0;
  values.forEach(x => sum+= x);
  return sum;
}
add(1, 2, 3); // 6

3. 数组:

const contains = (() => Array.prototype.includes ? (arr, value) => arr.includes(value) : arr.some(el => el === value))()

4. 对象

var target = {
  a: 1
};
var source1 = {
  b: 2
};
var source2 = {
  b: 3
}
Object.assign(target, source1, source2) // {a:1,b:2,c:3}

5. Symbol 一种新的原始数据类型,表示独一无二的值。每个Symbol的值都不相等。(Symbol值不能与其他类型的值进行运算)

var s = Symbol(’s’) 可接收一个参数,用于描述。

var mySymbol = Symbol();
// 第一种写法
var a = {};
a[mySymbol] = 'hello';
// 第二种写法
var b = {
  [mySymbol]: 'hello'
}
// 第三种写法
var c = {};
Object.defineProperties(c, mySymbol, {
  value: 'hello'
});
// 注意:Symbol值作为对象属性名时,不能使用点运算符

6. Set和Map数据结构

- Set——类似于数组,成员没有重复

数组去重:
[...new Set([1,2,3,4,4])] // [1,2,3,4]或者 Array.from(new Set([1,2,2,3,3]));

let mySet = new Set();
mySet.add(1).add(2).add(2);
s.size // 2
s.has(1) // true
s.has(2) // false
s.delete(2);
s.has(2); //  false

数组的map和filter也适用于Set,因此使用Set可以很容易的实现并集(Union)、交集(Intersect)、差集(Difference)。

let a = new Set([1,2,3]);
let b = new Set([2,3,4]);
// 并集
let union = new Set([...a,...b]); //set {1,2,3,4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x))); //set {2,3};
// 差集
let differenceA = new Set([...a].filter(x => !b.has(x))); // set{1}
let differenceB = new Set([...b].filter(x => !a.has(x))); // set{4};
let difference = new Set([...differenceA,...differenceB]); // set{1,4};
- Map——类似于对象,也是键值对的集合,各种类型的值都可以当做键,即“值——值”。
let map = new Map([
  [1,'one'],
  [2,'two'],
  [3, 'three']
])
[...map.keys()] // [1,2,3]
[...map.values()] // ['one','two','three']
[...map] // [[1,'one'],[2,'two'],[3,'three']]

结合数组的map方法、filter方法,可以实现Map的遍历和过滤。

[...map].filter(([k, v]) => k < 2); // map {1 => 'a'}

7. Proxy-代理、拦截

Proxy可以理解成为目标对象前架设一个“拦截”层,外界对改对象的访问都必须先通过这层拦截,可以对外界的访问进行过滤和改写。

let proxy = new Proxy(target, handler)

target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。

var proxy = new Proxy({}, {
  get(target, property) { // target 表示 目标对象,property所要访问的属性
    return 35;
  }
})

proxy.time // 35
proxy.title // 35

注意:
要使Proxy起作用,必须针对proxy实例。

var person = {
  name: '张三'
}
var personProxy = new Proxy(person, {
  get(target, property){
    if(property in target){
      return target[property];
    }else{
       throw new Error('...');
    }
  }
})
personProxy.name // 张三
personProxy.age // 报错
let validator = {
  set(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
      obj[prop] = value;
    }
  }
};
let person = new Proxy({}, validator);
person.age = 100; // 100
person.age = 'young'; // 报错
person.age = 300; // 报错

8. Promise对象——异步编程的解决方案

var getJson = function(url) {
  var promise = new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open('get', url);
    xhr.responseType = 'json';
    xhr.setRequestHeader('Accept', 'application/json');
    xhr.send();
    xhr.onreadystatechange = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    return promise;
  });
};

getJson('data.json')
  .then(json => {
    console.log('json' + json);
  })
  .catch(e => {
    console.log(e);
  });

注:promise先记录个简单用法,后期再深入学习。

9.Class

es5通过构造函数定义并生产对象,如:

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function() {
  return `(${this.x}, ${this.y})`;
};

ES6引入了Class(类)的概念作为对象的模板,通过class关键字定义类,通过class改写上面的Point类。

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  toString() {
    return `(${this.x}, ${this.y})`;
  }
}
let p = new Point(1, 2); // 类必须使用new来调用

类的所有方法都定义在类的prototype属性上。

10.Class的继承

Class通过extends实现继承。

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  toString() {
    return `(${this.x}, ${this.y})`;
  }
}

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y)
    this.color = color;
  }

  toString() {
    return `${this.color} ${super.toString()}`; // 调用父类的toString()
  }
}

let colorPoint = new ColorPoint(2, 3, 'red');

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。在子类的构造函数中,只有调用了super之后才可以使用this关键字。

ES5与ES6的继承

super虽然代表了父类的构造函数,但是返回的是子类的实例,即super内部的this指的是子类,因此super()在此相当于 父类.prototype.constructor.call(this)。

super关键字

class A {
  constructor() {
    this.x = 1;
  }
}

class B extends A {
  constructor(){
    super();
    this.x = 2;
    super.x = 3; // super.x 等同于 this.x
    console.log(super.x); // super.x 等同于 A.prototype.x  undefined
    console.log(this.x); // 3
  }
}

11.Module语法

ES6模块是编译时加载或者静态加载,CommonJS模块是‘运行时加载’,因此ES6模块效率更高。

// profile.js
let firstName = 'Michael';
let lastName = 'Jackson';
let year = 1958;
function getName(firstName, lastName) {
  return `${firstName} ${lastName}`;
}
function v1(year) {
  return `${year}-01-01`;
}
export { firstName, lastName, year, getName, v1 as getDate };

通常情况下,export输出的变量就是本身的名字,但也可以使用as关键字重命名。

import {
  firstName,
  lastName,
  year
} from './profile';

function setName(ele) {
  ele.textContent = `${firstName} ${lastName}`;
}

由于import是静态执行,所以不能使用表达式。如果多次重复执行同一句import语句,只会执行一次。

// circle.js
function area(radius) {
  return Math.PI * radius * radius;
}

function circumference(radius) {
  return 2 * Math.PI * radius;
}
export {
  area,
  circumference
}
// 指定加载某个值
import {area, circumference} from './circle';
console.log(area(4));
// 整体加载一个对象(* 重命名 circle)
import * as circle from './circle';
console.log(circle.area(4));

本质上,export default 就是输出了一个叫做default的变量或方法,将该命令后面的值赋给default然后再默认,然后系统允许我们为他取名字。

对比默认输出和正常输出

export default function foo(){
  console.log('foo');
} // 函数名foo在模块外无效,加载时视同匿名函数
import fn from './foo.js'
function foo() {
  console.log('foo');
}
export {
  foo
}
from './foo.js'
export {foo, bar} from './my_module';
// 等同于
import {foo, bar} from './my_module';
export {foo, bar};
import('./myModule.js')
  .then({export1, export2} => {
     // ...
  })
  .catch(e => {
   console.log(e)
  });

import()的适用场景

button.addEventListener('click', event => {
  import('./dialoge.js').then(dialoge => {
    dialoge.open();
  }).catch(e => {
    console.log(e);
  })
})
if(condition){
  import('moduleA').then()
}else{
  import('moduleB').then()
}

12.编码风格

  1. 在let和const之间,建议优先使用const。
    const优于let有一下原因:

    • 提醒阅读程序的人,此变量不可改变。
    • javascript编译器会对const 进行优化。
  2. 优先使用解构赋值。

  3. 注意区分Object和Map,只有模拟实体对象时才使用Object。如果只是需要key:value的数据结构,则使用Map。因为Map有内建的遍历机制。

  4. 用Class取代需要prototype的操作。因为Class的写法更简洁。使用extends实现继承,更简单。

  5. Module语法是Javascript模块的标准写法。使用import取代require,使用export取代mudule.exports。

上一篇下一篇

猜你喜欢

热点阅读