ES6初识


ES6 简述

就是新一代的Javascript标准,js引擎按照这个标准来实现Javascript这个语言,不需要把它想得太神秘,太高级,对于我们js的工程师而言,熟悉新的特性及语法,在实践过程中,提高工作效率,把项目搞好就行。当然,还有一点就像[我微博]里提到的,如果再不学习,可能过个一两年,等ES6普及开来了,一些库的代码你可能都读不懂了。

兼容性

由于今年才定稿,早期某些特性定稿的时候已经有『先进的浏览器』实现了部分特性,浏览器支持还不是太完整,而服务器端更激进一些,很多特性已经支持了,详细的特性支持列表,建议参考

http://kangax.github.io/compat-table/es6/

以后会是每年制定一个标准,所以也以年号来定,ES6也叫ES2015

关于学习的一点感触

语言只是工具,新特性如果能提高工资效率那必然是好特性,如果不能,然并卵 loadsh和underscore的存在,只能说明语言本身有很多未完善的地方,等到语言真的完善了,它们也就退出历史舞台了。

本文自带了babel,在代码区域单击,同时打开开发者工具,可以在控制台里看到输出

或者可以在我弄的这个网页版的repl里运行代码,在控制台里看结果

似曾相似

Object.assign

类似于jQuery的$.extend,但是功能比较弱,只是浅拷贝,用处很多,也可以克隆对象

let a = {a:1}
let b = {a:2}
let c = {c:{d:1}}
console.log(Object.assign(a, b, c))
c.c.d = 2

Array.prototype.find

查找到第一个符合条件的值比遍历更好用

console.log([1,3,4,2].find(function(v){
  return v > 3
})) //4

Array.prototype.filter

查找到所有符合条件的值

console.log([1,3,4,2].filter(function(v){
  return v > 2
})) //[3,4]

String.prototype.includes

String.prototype.startsWith

String.prototype.endsWith

三个方法都是indexOf的加强版,其中的查询字符串只不支持正则,如果是正则会抛出错误

console.log("hello".startsWith("ello", 1)) // true
console.log("hello".endsWith("hell", 4)  ) // true, 针对前4个字符
console.log("hello".includes("ell")      ) // true
console.log("hello".includes("ell", 1)   ) // true
console.log("hello".includes("ell", 2)   ) // false

字符串模板

告别手工拼接字符串

let x = 123
console.log(`${x}`) //123

${}内是标准的js语法

let x = 123
let y = 234
console.log(`${(x+y).toString(16)}`) //165

多行字符串

let name = 'hubo.hb'
let html = `
  <div id="header">
      ${name}
  </div>
`
console.log(html)

标签模板

一个可以干预模板翻译过程的函数

function toUpper(s) {
  return s.toString().toUpperCase()
}
console.log(toUpper`Go up!`) //'GO UP!'

第一个参数是除了替换的字符串的数组,剩下的参数是所有替换出来的值

function valuesOnly(stringsArray, ...valuesArray) {
  return valuesArray.join('; ')
}
var one = 1
var two = 2
console.log(valuesOnly`uno=${one}, dos=${two}, tres=?`) //'1; 2'

let, const

let is the new var,块级作用域, 区块中存在let和const命令,凡是在声明之前就使用这些命令,就会报错。 不会有变量提升,重复定义会报错

'use strict';

if (true) {
  let a = 1
  if (a) {
    console.log(a) //ReferenceError: a is not defined
    let a = 2
  }
}

const定义过的变量不能修改(修改无效),同样不会有变量提升,重复定义会报错

const a = 1
a = 2 //TypeError: Assignment to constant variable.

箭头函数

减少函数输入,this的自动绑定

var func = () => 'I return 1' //无参数的情况
console.log(func()) //I return 1

单个参数时可以省略参数括号

var odds = evens.map(v => v + 1)

如果想使用比较复杂的函数体,可以用{}包起来

nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v)
})

如果默认返回一个对象,需要用()把对象包裹起来

var nums = [1, 2, 3, 4]
console.log(nums.map(v => ({v}))) //[ { v: 1 }, { v: 2 }, { v: 3 }, { v: 4 } ]

遍历操作常用

console.log([1,2,3,4].map(v => v*2)) //单参的情况
  • 不能当作构造函数
  • 不能改变this
  • 不可以使用arguments对象
let o = {
  render(){
    setTimeout(()=> this.showIt(), 100)
  },
  showIt(){
    console.log('I show')
  }
}

o.render()

更方便的对象字面量

const x = 1
const y = 2

console.log({x, y}) //{x:1, y:2}

属性表达式

const x = 1
const y = 2

console.log({['xy'+ x + y]:`${x + y}`})

同时对象字面量也支持父级调用

var obj = {
  toString() {
    return "d " + super.toString()
  }
}

rest参数和展开符(…)

函数定义的时候使用…变量名,必须是最后一个参数,函数体内通过变量获取参数数组

const fn = (...rest) => rest.join()
console.log(fn(1, 2))

…把数组转化为参数序列,也可以

console.log([...'hello']) //["h", "e", "l", "l", "o"]

解构赋值

模式匹配批量赋值,数组,字符串,对象均可

const [a, b] = [1, 2]
console.log(a) //1
console.log(b) //2

const [c, d] = [...[1, 2]]
console.log(c) //1
console.log(d) //2

const [a, b, ...end] = [1, 2, 3, 4]
console.log(a, b, end) //1 2 [3,4]

const [h,...ends] = 'hello'
console.log(h, ends) //h ["e", "l", "l", "o"]

快速提取JSON里的值

var jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
}

let { id, status, data: [,secondData] } = jsonData;

console.log(id, status, secondData)// 42 OK 5309

同样可以用在函数参数里

function g({name: x}) {
  console.log(x)
}
g({name: 5}) // 5

可以使用默认值

let [a = 1] = []
console.log(a === 1) // true

参数默认值

传入的参数为undefined时,使用默认值

let number = (int = 0) => int;
console.log(number()) //0

对象参数默认值

function fetch(url, { body = '', method = 'GET', headers = {} } = {}){
  console.log(method)
}

fetch('http://jser.me')  //GET
fetch('http://jser.me', {})  //GET
fetch('http://jser.me', {method:'POST'})  //POST

参数省略只能从后向前省

本质上类是一个语法糖,可以使用ES5来模拟,它支持原型继承,父级调用,实例方法,静态方法和构造函数

class Point extends Sharp {
  constructor(x, y) {
    super(x, y)
    this.x = x;
    this.y = y;
  }

  update(x, y) {

  }

  static someMethod(){
     return 'call'
  }

  toString() {
    return '('+this.x+', '+this.y+')';
  }
}

Iterators和for of

迭代对象可以让我们方便的使用for of进行遍历,字符串,数组,Set, Map都可以使用for of进行遍历

var s = '123abc'
for (let n of s) {
  console.log(n) //1 2 3 a b c
}

自定义一个对象的迭代

let fibonacci = {
  [Symbol.iterator]() {
    let pre = 0, cur = 1
    return {
      next() {
        [pre, cur] = [cur, pre + cur]
        return { done: false, value: cur }
      }
    }
  }
}

for (var n of fibonacci) {
  if (n > 1000) break
  console.log(n)
}

模块

与nodejs的cmd定义有较大的区别

// lib/math.js
export function sum(x, y) {
  return x + y
}
export const pi = 3.141593

// app.js
import * as math from "lib/math"
alert("2π = " + math.sum(math.pi, math.pi))

默认导出 export default xxx

// lib/mathplusplus.js
export * from "lib/math"
export const e = 2.71828182846
export default function(x) {
    return Math.log(x)
}
// app.js
import ln, {pi, e} from "lib/mathplusplus"
alert("2π = " + ln(e)*pi*2)

Proxy

Proxy我个人理解提供了一个对象行为钩子,我们可以用来做拦截等事情

var target = {}
var handler = {
  get: function (receiver, name) {
    return `Hello, ${name}!`
  }
}

var p = new Proxy(target, handler)
console.log(p.world)

handler里可以用来挂的对象属性:

var handler =
{
  get:...,
  set:...,
  has:...,
  deleteProperty:...,
  apply:...,
  construct:...,
  getOwnPropertyDescriptor:...,
  defineProperty:...,
  getPrototypeOf:...,
  setPrototypeOf:...,
  enumerate:...,
  ownKeys:...,
  preventExtensions:...,
  isExtensible:...
}

Promies

不需要多讲,比较简单,大家多用就行了,用多了会上瘾。

Map和Set

两种新引入的数据结构,Map的键可以为任意对象,Map是Object的补充 Set可以理解为成员唯一的数组

总结

JS越来越完善,当然也越来越像JAVA。

参考链接


推荐文章