ES6 有哪些新特性 ? 全网最详细

目录

一、symbol

二、let和const

三、解构赋值

1、数组的解构

2、对象解构

3、字符串解构

四、新的对象和方法

1、Map 

2、Set

3、对象新特性

4、扩展运算符

 5、Array.from()把伪数组变成数组

6、Object.assign()

五、函数

1、参数默认值

2、不定参

3、箭头函数

六、类

七、模块导入导出

1、导入

2,导出

八、字符串 


一、symbol

ES6新增了一种原始数据类型:创建symbol数据类型的值时,需要给Symbol函数传递一个字符串,另外,每个symbol类型值都是独一无二的即使传递的是相同的字符串

const sy = Symbol('test');  // 只能用const   否则报错
const sy1 = Symbol('test');  // 只能用const   否则报错
console.log(typeof sy);   //'symbol'
sy == sy1;   //false

二、let和const

ES6新增了两个声明变量的关键字:let、const。

  • let和const声明的变量不存在变量提升,并且同一变量不能重复声明
  • let和const关键字有个特性:"暂时性死区,",其内部使用let和const关键字声明的变量与外部作用域中的变量相互隔绝,互不影响。即使是同名变量。
var a = 1;  // 这里不能是let关键字定义
function f1() {
    console.log(a)  //error Cannot access 'a' before initialization
    let a = 0;
    console.log(a)  //0
}
console.log(a);   //1
f1()
  • const关键字定义的变量,在定义的时候需要赋值,并且这个变量不可改变,引用类型除外
const obj = {
    name: "ren",
    age:12
};
// obj = {};   //error
obj.sex = "male";
console.log(obj);   //{name: "ren", age: 12, sex: "male"}

三、解构赋值

1、数组的解构

let [a, b, c] = [1, 2, 3];
console.log(a, b, c);    //1, 2, 3
 
let [a, b, c] = [1, , 3];
console.log(a, b, c);    //1, undefined, 3
 
let [a, , b] = [1, 2, 3];
console.log(a, b);//1, 3
 
let [a, ...b] = [1, 2, 3];    //...是剩余运算符,表示赋值运算符右边除第一个值外剩余的都赋值给b
console.log(a, b);//1, [2, 3]

2、对象解构

let obj = {name: 'ren', age: 12, sex: 'male'};
let {name, age, sex} = obj;
console.log(name, age, sex);  //'ren' 12 'male'
let {name:myName, age:myAge, sex:mySex} = obj;  //自定义变量名
console.log(myName, myAge, mySex);  //'ren' 12 'male'

3、字符串解构

let arr = 'hello';
let [a, b, c, d, e] = arr;
console.log(a, b, c, d, e);  //'h', 'e', 'l', 'l', 'o'

四、新的对象和方法

1、Map 

点击链接

2、Set

点击链接 

3、对象新特性

(1)、创建对象的字面量(字面量:变量的值)方式可以更加简洁。直接使用变量名作为属性函数体作为方法,最终变量值变成属性值函数名变成方法名

let name = 'ren';
 let age = 12;
 let myself = {
     name,
     age,
     say(){
         console.log(this.name);
     }
 };
console.log(myself);  //{name:'ren',age:12,say:fn}
myself.say();  //'ren'

4、扩展运算符

(1)、拷贝  · (对象、数组操作一样)

let obj = {name: 'ren', age: 12};
let person = {...obj};  // 拷贝对象 
console.log(person);//{name: 'ren', age: 12}
obj == person;  // false  第一层的对象是深拷贝  所以为false
let another = {sex: 'male'};
let someone = {...person,...another};//合并对象
console.log(someone);//{name:'ren',age:12,sex:'male'}

(2)、合并   (对象、数组操作一样)

let obj = {name: 'ren', age: 12}
let another = {sex: 'male'}
let someone = {...obj, ...another}
console.log(someone);  // {name: 'ren', age: 12, sex: 'male'}

 5、Array.from()把伪数组变成数组

function fn() {
    Array.from(arguments).forEach( it => {
        console.log(it)
    })
}
fn(1, 2, 3, 4)

6、Object.assign()

(1)、合并

const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a: 1, b: 2, c: 3}

注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性 

const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a: 1, b: 2, c: 3}

 (2)、深拷贝还是浅拷贝

①、第一层深拷贝

let srcObj = {'name': 'lilei', 'age': '20'};
let copyObj2 = Object.assign({}, srcObj);
console.log('srcObj', srcObj);		//'name': 'lilei', 'age': '20'
console.log('copyObj2', copyObj2);	//'name': 'lilei', 'age': '20'
srcObj.name="zhangsan";
console.log('srcObj', srcObj);		//'name': 'zhangsan', 'age': '20'
console.log('copyObj2', copyObj2);	//'name': 'lilei', 'age': '20'
copyObj2.age="10";
console.log('srcObj', srcObj);		//'name': 'zhangsan', 'age': '20'
console.log('copyObj2', copyObj2);	//'name': 'lilei', 'age': '10'

②、对象第一层,第二层浅拷贝

let srcObj = {'name': 'lilei', 'grade': {'chi':"80", 'eng':"100"}};
let copyObj2 = Object.assign({}, srcObj);
srcObj.name="zhangsan";
srcObj.grade.chi="10";
console.log('srcObj', srcObj);		//name: "zhangsan" grade: {chi: "10", eng: "100"}
console.log('copyObj2', copyObj2);	//name: "lilei" grade: {chi: "10", eng: "100"}

五、函数

1、参数默认值

function add(a=1, b=2){
    return a + b;
}
add();  //3
add(2);  //4
add(3, 4);  //7

2、不定参

 不定参:功能和使用arguments差不多。

function add(...num){
    return num.reduce(function(result, value){
        return result + value;
    });
}
add(1, 2, 3, 4);//10

3、箭头函数

注意:箭头内部没有arguments、也没有prototype属性

书写方式: 参数  =>  函数体

let add = (a,b) => {
    return a+b;
}
let print = () => {
    console.log('hi');
}
let fn = a => a * a;
//当只有一个参数时,括号可以省略,函数体只有单行return语句时,大括号也可以省略,强烈建议不要省略它们,是真的难以阅读
  • 当返回对象时需要加上小括号
const fn = () => ({name: 'ren', age: 12});
  • this指向

如果定义对象的方法直接使用箭头函数,那么函数内的this将直接指向window。

var age = 123;
 let obj = {
     age:456,
     say:() => {
         console.log(this.age);
     }
 };
obj.say();   //123
//对象是没有执行期上下文的(AO对象),定义对象的方法实际上是在全局作用域下,即window

如果你一定要在箭头函数中让this指向当前对象,其实也还是有办法的(但是没必要这么麻烦啊,直接使用普通函数不是更好吗?):

var age = 123;
 let obj = {
     age: 456,
     say: function(){
         var fn = () => {
         console.log(this.age);
        }
         return fn();
      }
 };
obj.say();  //456

六、类

class 作为对象的模板被引入ES6,你可以通过 class 关键字定义类。class 的本质依然是一个函数

1,创建类

class Ex {   //关键字声明方式
    constructor(name){
        this.name = name;
        this.say = () => {
            console.log(this.name);
        }
    }
    methods(){
        console.log('hello ' + this.name);
    }
    static a = 123;
    static m = () => {
        console.log(this.a);
    };
}
//let ex = class{}  字面量方式
var example = new Ex('ren');
example.say();    //'ren'
Ex.m();   //123
example.methods();  //'hello ren'

constructor是创建类必须的方法,当使用new调用类创建实例时,将自动执行该方法,该方法和构造函数类似,默认返回this对象。实例的方法和属性都定义在constructor内部。相当于构造函数的this方式。

类保留了prototype属性,类中的方法不需要使用function关键字,并且方法之间不需要逗号隔开。类中定义的方法实际上还是保存在类的prototype属性上。

使用static关键字定义类的静态属性和方法。类中不能定义共有属性,要想定义实例的共有属性还是需要使用prototype属性:Ex.prototype.属性名 copyable

 2、类的继承

类的继承通过extends关键字实现。
class Person {
    constructor (name,age){
        this.name = name;
        this.age = age;
    }
    say(){
        console.log(this.name + ':' + this.age);
    }
}
class Student extends Person{
    constructor (name,age,sex){
        super(name,age);
        this.sex = sex;
    }
}
var student = new Student('ren',12,'male');
student.name;  //'ren'
student.sex;  //'male'
student.say();  //'ren:12'

子类继承自父类,不会隐式的创建自己的this对象,而是通过super()引用父类的this。这个过程和在子构造函数内使用父构造函数call(this)很像,但他们有本质的区别。另外,ES6规定,super()必须在子类的this之前执行。所以一般我们把super()放在子类constructor方法的第一行,这样准没错!

七、模块导入导出

1、导入

import ‘模块名称’ from ‘路径’;
import  ‘路径’;
  • 通过 import...from 的方式引入模块,模块名称实际上相当于定义一个变量,用来接收即将导入的模块。
  • 路径可以有很多方式,既可以是绝对路径,也可以是相对路径,甚至只是一个简单的模块名称,更甚至连文件后缀都不需要。当你使用该命令时,系统会自动从配置文件中指定的路径中去寻找并加载正确的文件。
import Vue from "vue";
//完整路劲其实是 "../node_modules/vue/dist/vue.js";

通过 import... 的方式一般用来引入样式文件或预处理文件,因为他们不需要用变量来接收。

2,导出

默认导出:export default

export var name = 'ren';

按需导出:export 

let name = 'ren'
let age = 12;
export {name, age};
//注意:变量需要用大括号包裹,然后才能向外输出

总结:使用 export 向外输出成员时,可以同时输出多个,并且必须用‘{}’大括号包裹,在其他地方使用 import 导入时,接收成员的变量名必须和这里输出的名称一致,同时,可以根据实际情况,仅接收实际需要的的成员(接收的时候也要用大括号包裹)。

 export 向外暴露成员,并且在导入的时候自定义接收名称,那么你可以使用 as 关键字重命名

let name = 'ren'
let age = 12;
export {name, age};
 
import {name as myName, age as myAge} from 'url';

export default与export 的不同:①、在同一个模块中,export default 只允许向外暴露一次成员;然后,这种方式可以使用任意的名称接收;

                                                   ②、export 和 export default 可以在同一模块中同时存在。


let person = {name: 'ren'};
let age = 12;
let address = 'cd';
export default person;
export {age};
export {address};
 
import man,{age, address} from 'url'

八、字符串 

传统:

const a = 5;
const b = 10;
console.log("Fifteen is " + (a + b) + " and\nnot " + (2 * a + b) + ".");
// "Fifteen is 15 and
// not 20."

模板:

const a = 5;
const b = 10;
console.log(`Fifteen is ${a + b} and
not ${2 * a + b}.`);
// "Fifteen is 15 and
// not 20."

你可能感兴趣的:(es6,javascript,前端)