首页 >   >  正文

ES6


标签:        日期:2016-03-10    阅读:

ES6使用相关

ES6初篇


1 .ES6是什么

  • ECMAScript6
  • 最新的JavaScript核心语言标准

2.箭头操作符

当需要一个只有一个参数的简单函数时,可以使用新标准中的箭头函数,它的语法非常简单:标识符=>表达式。你无需输入function和return,一些小括号、大括号以及分号也可以省略。

简化了函数的书写,Input=>outputs

var array = [1,2,3];
array.forEach(function(v,i,a){
    console.log(v);
});

//ES6
array.forEach(v=>console.log(v));

如果要写一个接受多重参数(也可能没有参数,或者是不定参数、默认参数、参数解构)的函数,你需要用小括号包裹参数list。

  // ES6
var total = values.reduce((a, b) => a + b, 0);

3.字符串模板

var num=Math.random();

console.log(`your num is ${num}`);

##4. let命令 let命令:用于声明变量。用法类似于var,区别在于let所声明的变量,只在let命令所在的代码块内部有效。

var a = [];
for (let i = 0; i < 10; i++) {
    a[i] = function () {
        console.log(i);
    };
}
a[6](); // 10
  • 这段代码中for循环内部用let命令声明变量i,只在本轮循环内有效,所以每一次循环时i都是一个新值,所以最后输出6。

  • 如果for循环内用var声明变量i,在全局范围内都有效,所以每一次循环i的新值都会覆盖旧值,所以最后输出10。

    console.log(a); let a = 2;

let命令不存在“变量提升”现象,变量一定要在声明之后使用,否则会报错。 暂时性死区:只要块级作用域中存在let命令,所声明的变量就绑定在这个区域,不再受外部影响

例如:

var t = 1;
if(true) {
    t = 'a';
    let t;
}

因为在块级作用域中用let又声明了一个局部变量t,导致变量t绑定在这个块级作用域,所以在let声明变量t之前,对t赋值会报错。

不允许重复声明:let不允许在相同作用于内重复声明同一变量。

function func(arg) {
    let arg; // 报错
}

function func(arg) {
    {
        let arg; // 不报错
    }
}

不能在函数内部重新声明参数

5.const命令

const命令也用来声明变量,但是只可声明常量,一旦声明,常量的值不能再被改变。 一旦声明,必须初始化,其他用法大致与let相同。

跨模块常量:

6.增强的对象字面量

  • 可以在对象字面量里面定义原型
  • 定义方法可以不用function关键字
  • 直接调用父类方法

      //通过对象字面量创建对象
      var human = {
          breathe() {
              console.log('breathing...');
          }
      };
      var worker = {
          __proto__: human, //设置此对象的原型为human,相当于继承human
          company: 'freelancer',
          work() {
              console.log('working...');
          }
      };
      human.breathe();//输出 ‘breathing...’
      //调用继承来的breathe方法
      worker.breathe();//输出 ‘breathing...’
    

##7. ES6的块级作用域

  • 外层代码块不受内层代码块影响
  • 允许块级作用域的任意嵌套
  • 外层作用域无法读取内层作用域的变量
  • 内层作用域可以定义外层作用域的同名变量

8.数组的解构赋值

以前为变量赋值时只可以:

var a = 1;
var b = 2;
var c = 3;

现在可以写成这样:

var [a, b, c] = [1, 2, 3];

从数组中提取值,按照对应位置,对变量赋值

属于“模式匹配”,等号两边模式相同就会相应赋值,结构不成功时变量的值就等于undefined 等号左边的模式匹配一部分右边的数组时,解构也是成功的,属于不完全解构。

如果右边不是可以遍历的结构就会报错 let和const命令也适用。 默认值:解构赋值允许指定默认值。 但如果数组成员不严格等于undefined,默认值就不会生效

惰性求值:如果默认值是一个表达式,只有在用到的时候才会求值。

function f(){
    console.log("aaa");
}
let [x = f()] = [1];

上面代码因为x可以取到值所以f()不会执行。

9.对象的解构赋值

对象的属性没有顺序,变量必须与属性同名,才能取到正确的值

var { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

若不同名,则必须写为:

var { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'

被赋值的是变量 不是模式。 其余与数组解构类似。

10.字符串的解构赋值

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

此时,字符串被转换成了一个类似数组的对象。 会有length属性,也可以解构赋值

let {length : len} = 'hello';
len // 5

函数的参数也可以使用解构赋值,并且也可以使用默认值。 不能使用圆括号的三种情况:

  • 变量声明语句中,模式不能带有圆括号。

      var [(a)] = [1];
      var { x: (c) } = {};
      var { o: ({ p: p }) } = { o: { p: 2 } }; 
    

以上三种写法全部会报错。

  • 函数参数中,模式不能带有圆括号。
  • 不能将整个模式,或嵌套模式中的一层,放在圆括号之中。

只有赋值语句的非模式部分才可以使用圆括号。

11.支持模块

模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

将不同功能的代码写在不同的文件中

//user.js
module "user"{
    export class User{
        constructor (x,y) {
            public x = x;
            public y = y;

        }
    }
}


//app.js
//声明所要引用的模块
module user from "/user.js";

import User from "user";

var o = new User(1,3);
console.log(o);

12.类的支持

ES6中像Java一样增加了对于类的支持,可以在JavaScript中用class定义类。使我们在JavaScript中对象的创建和继承更加清楚直观。

class Animal {
    //ES6中新型构造器
    constructor(name) {
        this.name = name;
    }
    //实例方法
    sayName() {
        console.log('My name is '+this.name);
    }
}
//类的继承

class Dog extends Animal {
    constructor(name) {
        //直接调用父类构造器进行初始化
        super(name);
    }
    program() {
        console.log("I'm coding...");
    }
}
//测试
var animal=new Animal('dummy'),
wayou=new Dog('wayou');
animal.sayName();//输出 ‘My name is dummy’
wayou.sayName();//输出 ‘My name is wayou’
wayou.program();//输出 ‘I'm coding...’

ps:java中解释super()是当前对象的直接父类的无参的构造函数。

13.新增的集合类型:Map,Set 和 WeakMap,WeakSet

使用 WeakMap,WeakSet:当作为属性键的对象没有别的变量引用时。就会被回收释放,不会被保存

// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });//因为添加到ws的这个临时对象没有其他变量引用它,所以ws不会保存它的值,也就是说这次添加其实没有意思

14.Proxy

可以监听对象身上发生什么变化

//定义被监听的目标对象
var e = { name: 'Joe', salary: 50 };
//定义处理程序
var i = {
    set: function (receiver, property, value) {
        console.log(property, 'is changed to', value);
        receiver[property] = value;
    }
};
//创建代理以进行侦听
e = Proxy(e, i);
//做一些改动来触发代理
e.salary = 60;//控制台输出:salary is changed to 60

如果监听的对象属性被更改,处理程序就会被调用

  • Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

Proxy支持的拦截操作一览。

对于可以设置、但没有设置拦截的操作,则直接落在目标对象上,按照原先的方式产生结果。

(1)get(target, propKey, receiver)

拦截对象属性的读取,比如proxy.foo和proxy[‘foo’],返回类型不限。最后一个参数receiver可选,当target对象设置了propKey属性的get函数时,receiver对象会绑定get函数的this对象。

(2)set(target, propKey, value, receiver)

拦截对象属性的设置,比如proxy.foo = v或proxy[‘foo’] = v,返回一个布尔值。

(3)has(target, propKey)

拦截propKey in proxy的操作,返回一个布尔值。

(4)deleteProperty(target, propKey)

拦截delete proxy[propKey]的操作,返回一个布尔值。

(5)enumerate(target)

拦截for (var x in proxy),返回一个遍历器。

(6)hasOwn(target, propKey)

拦截proxy.hasOwnProperty(‘foo’),返回一个布尔值。

(7)ownKeys(target)

拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一个数组。该方法返回对象所有自身的属性,而Object.keys()仅返回对象可遍历的属性。

(8)getOwnPropertyDescriptor(target, propKey)

拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。

(9)defineProperty(target, propKey, propDesc)

拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。

(10)preventExtensions(target)

拦截Object.preventExtensions(proxy),返回一个布尔值。

(11)getPrototypeOf(target)

拦截Object.getPrototypeOf(proxy),返回一个对象。

(12)isExtensible(target)

拦截Object.isExtensible(proxy),返回一个布尔值。

(13)setPrototypeOf(target, proto)

拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。

如果目标对象是函数,那么还有两种额外操作可以拦截。

(14)apply(target, object, args)

拦截Proxy实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)。

(15)construct(target, args, proxy)

拦截Proxy实例作为构造函数调用的操作,比如new proxy(…args)。

##15. Symbols

  • symbol是一种基本类型

      let s = Symbol();
    
      typeof s
      // "symbol"
    
  • 可以用symbol这种值作为对象的键

  • Symbol通过调用symbol函数产生,有一个可选的名字的参数,凡是属性名属于Symbol类型,就都是独一无二的。

  • Symbol还可以用来创建私有属性,外部无法直接访问

  • 注意,Symbol函数前不能使用new命令,因为生成的Symbol是一个原始类型的值
  • Symbol函数的参数只是表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值是不相等的。

      // 没有参数的情况
      var s1 = Symbol();
      var s2 = Symbol();
        
      s1 === s2 // false
        
      // 有参数的情况
      var s1 = Symbol("foo");
      var s2 = Symbol("foo");
        
      s1 === s2 // false
    
  • Symbol值不能与其他类型的值进行运算,会报错。
  • Symbol值可以显式转为字符串。
  • Symbol值也可以转为布尔值,但是不能转为数值。

16.Promises

异步操作的一种模式,比如jQuery中的deferred对象 Promise对象是一个构造函数,用来生成Promise实例。

    var promise = new Promise(function(resolve, reject) {
          // ... some code
        
          if (/* 异步操作成功 */){
            resolve(value);
          } else {
            reject(error);
          }
    });

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用自己部署。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在成功时调用,并将结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected),在失败时调用,并将报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。

    promise.then(function(value) {
      // success
    }, function(value) {
      // failure
    });

17.生成器(Generator)

  • 普通函数使用function声明,而生成器函数使用function*声明。
  • 关键字yield 类似于普通函数里的return,但是生成器函数可以yield多次
  • 生成器函数可以自暂停

Generator函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield语句就是暂停标志。

遍历器对象的next方法的运行逻辑如下。

(1)遇到yield语句,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。

(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield语句。

(3)如果没有再遇到新的yield语句,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。

(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。

需要注意的是,yield语句后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行,因此等于为JavaScript提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。

Generator.prototype.throw()

Generator函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在Generator函数体内捕获。

Generator.prototype.return()

Generator函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历Generator函数。

yield*语句

用来在一个Generator函数里面执行另一个Generator函数。

18.字符串的扩展

字符的Unicode表示法

JavaScript中允许采用\uxxxx形式表示一个字符,其中“xxxx”表示字符的码点,只限于\u0000——\uFFFF之间的字符,但在ES6中将码点放入大括号就可以正确解读超出范围的字符。 JavaScript有六种方法可以表示一个字符:

'\z' === 'z'  // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true

codePointAt()

codePointAt方法会正确返回32位的UTF-16字符的码点。对于那些两个字节储存的常规字符,它的返回结果与charCodeAt方法相同。(返回的是十进制) codePointAt方法的参数是字符在字符串中的位置(从0开始),

String.fromCodePoint()

ES5提供的String.fromCharCode方法,用于从码点返回对应字符。但是这个方法不能识别32位的UTF-16字符。 ES6提供了String.fromCodePoint方法,可以识别0xFFFF的字符,弥补了String.fromCharCode方法的不足。在作用上,正好与codePointAt方法相反,如果有多个参数,则会合并成一个字符串返回。

at()

ES7提供了字符串实例的at方法,可以识别Unicode编号大于0xFFFF的字符,返回正确的字符。Chrome浏览器已经支持该方法。是对ES5中charAt方法的扩展。

includes(), startsWith(), endsWith()

ES6提供了三种新方法来确定一个字符串是否包含在另一个字符串中:

  • includes():返回布尔值,表示是否找到了参数字符串。
  • startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
  • endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。

三种方法都支持第二个参数,代表开始搜索的位置。 其中endWith方法使用第二个参数n时针对qiann个字符,而其他两种方法针对从第n个位置到字符串结束。

repeat()

repeat方法返回一个新的字符串,将原来的字符串重复n次,参数如果是小数会被取整,如果是负数或者是Infinity,会报错,如果是0到-1之间的小数等同于0,NaN等同于0,如果参数是字符串则会先转换成数字。

'hello'.repeat(3) // "hellohellohello"

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。 像这样:

$("#result").append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

String.raw()

String.raw方法,用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,将所有变量替换,对应于替换变量后的模板字符串。 如果原字符串的斜杠已经被转义就不会做任何处理

19.正则的扩展

  • ES6中允许RegExp构造函数接受正则表达式作为参数,会返回一个原有正则表达式的拷贝如果使用RegExp构造函数的第二个参数指定修饰符,则返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。
  • 字符串对象共有4个方法,可以使用正则表达式:match()、replace()、search()和split()。
  • ES6对正则表达式添加了u修饰符,含义为“Unicode模式”,用来正确处理大于\uFFFF的Unicode字符。
  • ES6还为正则表达式添加了y修饰符,叫做“粘连”(sticky)修饰符。y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
  • 与y修饰符相匹配,ES6的正则对象多了sticky属性,表示是否设置了y修饰符。
  • ES6为正则表达式新增了flags属性,会返回正则表达式的修饰符。

20.数值的扩展

二进制和八进制表示法

ES6提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。 如果要将0b和0x前缀的字符串数值转为十进制,要使用Number方法。

Number.isFinite(), Number.isNaN()

ES6在Number对象上,新提供了Number.isFinite()和Number.isNaN()两个方法,用来检查Infinite和NaN这两个特殊值。 这两个新方法只对数值有效,非数值一律返回false。

Number.parseInt(), Number.parseFloat()

ES6将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。

// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45

Number.isInteger()

Number.isInteger()用来判断一个值是否为整数。需要注意的是,在JavaScript内部,整数和浮点数是同样的储存方法,所以3和3.0被视为同一个值。

Number.EPSILON

ES6在Number对象上面,新增一个极小的常量Number.EPSILON。

安全整数和Number.isSafeInteger()

JavaScript能够准确表示的整数范围在-2^53到2^53之间(不含两个端点),超过这个范围,无法精确表示这个值。

ES6引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。

Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内。

Math()对象的扩展

ES6在Math对象上新增了17个与数学相关的方法。所有这些方法都是静态方法,只能在Math对象上调用。

指数运算符

ES7新增了一个指数运算符(**),目前Babel转码器已经支持。

21.二进制数组

二进制数组(ArrayBuffer对象,TypedArray视图和DataView视图),是JavaScript操作二进制数据的一个接口。

  • 原始设计目的:与WebGL项目有关。

二进制数组由三类对象组成:

  • ArrayBuffer对象:代表内存里的一段二进制数据,可以通过视图进行操作。视图部署了数组接口,可以用数组的方法操作内存。
  • TypedArray视图:包括9种类型的视图,比如Uint8Array(无符号8位整数)数组视图, Int16Array(16位整数)数组视图, Float32Array(32位浮点数)数组视图等等。
  • DataView视图: 可以定义复合格式的视图。比如第一个字节是Uint8(无符号8位整数)、第二、三个字节是Int16(16位整数)、第四个字节开始是Float32(32位浮点数)等等,还可以自定义字节序。

(1)ArrayBuffer对象

代表储存二进制数据的一段内存,不能直接读写,只能通过视图读写。 也是一个构造函数,可以分配一段可以存放数据的连续内存区域。

视图的作用:以指定的格式解读二进制数据。

    var buf = new ArrayBuffer(32);
    var dataView = new DataView(buf);
    dataView.getUint8(0) // 0

上面代码中ArrayBuffer对象生成了一段32字节的内存区域,每个字节的默认值都是0,然后对这段字节指定视图。 TypedArray视图与DataView视图的一个区别是,它不是一个构造函数而是一组构造函数,代表不同的数据格式

    var buffer = new ArrayBuffer(12);
    var x1 = new Int32Array(buffer);
    x1[0] = 1;
    var x2 = new Uint8Array(buffer);
    x2[0]  = 2;
    
    x1[0] // 2

TypedArray视图的构造函数还可以接受普通数组作为参数,直接分配内存生成底层的ArrayBuffer实例,并且同时完成赋值。

(2)TypedArray视图

TypedArray视图一共包括9种类型,每一种视图都是一种构造函数。

Int8Array:8位有符号整数,长度1个字节。 Uint8Array:8位无符号整数,长度1个字节。 Uint8ClampedArray:8位无符号整数,长度1个字节,溢出处理不同。 Int16Array:16位有符号整数,长度2个字节。 Uint16Array:16位无符号整数,长度2个字节。 Int32Array:32位有符号整数,长度4个字节。 Uint32Array:32位无符号整数,长度4个字节。 Float32Array:32位浮点数,长度4个字节。 Float64Array:64位浮点数,长度8个字节。

由这9个构造函数生成的数组,统称为TypedArray视图。

(3)BYTES_PER_ELEMENT属性

每一种视图的构造函数都有一个BYTES_PER_ELEMENT属性,表示这种数据类型占据的字节数

(4)ArrayBuffer与字符串的互相转换

相互之间转换时,需要字符串的编码方法是确定的

(5)DataView视图

如果一段数据包括多种类型(比如服务器传来的HTTP数据),这时除了建立ArrayBuffer对象的复合视图以外,还可以通过DataView视图进行操作。

22.Set和Map数据结构

Set

Set是一种新的数据结构,类似数组,但是成员的值都是唯一的并且没有重复值,本身是一个构造函数,用来生成Set数据结构 Set函数可以接受一个数组(或者一个类似数组的对象)作为参数,用来初始化。

Set实例的四个操作方法。

  • add(value):添加某个值,返回Set结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值

遍历操作:可以用于遍历成员。

  • keys():返回一个键名的遍历器
  • values():返回一个键值的遍历器
  • entries():返回一个键值对的遍历器
  • forEach():使用回调函数遍历每个成员

Set结构没有键名,只有键值(或者说键名和键值是同一个值)

Map

ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。

    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

作为构造函数,Map也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。

如果对同一个键多次赋值,后面的值将覆盖前面的值。

23.Iterator和for of 值遍历

for of 循环

在每次循环中循环的是值而不是序号 可以正确响应break、continue和return语句 for-of循环不支持普通对象

for…of循环可以使用的范围包括数组、Set和Map结构、某些类似数组的对象(比如arguments对象、DOM NodeList对象)、后文的Generator对象,以及字符串。

Iterator(遍历器)

Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费。

Iterator的遍历过程:

(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。

(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。

(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。

本文为原创文章,转载请注明出处:大耳朵梦斗士的博客 » ES6
如果本站内容帮助到了你,请记得收藏、分享,或打赏支持,谢谢!

上篇: React Context