ES6(语法) 新特性总结

一、新增 let 和 const

ES5只有两种声明变量的方法 var命令和function命令;ES6添加了let命令和const命令,还有import命令和class命令。

1、let:

1.不存在变量提升

// var a; (此处为js预解析,隐含存在。在下方代码执行中就隐藏着这个。)

console.log(a);

var a = 'abc';

// 若 var,执行结果为undefined,不是“abc”也不报错

// 若 let ,则会报错,let不存在预解析【error】

2.同一作用域下不能重复定义同一个名称

var b = 1;

var b = 2;

console.log(b);

// 若 var , 执行结果为2,var 声明的同名变量会覆盖之前的

// 若 let,执行结果报错,不可再次定义【error】

3.有着严格的作用域,var 属于函数作用域,let 属于块级作用域

function fun_test(){

    var num = 1;

    if(true){

        var num = 2; 

    }

    console.log(num);

}

fun_test();

// var 执行结果为2;在function类中var声明的同名变量均会后面的覆盖前面的;同时,使用var的时候注意不要和全局变量命名相同,否则局部的会覆盖掉全局的。

// let 执行结果为1;以{}为一个块级作用域,此处两个同名变量不报错是因为二者不在同一作用域下,分别执行。

Ps: js预解析功能,按照浏览器的功能会提前将命名的变量提前解析,然后再逐步加载代码执行。

2、const

1. const 声明一个只读的常量,一旦声明,常量的值就不能改变。

const TEMP = 11;

TEMP = 22;

console.log(TEMP);

// 执行报错【error】

2.const 一定要初始化,不能只声明不赋值

const RL;

// 报错【error】

3、当声明的常量是数组、对象等引用类型时,相当于只是定义了一个内存地址,对象所包含的值可以被修改,但对象指向的地址不能被修改。

const p = {name:"OldName", age:18};

p.age = 23; //  不报错,--- 修改包含的值,person的age属性变为23

p = {name:"NewName",age:19}; // 报错, --- 修改对象执行的地址

ps: 关于let 和 const的小 tips:

(1) let 关键词声明的变量不具备变量提升特性;

(2)let 和 const 声明只在最靠近的一个块中有效,也是块级作用域;

(3)当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING;

(4)使用let会出现暂时性死区,原因是let所声明的变量会锁在它所在的作用域里,不允许访问,就是说,它也会先扫描一遍,把let声明的变量保存起来,但是不允许使用,这时候你访问a,由于此作用域中有a,就不用访问外面的a了,但是你不能在它声明之前访问它。

    var a = 1;

    if(true){

        console.log(a); //ReferrenceError

        let a = 1;

    }

(5)使用let和const时不能重复声明。

(6) 使用var声明的全局变量或者未声明的变量都会归属到window对象下,但是使用let和const声明全局变量时不会发生这种情况。

(7)const本质:const命令声明的变量的值并不是不得改动的,而是变量执行那个的那个内存地址所保存的数据不得改动 对于数值、字符串、boolean这种类型的数据的值就保存在变量指向的那个内存地址,因此是常量。

  拓展: 如何使用ES5标准来实现let,换言之就是如何实现块级作用域。(答:使用匿名函数

二、模板字符串

在过去我们想要将字符串和变量拼接起来,只能通过运算符“+”来实现,若内容过多还要用“\”来表示换行,如:

var p1 = {name:"p1",age:19};

$(".introduction").html("Hello,my name is "+ p1.name +", and my \

age is "+ p1.age +".");

而在ES6中,可以将反引号(``)将内容括起来,在反引号中,可以使用${}来写入需要引用到的变量。如:

var person = {name: "Peter", age: 22, career: "student"};

$(".introduction").html(`Hello, my name is ${person.name}, and my career is ${person.career}.`);

三、箭头函数

1.不需要用关键字function来定义函数;

2.一般情况下可以省略return

3.在箭头函数内部,this并不会跟其他函数一样指向调用它的对象,而是继承上下文的this指向的对象

/* 

** 对应上面所说的第3点 

** 在箭头函数中,this的指向与它的上下文有关 

** 在本例中,箭头函数fun的上下文是window,所以this指向的也是window 

*/ 

window.val = 12; 

let fun = () => { 

    let val = 13; 

    console.log(val);// 13

    console.log(this.val);// 12

    console.log(this== window);// true

}

fun();

// 当参数只有一个,{}中的代码只有一行时,可以省略()和{},如果有return也可省略。

let f = v=>v; // 变量名=参数=>返回值(函数体)

// 等同于 

var f = function(v){

    return v;

}

四、数组、对象解构

可以将对象中的属性,数组值进行解构。以便快速获取数组和对象的值。

1、数组解构就是能快速提取数组中的指定成员(数组的某一项值或所有的值)

1. 解构赋值都是一一对应的,按照顺序

const arr = [200,300,400];

const [a,b,c] = arr;

console.log(a,b,c) ; // 200,300,400;

2. 也可以去数组的某一项值(解构必须保持一致)

const arr = [200,300,400];

const [,,c] = arr;

console.log(c) // 400

3. 还可以用“...”的方式提取所有的成员(注意的是:这种...的写法只能在解构成员的最后一个成员使用)

const arr = [200,300,400];

const [a,...all] = arr;

console.log(all) // [300,400] 会返回得到一个最后所有的数组

4. 如果提取的解构成员小于数组的长度,会从前到后的顺序来提取

const arr = [200,300,400]

const [a] = arr;

console.log(a) // 200  按顺序提取第一个

5. 如果提取成员大于数组长度,那么最后的提取的是undefined.

const arr = [200,300,400];

const [a,b,c,d] = arr;

console.log(d); //  undefined;

2、对象解构和数组解构基本类似,只不过对象解构的取值方式是根据对象的属性名来取值

const obj = {name:"aaa",age:30};

const {name} = obj;

console.log(name); // aaa

ps: 对象里面的属性名和其他自定义的变量名称如果重名会报错。

const obj = {name:"aaa",age:10};

const name = "bbb";

const {name} = obj

console.log(name); // 会报错

// 解决方法:要么重新命名,要么可以按照下面的写法来避免

const obj = {name:"aaa",age:10};

const name = "bbb";

const {name:nameObj} = obj; // 对象属性名称的重新指定

console.log(nameObj) // aaa

    借鉴于:https://blog.csdn.net/xuanzhuan365/article/details/109481552

五、新增数据类型:set 、map

1、set 类似于数组,成员是唯一的

const s = new Set();

s.add(1);

s.add(2).add(3).add(4); // 支持链式添加

s.add(2).add(3).add(4).add(2); // 这样的情况下不会打印最后的2。因为成员唯一,进行了去重处理

eg:  问: 对 var arr= [2,3,4,5,6,6,3,4,5] 去重处理

       答:var arr2 = [...new Set(arr)]; 即可

2、map 类似于对象,键并不是单纯的字符串,类型更多样

// map 以键值对的形式添加值

const m = new Map();

m.set("name","bob").set("age",18);

for(let [key,value] of m){}

六、函数设置默认参数值

以前设置默认值:

function f_1(txt) {

    var txt = txt || "hello world 1";

    console.log(txt);

}

function f_2(txt="hello world 2"){  console.log(txt);  }

f_1(); // 输出:hello world 1

f_2(); // 输出:hello world 2

f_1("elseString1"); // 输出:elseString1

f_2("elseString2"); // 输出:elseString2

七、迭代器 iterator, for...of , for...in

1、Iterator: 是ES6中的一种新的遍历机制;

1. 遍历器(iterator)它是一种接口,为各种不同的数据结构提供统一的访问机制

2.iterator的作用有三个:

a、为各种数据结构,提供一个统一的、简便的访问接口;

b、使数据接口的成员能够按某种次序排列

c、ES6创造了一种新的遍历命令for...of循环,iterator接口主要供for...of消费

3.iterator遍历的过程

 (1)  创建一个指针对象,指向当前数据结构的起始位置,Iterator的本质就是一个指针对象;

(2)当第一次调用指针对象的next()方法时,指针指向数据结构的第一个元素;

(3)当第二次调用指针对象的next()方法时,指针指向数据结构的第二个元素;

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

每一次调用next()方法时,会返回两个属性的对象,一个时value和done。value属性表示当前数据里元素的值,done返回一个boolean值,表示是否遍历完成。举以下为例:

function iIterator(array){

    var index = 0;

    return {

        next: function() {

                 if(index<array.length){

                     return {

                         value:array[index++],

                         done:false

                     }

                 } else {

                     return {

                         value:undefined,

                        done:true

                     }

                 }

        }

    }

};

var it = new iIterator([1,2,3,4]);

it.next(); // value:1,done:false

it.next(); // value:2,done:false

it.next(); // value:3,done:false

it.next(); // value:4,done:false

it.next(); // value:undefined,done:true

4.iterator 可以遍历的数据类型

Array、Map、Set、String、TypedArray、函数的arguments对象、NodeList对象

2、for...of循环

可用于替换for...in 和forEach()

for...of 是ES6新引用的循环,一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbor.iterator方法。

常用for...of遍历的数据类型:Map、Set、Array、String等

eg:以Array为例

var arr1 = ["a","b","c","d"];

arr1.forEach((element,index)=>{

    console.log(element);  // a,b,c,d

    console.log(index); // 0,1,2,3

});

for(let i in arr1) {

    console.log(i); // 0,1,2,3

}

for(let i of arr1) {

    console.log(i); // a,b,c,d

}

有上述可知:for...in遍历的是键名,不能直接获得键值。for...of遍历的是键值

八、class类的支持

Es6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。在ES5中,我们更多的是使用原型链来实现继承。

class Person {

    constructor(name) {

        this.name = name;

        // 不推荐以下写法,不能实现共享,且会造成内存浪费

        this.getName = function() {

            return this.name

        };

    }

    // Person.prototype.toGetName = function(){} == toGetName  true

    toGetName(name){

        return this.name;

    }

}

var p = new Person("张三");

p.getName(); // 张三

p.toGetName(); // 张三

九、对象的简化赋值

ps: 只有当对象的属性名和变量名一致时

const person = { "name":"name","age":"age" };

可简化为: const person = {name,age}; 

十、Spread / Rest 操作符

Rest运算符用于获取函数调用时传入的参数。

let fun = function(...args){

    console.log(args);

}

const list = ["p1","p2","p3"];

fun(list); // ["p1","p2,"p3"]

Spread运算符用于数组的构造、析构,以及在函数调用时使用数组填充参数列表。

// 使用Spread运算符合并数组

const list1 = ["p1","p2"];

const list2 = ["p3","p4"];

const list = [...list1,...list2];

console.log(list); // ["p1","p2,"p3","p4"]

// 使用Spread运算符析构数组

const [person,...list3] = list;

console.log(person); // p1

console.log(list3); // ["p2,"p3","p4"] 

了解更多

十一、二进制和八进制的字面量

ES6支持二进制和八进制的字面量,通过在数字签名增加0o或者0O就可以将数字转换为八进制。

let num1 = 0o10;

console.log(num1); // 8, 八进制的0o10对应十进制的8

let num2 = 0b10;

console.log(num2); // 2, 二进制的0b10对应十进制的2

十二、允许在对象中使用super方法

super方法在java中用来代表调用父类的构造函数。由于js不是面向对象语言,所以也没有继承这类说法。但是在ES6中,可以通过调用setPrototypeOf()方法来设置一个对象的prototype对象,与面向对象语言中的继承有相似之处,所以也可以理解成这是js中用来实现继承的方法。所以,在ES6中,通过使用super可以调用某个对象的prototype对象的方法或获取参数。

var father = {

    text:"Hello from the Father.",

    foo() {

        console.log("Hello from the Father 2.");

    }

}

var son = {

    foo() {

        super.foo();

        console.log(super.text);

        console.log("Hello from the Son.");

    }

}

// 将father设置成son的prototype,当在son中调用super时,可以直接调用到它的prototype对象,即father的方法和变量.

Object.setPrototypeOf(son,father);

son.foo();

// Hello from the Father 2.

// Hello from the Father.

// Hello from the Son.

参考1    参考2    参考3

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容