码迷,mamicode.com
首页 > Web开发 > 详细

js的ES6特性

时间:2017-04-22 23:13:12      阅读:555      评论:0      收藏:0      [点我收藏+]

标签:ons   size   gen   添加   字符串连接   初学者   window   自动   函数调用   

一。 let和const关键字

let出现之前,js所有的作用域都是以函数为单位的,只要在一个function里声明的var,

无论是for循环等块里面声明的还是在块外面声明的,整个function都可以使用这个var,比如:

function foo() {
    for (var i=0; i<100; i++) {
        //
    }
    i += 100; // 仍然可以引用变量i
}

我个人的理解是js的提升特性,函数会将里面声明的所有var都提升到函数开始的地方,所以整个函数内都共享这些var。

let的出现解决了块级作用域的问题:

function foo() {
    var sum = 0;
    for (let i=0; i<100; i++) {
        sum += i;
    }
    i += 1; // SyntaxError
}

但是要注意的是,let并没有提升特性,也就是说不允许在声明之前就使用,而且在某一个块中声明的let变量,会屏蔽掉同名的var变量

var c = ‘test‘;
if (true) {
  c = ‘new‘; //ReferenceError
  let c;
  console.log(c);
}

const的是”常量let“,也就是说是有块级作用域的常量值。 

二。 箭头函数

箭头函数使用的最重要一点就是this的使用,一不小心就会出错。

let a = {
  foo: 1,
  bar: () => console.log(this.foo)
};
a.bar(); // undefined

  代码中的this指向调用a的对象,而不是a本身,如果为a外面没有定义foo的话,this会一直追溯到window对象,所以this.foo就是undefined了。

如果想调用a,只能使用普通函数:

let a = {
  foo: 1,
  bar: function() { console.log(this.foo); }
};
a.bar(); // 1

 再来看一个例子:

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
    }
};
obj.getAge(); // 25

 这里的this指向调用getAge的对象obj,所以this.birth能取到obj中的birth属性,该写法等价于:

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var that = this;
        var fn = function () {
            return new Date().getFullYear() - that.birth; // this指向window或undefined
        };
        return fn();
    }
};
obj.getAge(); // 25

这里必须使用that来捕获对象,否则在fn中的this并不是指向obj而是指向调用fn的对象。相比之下,该例中的箭头函数的使用就很清晰简洁了。

依我看来,并不应该把箭头函数归类为函数,而更应该使用lambda演算或lambda表达式这一称谓,

这一点在java中做的比较好,不知道为什么在js中很多人喜欢成为箭头函数,容易引起混淆。 

三。 字符串的使用

(1)多行字符串

用反引号 ` ... ` 表示:

alert(`多行
字符串
测试`);

(2)模板字符串

var name = ‘小明‘;
var age = 20;
var message = `你好, ${name}, 你今年${age}岁了!`;
alert(message);

模板字符串在一定程度上简化了+号的字符串连接作用。

四。 for…of…结构

for…in…循环有很多问题,但由于历史遗留问题至今还在使用。 

for...in...遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性,

所以当使用for…in…来遍历数组时,会感觉很别扭,而且当我们手动给Array对象添加了额外的属性后,for...in循环将带来意想不到的意外效果,比如:

var a = [‘A‘, ‘B‘, ‘C‘];
a.name = ‘Hello‘;
for (var x in a) {
    alert(x); // ‘0‘, ‘1‘, ‘2‘, ‘name‘
}

 这对于很多初学者来说很不习惯,for…of…就避免了这个问题,循环则完全修复了这些问题,它只循环集合本身的元素:

var a = [‘A‘, ‘B‘, ‘C‘];
a.name = ‘Hello‘;
for (var x of a) {
    alert(x); // ‘A‘, ‘B‘, ‘C‘
}

这就是为什么要引入新的for ... of循环。 

五。 Map和Set

Map是一种key-value结构,注意要区分和对象的写法,不同的key和value通过[ ]来划定而不是逗号,用逗号连接key和value而不是冒号。

var m = new Map([[‘Michael‘, 95], [‘Bob‘, 75], [‘Tracy‘, 85]]);
m.get(‘Michael‘); // 95

Set是一组key的集合,不存储value,注意和数组的区别,Set中值都是唯一的,重复的值被自动过滤,这也是和普通数组最大的区别。

var s = new Set([1, 2, 3, 3, ‘3‘]);
s; // Set {1, 2, 3, "3"} 

六。 iterable类型 

遍历Array可以采用下标循环,遍历MapSet就无法使用下标。

为了统一集合类型,ES6标准引入了新的iterable类型。

ArrayMapSet都属于iterable类型。具有iterable类型的集合可以通过新的for ... of循环来遍历。

然而,更好的方式是直接使用iterable内置的forEach方法(注意forEach()方法是ES5.1标准引入的,也就是说时在引入iterable类型之前就引入了),

forEach接收一个函数,每次迭代就自动回调该函数,比如以Array为例。

var a = [‘A‘, ‘B‘, ‘C‘];
a.forEach(function (element, index, array) {
    // element: 指向当前元素的值
    // index: 指向当前索引
    // array: 指向Array对象本身
    alert(element);
});

SetArray类似,但Set没有索引,因此回调函数的前两个参数都是元素本身:

var s = new Set([‘A‘, ‘B‘, ‘C‘]);
s.forEach(function (element, sameElement, set) {
    alert(element);
});

Map的回调函数参数依次为valuekeymap本身:

var m = new Map([[1, ‘x‘], [2, ‘y‘], [3, ‘z‘]]);
m.forEach(function (value, key, map) {
    alert(value);
});

如果对某些参数不感兴趣,由于JavaScript的函数调用不要求参数必须一致,因此可以忽略它们。例如,只需要获得Setelement

var s = new Set([‘A‘, ‘B‘, ‘C‘]);
s.forEach(function (element) {
    console.log(element);
});

七。 generator

(由于generator的概念比较复杂,详情请参考廖雪峰老师的网站

 generator由function*定义(注意多出的*号),并且,除了return语句,还可以用yield返回多次。

直接调用一个generator和调用函数不一样,f()仅仅是创建了一个generator对象,还没有去执行它

真正要执行generator对象有两个方法,一是不断地调用generator对象的next()方法,第二个方法是直接用for ... of循环迭代。

(1)调用next

next()方法会执行generator的代码,然后,每次遇到yield x;就返回一个对象{value: x, done: true/false},然后“暂停”。

返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。如果donetrue,则value就是return的返回值。

当执行到donetrue时,这个generator对象就已经全部执行完毕,不要再继续调用next()了。下面来看个例子:

要生成一个自增的ID,可以编写一个next_id()函数,由于函数无法保存状态,故需要一个全局变量current_id来保存数字:

var current_id = 0;
function next_id() {
    current_id ++;
    return current_id;
}

为了避免全局变量的污染,使用generator来保存运行状态:

function* next_id () {
    var current_id = 1;
    while (true)  {
       yield current_id;
       current_id ++;
    }   
    return current_id; // 可以不写
}

由于这里的while并没有跳出的可能,所以永远也不会执行return,可以一直调用next方法:

g = next_id(); // 只是创建了一个generator对象,还没有执行
g.next(); // 1
g.next(); // 2
...

再来看一个可以跳出循环的例子:

function* fib(max) {
    var
        t,
        a = 0,
        b = 1,
        n = 1;
    while (n < max) {
        yield a;
        t = a + b;
        a = b;
        b = t;
        n ++;
    }
    return a;
}

该例子是创建斐波那契数列数列,调用情况如下:

var f = fib(5); // 创建generator
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: true} 
f.next(); // {value: undefined, done: true}

注意最后一行的value是undefined,由于在上一行已经return了,所以这一行没有意义。

(2)使用for…of

直接用for ... of循环迭代generator对象,这种方式不需要我们自己判断done

for (var x of fib(5)) {
    console.log(x); // 依次输出0, 1, 1, 2, 3
}

js的ES6特性

标签:ons   size   gen   添加   字符串连接   初学者   window   自动   函数调用   

原文地址:http://www.cnblogs.com/stephen666/p/6749439.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!