ECMAScript 6

博客分类: 原创

ECMAScript 6

在业务中呆久了,对新事物的敏感度会下降的。也许这在某些情况下看来是一种借口,但业务确实需要考虑实际的产出,不能轻易的说对某些浏览器的舍弃,对于某些技术的实践。需要考虑对用户的影响,一般业务要对新技术的实践需要做非常多的前期调研,在飞速发展的前端时代,很可能在等待技术成熟的过程中错过了尝试让技术成熟的机会,而我很想体验一下这个过程。

纯技术与业务各有各的优劣,我想趁年轻都尝试一下。来打击一下自己浮躁的心。

use strict

use strict:严格模式,ECMAscript 5添加的新特性。

严格模式的作用:

  • 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
  • 消除代码运行的一些不安全之处,保证代码运行的安全;
  • 提高编译器效率,增加运行速度;
  • 为未来新版本的Javascript做好铺垫。

严格模式下的代码更合理、更安全、更严谨。下面看一些例子说明严格模式与一般模式的区别。

首先是使用场景:

<!--在不同的脚本中,会让不同的脚本进入不同的模式-->
<script>     "use strict";     console.log("这是严格模式。");   </script>   <script>     console.log("这是正常模式。");   </script>

// 在方法中有作用域的区别
function strict(){     "use strict";     return "这是严格模式。";   }

  function notStrict() {     return “这是正常模式。”;   }

区别:

"use strict";

// 报错,v未声明
v = 1;
// 报错,i未声明   for(i = 0; i < 2; i++) {}

// 语法错误,禁止使用 with
with (o){}

// evel 的参数不再污染全局
var x = 2;
console.log(x);                           // 2
eval('var x = 5; console.log(x)');        // 5
console.log(x);                           // ? 严格模式下是2,非严格模式下是5

// 强化作用域的概念
var xxx = (function (){
    return !this;
})();
console.log(xxx);

var xxx = (function (){
    "use strict";
    return !this;
})();
console.log(xxx);

// 禁止函数内部遍历调用栈
(function f1() {
    f1.caller;
    f1.arguments;
})()

// 禁止删除变量,但是还是能够删除属性
"use strict";
var x;
delete x;       // 语法错误
var x = {
    a: 1
}
delete x.a      // 正常

// 禁止重名参数
function(a, a, b) {
    return;  
}

// 禁止八进制表示法,第一位数据为0时报错
var n = 0100;

// 不允许任何情况下对 arguments 进行赋值
arguments = 1;

// arguments不再追踪参数的变化
(function (a) {    
    a = 2;    
    console.log(a, arguments[0]);
})(1);

(function (a) {
    "use strict";
    a = 2;
    console.log(a, arguments[0]);
})(1)

// 禁止使用保留字
function package(protected) {
    var implements;
}

// 函数必须要声明在外部
if (true) {
    console.log(123)
    function f() {console.log(1)}
}
f()

for...of

可以遍历出值,不是键,

'use strict';
var arr = ["a", "b", "c", "d"];
for (let a of arr) {
    console.log(a);     // a、b、c、d
}
var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (let e of engines) {
    console.log(e);     // Gecko、Trident、Webkit
}

let

定义块级作用域用的,局部变量;

"use strict";
{
    var a = 10;
    let b = 20;
}
console.log(a)      // 10
console.log(b)      // ReferenceError: b is not defined

块级作用域不被外界所污染。

"use strict";
var a = 10;
let b = 10;
{
    var a = 20;
    let b = 20;
}

console.log(a)      // 20
console.log(b)      // 10

不会被申明提前

"use strict";
console.log(a);     // undefined
console.log(b);     // ReferenceError: b is not defined
var a = 10;
let b = 10;

同一块级作用域不允许被再次赋值

"use strict";
let a = 10;
let a = 10;         // SyntaxError: Identifier 'a' has already been declared

const

申明真正意义上的常亮,不允许修改属性,不允许重新赋值,都会报错

"use strict";
const PI = 3.1415;
PI = 3;             // TypeError: Assignment to constant variable
const PI = 3.1;     // SyntaxError: Identifier 'PI' has already been declared

新的数据结构Set

Set数据结构类似于数组,但是成员的值都是唯一的,没有重复的值,Set本身是一个构造函数,用来生成Set数据结构。

这种数据结构提供如下集中方法:

  • size:返回成员总数。
  • add(value):添加某个值。
  • delete(value):删除某个值。
  • has(value):返回一个布尔值,表示该值是否为set的成员。
  • clear():清除所有成员。

唯一性:

'use strict'
var s = new Set();
[2, 3, 5, 4, 5, 2, 2].map(function(item){
    s.add(item);
})
console.log(s)      // Set { 2, 3, 5, 4 }

可遍历:

'use strict'
var s = new Set();
[2, 3, 5, 4, 5, 2, 2].map(function(item){
    s.add(item);
})
for(var i of s){
    console.log(i);  // 2   3   4   5
}

API使用:

'use strict'
var s = new Set();
[2, 3, 5, 4, 5, 2, 2].map(function(item){
    s.add(item);
})
console.log(s.size);        // 4
console.log(s.has(2));      // true
s.delete(2);
console.log(s.has(2));      // false
s.clear();
console.log(s);             // Set {}

新的数据结构Map

Map数据结构类似于对象,就是一个键值对的集合,但是“键”的范围不限于字符串,甚至对象也可以当作键。

这种数据结构提供如下集中方法:

  • size:返回成员总数。
  • set(key, value):设置一个键值对。
  • get(key):读取一个键。
  • has(key):返回一个布尔值,表示某个键是否在Map数据结构中。
  • delete(key):删除某个键。
  • clear():清除所有成员。

可遍历:

'use strict'
var m = new Map();
m.set('name', 'karyn')          // 键是字符串
m.set(23, 'age')                // 键是数值
m.set(undefined, 'undefined')   // 键是undefined
var hello = function() {
    console.log('hello');
}
m.set(hello, 'Hello ES6!')      // 键是函数
for(var b of m){
    console.log(b)
}

// [ 'name', 'karyn' ]
// [ 23, 'age' ]
// [ undefined, 'undefined' ]
// [ [Function], 'Hello ES6!' ]

API使用:

'use strict'
var m = new Map();
m.set('name', 'karyn')          // 键是字符串
m.set(23, 'age')                // 键是数值
m.set(undefined, 'undefined')   // 键是undefined
var hello = function() {
    console.log('hello');
}
m.set(hello, 'Hello ES6!')      // 键是函数
console.log(m)                  // Map { 'name' => 'karyn', 23 => 'age', undefined => 'undefined', [Function] => 'Hello ES6!' }
console.log(m.has('name'))      // true
console.log(m.has('years'))     // false
console.log(m.has(23))          // true
console.log(m.has(undefined))   // true
console.log(m.has(hello))       // true
m.delete(undefined)
console.log(m.has(undefined))   // false
console.log(m.get(hello))       // Hello ES6!
console.log(m.get('name'))      // karyn

遍历器Iterator

遍历器Iterator是一种协议,任何对象都可以部署遍历器协议,从而使得for...of循环可以遍历这个对象。遍历器协议规定,任意对象只要部署了next方法,就可以作为遍历器,但是next方法必须返回一个包含value和done两个属性的对象。其中,value属性当前遍历位置的值,done`属性是一个布尔值,表示遍历是否结束。

类似于中间件的思想,提供一个next方法。调用next方法时从堆栈中取出对应的值,可以一直调用下去。

'use strict'
function makeIterator(array) {
    let nextIndex = 0;
    return {
        next: function() {
            return nextIndex < array.length ? {
                value: array[nextIndex++],
                done: false
            } : {
                done: true
            };
        }
    }
}

let it = makeIterator(['a', 'b']);
let value_a = it.next();
let value_b = it.next();
let value_c = it.next();
let value_d = it.next();
console.log(value_a.value, value_a.done);       // a false
console.log(value_b.value, value_b.done);       // b false
console.log(value_c.value, value_c.done);       // undefined true
console.log(value_d.value, value_d.done);       // undefined true

generator函数

根据上面的协议,就有了新的generator函数,可以实现函数的暂停。直接看例子吧

'use strict'
function* helloWorldGenerator() {
    yield 'hello';
    yield 'world';
}
var hw = helloWorldGenerator();
console.log(hw.next())      // { value: 'hello', done: false }
console.log(hw.next())      // { value: 'world', done: false }
console.log(hw.next())      // { value: undefined, done: true }
console.log(hw.next())      // { value: undefined, done: true }

函数体执行之后会在有yield的地方暂停,暂停之后只有主动调用next时才会继续执行。执行顺序如下。

'use strict'
function* f() {
    console.log(1)
    for (var i = 0; true; i++) {
        var reset = yield i;
        console.log(reset)
        if (reset) {
            i = -1;
        }
    }
}
var g = f();
console.log(0)
g.next() // { value: 0, done: false }
console.log(2)
g.next() // { value: 1, done: false }
console.log(3)
g.next(true) // { value: 0, done: false }

Class

ES6提供了“类”(class)。此前,一般用构造函数模拟“类”。

老式的写法

'use strict';
// ES5
let People = function(name) {
    this.name = name;
};
People.prototype.sayName = function() {
    return '我是' + this.name;
};
let person = new People('karyn');
console.log(person.sayName())

新的写法

'use strict';
// ES6
class People {
    constructor(name) {
        this.name = name;
    }
    sayName() {
        return '我是' + this.name;
    }
}
let person = new People('karyn');
console.log(person.sayName())       // 我是karyn

继承的实现

class HandsomeBody extends People {
    constructor(name) {
        super(name);                // 执行父类 constructor
    }
    sayName() {
        return super.sayName() + ',帅气如我';   // 调用父类的方法
    }
    sayHi() {
        return '帅气'
    }
}
let personB = new HandsomeBody('karynsong');
console.log(personB.sayName())      // 我是karynsong,帅气如我
console.log(personB.sayHi())        // 帅气