js的ES6特性

一。 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
}
时间: 2024-12-27 21:24:24

js的ES6特性的相关文章

最常用的ES6特性

遇到了要写出es6新特性的题目,所以查阅了资料来总结一下,点击查看原文. 进入正题,最常用的ES6特性有:let, const, class, extends, super, arrow functions, template string, destructuring, default, rest arguments. 1.let,const 针对目标:块级作用域 关于这两个特性,可以先查看我的博客:js中const,var,let区别. 在之前的基础上,进行补充:ES5只有全局作用域和函数作

最常用的ES6特性(转)

最常用的ES6特性 let, const, class, extends, super, arrow functions, template string, destructuring, default, rest arguments这些是ES6最常用的几个语法,基本上学会它们,我们就可以走遍天下都不怕啦!我会用最通俗易懂的语言和例子来讲解它们,保证一看就懂,一学就会. let, const 这两个的用途与var类似,都是用来声明变量的,但在实际运用中他俩都有各自的特殊用途.首先来看下面这个例子

解决浏览器兼容ES6特性

为什么ES6会有兼容性问题? 由于广大用户使用的浏览器版本在发布的时候也许早于ES6的定稿和发布,而到了今天,我们在编程中如果使用了ES6的新特性,浏览器若没有更新版本,或者新版本中没有对ES6的特性进行兼容,那么浏览器肯定无法识别我们的ES6代码,好比浏览器根本看不懂我写的let和const是什么东西?只能报错了.这就是浏览器对ES6的兼容性问题. 好消息 哪里有灾难,哪里就有勇士和救兵,针对ES6的兼容性问题,很多团队为此开发出了多种语法解析转换工具,把我们写的ES6语法转换成ES5,相当于

解决让浏览器兼容ES6特性

为什么ES6会有兼容性问题? 由于广大用户使用的浏览器版本在发布的时候也许早于ES6的定稿和发布,而到了今天,我们在编程中如果使用了ES6的新特性,浏览器若没有更新版本,或者新版本中没有对ES6的特性进行兼容,那么浏览器肯定无法识别我们的ES6代码,好比浏览器根本看不懂我写的let和const是什么东西?只能报错了.这就是浏览器对ES6的兼容性问题. 好消息 哪里有灾难,哪里就有勇士和救兵,针对ES6的兼容性问题,很多团队为此开发出了多种语法解析转换工具,把我们写的ES6语法转换成ES5,相当于

利用js对象的特性,去掉数组中的重复项

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Unt

Javascript ES6 特性概述(即ECMAScript 6和ES2015+)

Javascript在过去的一年里变化了很多,从现在开始,有12个新的特性可以开始用了! 1. 历史 ECMAScript 6是对Javascript语言的增强,有时候也被称为ES6或者ES2015+. Javascript诞生在1995年,从那以后一直在缓慢地演变,每隔几年会有一些新的增强特性出现.ECMAScript出现在1997年,目的是指导Javascript的演化路径,它已经发布了好几个版本,如ES3.ES5.ES6,等等. 可以看到,在ES3.ES5和ES6之间分别有10年和6年的空

JS面向对象之特性和值类型与复合类型

JS面向对象之特性已经值类型与复合类型 一些属性 空对象 空对象也是对象, 只是有存变量的变量名, 没有对象属性 var o = {}; 参数传递 值类型: 函数内外两个变量, 两个数据, 都不相同 引用类型: 函数内外变量不同, 一个数据, 相同地址 赋值 var num = 123; var num2 = num; 值类型的赋值特点 将变量内的数据全部拷贝一份, 赋值的变量 var num = 123 表示变量中存储中的数字是 123 将 123 数据拷贝一份, 内存中有 2 个数据 将拷贝

JS的ES6

JS的ES6 1.let let age = 12; (1). 作用: 与var类似, 用于声明一个变量 (2). 特点: 在块作用域内有效 不能重复声明 不会预处理, 不存在提升 (3). 应用: 循环遍历加监听 使用let取代var是趋势 2.const const sex = '男'; (1). 作用: 定义一个常量 (2). 特点: 不能修改 其它特点同let (3). 应用: 保存不用改变的数据 3.解构赋值 (1)对象的解构赋值:从对象的属性中取到想要的属性值 1 let obj =

JS的ES6的Generator

JS的ES6的Generator 1.Generator函数的概念: ES6提供的解决异步编程的方案之一,现在已经不怎么用了被淘汰了. Generator函数是一个状态机,内部封装了不同状态的数据. 用来生成遍历器对象 暂停函数,yield关键字暂停,next()方法启动,yield可以获得next方法传递过来的数据,如果无数据yield返回undefined,如果有数据则返回数据. 2.Generator使用: 1 function* generatorExample(){ 2 let res