浅谈ES6新特性

407 阅读6分钟

       ES6是新版本javascript语言的标准,它给我们带来了更简单、更快捷也更容易理解的语法,如箭头函数、模板字符串等,为我们提供新语法以及代码特性来提升javascript的使用体验,目前大多数浏览器已经支持ES6中绝大多数特性,基于此ES6普及速度相当快,基本成为业界标准。

ES6常用特性列举

一、新的变量声明方式:let和const

       ES6推荐使用let声明变量,相较于var,let声明的变量会形成一个块级作用域,其声明的变量只在局部作用域中起作用:

    var a=1;
    {
        let b=2;
    }
    console.log(a);//1
    console.log(b);//ReferenceError: b is not defined

       let表示声明变量,而const表示声明常量,两者都会形成块级作用域,但是const声明的变量都会以常量的形式存在,即值一旦确定就不能修改:

    const a=1;
    a=0;
    console.log(a);//TypeError: Assignment to constant variable.

       const声明对象时,对象的属性值可以被修改:

    const hero={
        name:"stark",
        from:"American"
    }
    hero.name="batman";
    console.log(hero);//{name: "batman", from: "American"}

       let与const的其他注意细节:

  • 1.let和const声明的变量不具备在预编译时提升的特性
  • 2.let声明的变量可以先声明不赋值
  • 3.let和const声明变量不允许重复声明
  • 4.const在声明变量时必须初始化

二、新的函数声明方式:箭头函数

       传统的函数声明方式包括函数声明,函数表达式声明等,而ES6中新增的函数声明方式:箭头函数,其简便直观的特点,更简化了开发者的工作复杂度。
       箭头函数最直观的特点:

  • 省略了function函数声明关键字
  • 返回值return关键字可省
  • 其声明的函数内部this指向其上一级
    //传统的表达式声明方式
    var getSum=function(a,b){
        return a+b;
    };
    getSum(1,2);//3
    //箭头函数
    var add=(a,b)=>a+b;
    add(1,2);//3

       此处函数体只有一条执行语句,函数体return和{}可以同时省略。箭头函数只有一个参数时,包裹形参的()也可以省略:

    let func=a=>a;
    func(666);//666

       箭头函数中的this指向:

    setTimeout(()=>console.log(this),1000);//当前this指window全局对象

三、模版字符串

       ES6之前的字符串处理方式:

let sayInfo=(name,fromArea)=>console.log("I am "+name+" and from "+fromArea+".");
sayInfo("Michael","American");//I am Michael and from American.

       而采用模版字符串之后:

    let sayInfo=(name,fromArea)=>console.log(`I am ${name} and from ${fromArea}.`);
    sayInfo("Mary","Cuba");//I am Mary and from Cuba.

       不难看出,采用模版字符串之后减少了+的拼接工作,降低了代码量也让代码的可读性更强。
       模版字符串的特点如下:

  • 数据用``包裹
  • 基本的字符串格式化
  • 表达式嵌入字符串中进行拼接,用${}来界定
    console.log(`<li>学习中心</li>
                <li>案例交流</li>
                <li>课程分享</li>  
    `); //<li>学习中心</li>
        //<li>案例交流</li>
        //<li>课程分享</li> 

模版字符串的又一强大之处,输出后结果会保留数据的原格式。

四、解构赋值

数组解构

    //一般意义上的赋值
    let arr=[1,2,3];
    let a=arr[0];
    let b=arr[1];
    let c=arr[2];

       数组解构使用数组字面量,且解构操作全部在数组类内完成。

    let colors=["red","green","blue"]
    let first=colors[0];
    let second=colors[1];
    console.log(first,second);//red green

       在数组解构语法中,我们通过值在数组中的位置进行选取,且可以将其存储在任意变量中,未显式声明的元素都会直接被忽略。
       在数组解构中可直接跳过变量名,只为需要的元素提供变量名:

    let people=["zhangsan","lisi","wangwu"];
    let [,,third]=people;
    console.log(third);//wangwu

       使用解构赋值语法从people中获取第3个元素,third前的逗号是前方元素的占位符,无论数组中的元素有多少个,都可以通过这种方法提取想要的元素,不需要为每一个元素都指定变量名。

变量交换

       数组解构语法还有一个独特的用例:交换两个变量的值。

    //互换变量的值
    let a=1,
        b=2;
    [a,b]=[b,a];
    console.log(a,b);//2 1

       数组解构赋值看起来像是一个镜像:赋值语句左侧(也就是等号左侧)与其他数组解构示例一样,是一个解构模式;右侧是一个为交换过程创建的临时数组字面量。代码执行过程中,先解构临时数组,将b和a的值复制到左侧数组的前两个位置,最终结果是变量互换了它们的值。

  • 注意细节:如果右侧数组解构赋值表达式的值为null或undefined,则会导致程序抛出错误

默认值

       在数组解构赋值表达式中为数组中的任意位置添加默认值,当指定位置的属性不存在或其值为undefined时使用默认值。

    let students=["Jane","Mary"];
    let [first,second,third="Michael"]=students;
    console.log(first,second,third);//Jane Mary Michael

       students数组中没有第三个元素与之对应,但是它有默认值Michael,不会输出undefined。

嵌套数组解构

       嵌套数组解构即在原有数组模式中插入另一个数组模式,将解构过程深入到下一个层级。

    let students=["Machael",["Jane","Mary"],"Mike"];
    let [first,[second,third]]=students;
    console.log(first);//Machael
    console.log(second,third);//Jane Mary

       变量second引用的是students数组中的值"Jane",该元素包含在数组内部的另一个数组中,所以second与third两侧的方括号是一个必要的解构模式。

数组复制

       在ES5中一般使用concat()方法实现对数组的拷贝:

    //concat()方法拷贝数组
    let colors=["red","green","blue"];
    let cloneColors=colors.concat();
    console.log(cloneColors); // ["red", "green", "blue"]

       在ES6中,可以通过不定元素的语法来实现相同的目标:

    let colors=["red","green","blue"];
    let [...cloneColors]=colors;
    console.log(cloneColors);
  • 在被解构的数组中,不定元素必须为最后一个条目,在后面继续添加逗号会导致程序抛出语法错误

对象解构赋值

       对象字面量的语法形式是在一个赋值操作符左边放置一个对象字面量:

    let node = {
        type: "Identifier",
        name: "foo"
    };
    let { type, name } = node;
    console.log(type); // "Identifier"
    console.log(name); // "foo"

       在这段代码中,node.type的值被存储在名为type的变量中;node.name的值被存储在名为name的变量中。

解构赋值

       上面我们已经将对象解构应用到了变量的声明中。然而,我们同样可以在给变量赋值时使用解构语法。

    let node={
        type:"Identifier",
        name:"Mike"
    },
    type="Literal",
    name=5;
    //使用解构分配不同的值
    {type,name}=node;
    console.log(type,name);// Identifier Mike

       这段代码中在声明type与name时初始化了一个值,后面通过解构赋值的方法,从对象中获取相应值重新为两个变量赋值了。

默认值

       使用解构赋值表达式时,如果指定的局部变量名称在对象中不存在,那么这个局部变量会被赋值为undefined,与数组解构赋值有相似处。

    let student={ name:"Michael"};
    let {name,age=20}=student;
    console.log(name); //Michael
    console.log(age); //20

       这段代码中为age设置了默认则value,只有当对应student上没有该属性或者该属性值为undefined时此默认值才有效。

为非同名局部变量赋值

       如果希望使用不同命名的变量来存储对象属性的值,ES6的一个扩展语法可以满足需求:

    let hero={
        type:"ironman",
        name:"stark"
    };
    let {type:ownType,name:ownName}=hero;
    console.log(ownType); //ironman
    console.log(ownName); //stark

       使用解构赋值来声明变量ownType与ownName,两个变量分别存储hero对象中的type与name的属性值。

嵌套对象解构

    let info={
        type:"Identifier",
        name:"zhangsan",
        friends:{
            first:{
                age:35,
                hobby:"drink"
            },
            second:{
                age:32,
                hobby:"smoke"
            }
        }
    };
    let { friends:{second}}=info;
    console.log(second.age); //32
    console.log(second.hobby); //somke

       在解构模式中使用了{},其含义为在对象中找到friends属性后,继续深入一层查找second属性,并最终获取到赋值运算符右侧的属性值。
       对象解构模式可以应用于任意层级深度的对象,且每一层都具备同等的功能。

五、扩展运算符

扩展运算符在数组中的应用

    let arr=[...[1,2,3]];
    console.log(arr); //[1,2,3]

       利用扩展运算符实现数组的复制,即浅拷贝。

    function getNum(x,y,z){
        //遍历arguments对象
        for(var i=0;i<arguments.length;i++){
        console.log(arguments[i]);// 4 5 6
    }
        //转化前为伪数组
        console.log(Array.isArray(arguments));//false
        let newArguments=[...arguments];
        //转化后为真数组
        console.log(Array.isArray(newArguments));//true
    };
    getNum(4,5,6);

       利用扩展运算符将伪数组转化为真数组。
       除此之外扩展运算符还可以用于合并数组:

    let arr1=[1,2];
    let arr2=[3,4];
    console.log(...arr1,...arr2); //1 2 3 4
    注意细节:扩展运算符使用时必须有容器包裹,否则会导致系统抛出错误。

扩展运算符在对象中的应用

    let student={
        name:"Jane",
        sex:"woman",
        friends:["Mary","Mike"]
    };
    let newStudent={...student};
    //let newStudent=Object.assign({},student);等同于扩展运算符方法
    console.log(newStudent); //{name: "Jane", sex: "woman", friends: Array(2)};

       与数组中的实现功能相似,完成了新对象对旧对象的浅拷贝。此外扩展运算符也可以用于对象的合并:

    let info1={ name:"Mike" };
    let info2={ hobby:"write" };
    let studentInfo={ ...info1,...info2};
    console.log(studentInfo);// {name: "Mike", hobby: "write"};

       与数组的扩展运算符一样,其后可以跟表达式:

    const obj={
        ...(1<2?{a:1}:{a:2}),
        b:2,
    };
    console.log(obj); // {a: 1, b: 2}

       如果扩展运算符后面是一个空对象,则没有任何效果:

    let obj={...{},a:1};
    console.log(obj); //{a:1}

       如果扩展运算符的参数是null或undefined,这两个值编译时会被忽略,不会报错:

    let emptyObj={...null,...undefined}; //不会报错

       对象的扩展运算符与解构赋值的结合使用:

    let {x,y,...z}={x:1,y:2,m:3,n:4};
    console.log(x,y,z);//1 2 {a:3,b:4};

       上述代码中变量z对应的是解构赋值所在的对象,它获取赋值运算符右边所有尚未读取的属性,连通属性值一统拷贝过来。由于解构赋值要求等号右边是一个对象,所以如果等号右边是 undefined 或 null,就会报错,因为它们无法转为对象。

六、ES6中字符串扩展

       1.trim() : 用于除去字符串中空白符

    let str=' a bc de ';
    console.log(str.trim()); // "a bc de"
    console.log(str.trimLeft()); // "a bc de "
    console.log(str.trimRight()); //" a bc de"

       2.repeat() : 字符串重复次数

    let str="12345";
    console.log(str.repeat(2)); // "1234512345"

       3.includes() :是否包含传入参数,返回布尔值

    let str="hello world";
    console.log(str.includes("h")); // true
    console.log(str.includes("z")); //false

       4.starts/endsWith():是否已传入参数开头/结尾,返回布尔值

    let str="hello world";
    console.log(str.startsWith("hello")); // true
    console.log(str.endsWith("xyz")); // false

       5.padStart/End():接收两个参数,第一个参数为填充之后的字符串长度,第二个参数为填充元素

    let str="abc def";
    console.log(str.padStart(15,"*")); // ********abc def
    console.log(str.padEnd(20,"-")); // abc def-------------

七、ES6中数组扩展

       1.Array.from()

    function getNum(x,y,z){
        console.log(Array.isArray(arguments));//false
        console.log(Array.isArray(Array.from(arguments)));//true
    };
    getNum(1,2,3);

       使用Array.from转化前判断结果为false,并不是真正的数组,而转化后结果为true,已经从类数组转变为了真正的数组。

       2.Array.of()

作用:将一组值转换为数组,主要目的是弥补构造器Array的不足

       之前利用new操作符创建数组:

    let arr1=new Array(3);
    let arr2=new Array("3");
    console.log(arr1,arr2);// [empty × 3] ["3"]

       从输出结果可以看出我们的初衷并不是创建一个长度为3的空数组,这就是Array构造器创建数组的缺陷。
       利用Array.of新建数组:

    let arr1=Array.of(3);
    let arr2=Array.of("3");
    console.log(arr1,arr2); // [3] ["3"]

       Array.of()完美解决了Array构造器的缺陷,并且简化了利用构造器创建数组的操作。

       3.find()与findIndex()

find()用于找出第一个符合条件的数组元素,找不到则会返回undefined

    let infoArr=[ 
        {name:"Lucy",score:85},
        {name:"Jane",score:78},
        {name:"Michael",score:80}
    ];
    //返回name属性为Jane的对象
    let result=infoArr.find(item=>item.name=="Jane");
    console.log(result); // {name: "Jane", score: 78}
  • 注意细节:find()不会返回多个值,找到一个符合条件的元素就会返回。

findIndex():返回第一个符合条件的数组元素的索引,没有符合条件的则会-1。

    let infoArr=[ 
        {name:"Lucy",score:85},
        {name:"Jane",score:78},
        {name:"Michael",score:80}
    ];
    //返回score属性值为80的元素的索引
    let result=infoArr.findIndex(item=>item.score==80);
    console.log(result); // 2

       4.includes()

includes()用于判断数组中是否包含该元素,并返回一个布尔值。

    let arr=[1,2,3];
    let result1=arr.includes(2);
    let result2=arr.includes("a");
    console.log(result1,result2);// true  false

       indexOf()用于查找元素在数组中的索引值,基于此也可以实现与includes类似的功能:

    let arr=[1,2,3];
    let result1=arr.indexOf(2);
    let result2=arr.indexOf('b');
    console.log(result1,result2); //1 -1

       通过其返回的索引值结果我们也可以判断出数组中是否存在该元素,但是它对NaN的判断不准确。

    let arr=[1,NaN,3,6];
    let result1=arr.indexOf(NaN);
    console.log(result1); //-1
    let result2=arr.includes(NaN);
    console.log(result2); //true

       5.fill()

作用:给数组填充指定值,可以用于数组初始化

    let arr=new Array(5);
    console.log(arr.fill("*")); //["*", "*", "*", "*", "*"]

       使用fill()填充数组具有覆盖性:

    let arr =Array.of(1,2,3);
    console.log(arr.fill("a")); // ["a", "a", "a"]

       此外fill()还可以接收第二个和第三个参数,用于指定数据填充位置。

    let arr =Array.of("a","b","c");
    console.log(arr.fill("d",2,3)); // ["a", "b", "d"]

八、新的数据结构:Set与Map

       Set与数组形式相似,也是一种数据集合,区别在于它存储的值都是唯一的不能重复。创建一个Set实例:

    let s1=new Set();

       使用Set时传入数据有两种方式,一种为初始化时以数组形式传入,另一种为使用add()方法添加。

    let s1=new Set([1,2,3,true]);
    s1.add(4,"a");
    console.log(s1); // {1, 2, 3, true, 4,"a"}

       对于Set中数据的遍历,可以采用数组中的forEach方法:

    let s1=new Set([1,2,3,true]);
    s1.forEach(item=>console.log(item));// 1 2 3 true

       此外对于Set数据结构,还有一种for of方法:

    let s1=new Set(["a","b","c"]);
    for(let item of s1){
        console.log(item);  // a b c
    };

注意细节:Set本质上并不是一个数组。

    let s1=new Set([1,2,3]);
    console.log(Array.isArray(s1)); //false
    console.log(typeof s1);//object

       由输出结果不难发现,Set不是数组,而是形式上与数组类似的对象,即类数组。
       利用Set中数据的唯一性,我们可以轻松的实现数组的去重工作:

    let s1=new Set([1,1,2,2,3,3,4,4]);
    console.log(s1); //{1, 2, 3, 4}
    let arr=[1,2,5,3,1,3,NaN,false,NaN];
    //Set与扩展运算符结合使用,完成数组去重后的浅拷贝
    let newArr=[...(new Set(arr))];
    console.log(newArr);// [1, 2, 5, 3, NaN, false]

       Map也类似于对象,区别在于对象中的键名即属性名只能是字符串,而Map中存放的键可以是任意值。
       创建一个Map实例:

    let m1=new Map();

       Map存放数据的方式与数组、对象等其他数据结构都有差别:

    let m=new Map([
        ["name","Mike"],
        ["area","American"],
        [false,"hello"]
    ]);
    console.log(m);// {"name" => "Mike", "area" => "American", false => "hello"}

       除这种初始化方式外,还可以利用set添加数据:

    let m=new Map();
    m.set(true,"xyz");
    m.set([1,2,3],{name:"stark"});
    console.log(m);// {true => "xyz", Array(3) => {…}}

       既然有set添加数据,相应的必然有get获取数据:

    let m=new Map([
        ["a","hello"],
        [1,"world"],
        [false,"xyz"]
    ]);
    m.set([1,2,3],{name:"Michael"});
    console.log(m.get("a"),m.get(1)); // hello world
    console.log(m.get([1,2,3])); // undefined

注意细节:m.get([1,2,3])获取不到值的原因:get()比较的是栈区中的地址。
利用set添加数据时如果有重复的键,后面的会覆盖掉前面的。

Map结构遍历

Map 结构原生提供三个遍历器生成函数和一个遍历方法:

  1. keys():返回键名的遍历器.
  2. values():返回键值的遍历器。
  3. entries():返回所有成员的遍历器。
  4. forEach():遍历 Map 的所有成员。
    const map=new Map([
        ["a","hello"],
        ["b","world"]
    ]);
    for(let key of map.keys()){
        console.log(key); // a b
    };
    for(let value of map.values()){
        console.log(value); // hello world
    };
    for(let item of map.entries()){
        console.log(item[0],item[1]); //a hello   b world
    };
    map.forEach((item,index)=>console.log(item,index)); // hello a   world b

九、JS中的class类

1.创建class类

       在JavaScript中,创建实例对象的传统方法是通过构造函数生成:

    function Hero(name,height,country){
        this.name=name;
        this.height=height;
        this.country=country;
    };
    Hero.prototype.sayInfo=function(){
        console.log(`My name is ${this.name} and come from ${this.country}.`);
    };
    let stark=new Hero("stark",178,"American");
    stark.sayInfo(); // My name is stark and come from American.

       上面这种写法与传统的面向对象语言差异很大,很容易让初学者产生困惑。
       基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。用class改写传统的构造函数法:

    //定义Hero类
    class Hero{
        //定义构造方法
        constructor(name,height,country){
            this.name=name;
            this.height=height;
            this.country=country;
        };
        //定义方法
        sayInfo(){
            console.log(`My name is ${this.name} and come from ${this.country}.`);
        };
    };
    let stark=new Hero("stark",178,"American");
    stark.sayInfo(); // My name is stark and come from American.

       ES6中的类,完全可以可以看做构造函数的另一种简单写法,类的使用方法也与构造函数一致,直接对类使用new操作符创建实例对象。

2.constructor方法
       constructor方法是类的默认方法,通过new操作符创建实例对象时自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

    class Study{
    }
    //等同于
    class Study{
        constructor(){}
    }

       上面定义了一个空的类Study,JS引擎在编译时会自动为它添加一个空的constructor方法。
       constructor方法默认返回实例对象,但是我们可以在constructor内部指定返回特定对象。

    let obj={};
    class Cat{
        constructor(){
            return obj;
        }
    };
    console.log(new Cat() instanceof Cat);//false

       上面的类中constructor方法返回了另一个空对象,所以新创建的实例对象的构造器并不指向Cat类。
       ES6中的类与构造函数有诸多相似之处,它们的一个主要区别就是类必须使用new操作符来调用,而构造函数即使调用时没有new操作符也不会报错。

    class Cat{
        constructor(){}
    };
    Cat(); // TypeError: Class constructor Cat cannot be invoked without 'new'

3.class表达式
       与函数中一样的是,类也可以使用表达式的形式定义:

    let NewClass=class OldClass{
        getName(){
            return OldClass.name;
        }
    };

       使用表达式定义一个类,这个类的名字是NewClass而不是oldClass,oldClass只在class的内部代码可用,指代当前类。

    let class1=new NewClass();
    console.log(class1.getName()); // OldClass
    console.log(OldClass.name); // ReferenceError: OldClass is not defined

       输出结果表示,OldClass只在class内部能够访问到。
       采用类的表达式写法,可以写出立即执行的class类:

    let Lucy=new class{
        constructor(name){
        this.name=name;
        }
        sayName(){
            console.log(`I am ${this.name}.`)
        }
    }('Lucy');
    Lucy.sayName(); // I am Lucy.

4.class中的继承
       ES6之前传统意义上的继承:

    function Hero(name,country){
        this.name=name;
        this.country=country;
    };
    Hero.prototype.sayName=function(){
        console.log(`My name is ${this.name} and from ${this.country}.`);
    };
    function HeroAbility(name,country,ability){
        //使用call继承父对象的属性
        Hero.call(this,name,country);
        this.ability=ability;
    };
    //使用浅拷贝继承父对象的方法
    for(let p in Hero.prototype){
        HeroAbility[p]=Hero.prototype[p];
    };
    //定义子对象的方法
    HeroAbility.prototype.sayDetail=function(){
        console.log(`My name is ${this.name} and from ${this.country} and have ability of ${this.ability}.`)
    };
    (new HeroAbility("superman","American","fly").sayDetail());
    //My name is superman and from American and have ability of fly.

       使用ES6 class中的extends实现继承:

    class Hero{
        constructor(name,country){
            this.name=name;
            this.country=country;
    };
        sayName(){
            console.log(`My name is ${this.name} and from ${this.country}.`);
        };
    };
    class HeroAbility extends Hero{
        constructor(name,country,ability){
            //继承父类的属性
            super(name,country);
            this.ability=ability;
        };
        sayDetail(){
            console.log(`My name is ${this.name} and from ${this.country} and have ability of ${this.ability}.`)
        };
    };
    (new HeroAbility("Batman","American","Batcar").sayDetail());
    //My name is Batman and from American and have ability of Batcar.

       constructor方法中出现的super关键字,表示父类的构造函数,用来新建父类的this对象。
       子类必须在constructor方法中调用super方法,否则新建实例时会报错,这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性与方法,然后再加上自身的属性与方法。如果不调用super方法,子类就得不到this对象。

十、对象的扩展

1.属性相关方法

Object.defineProperty():精细化设置一个对象的属性

    let obj={};
    Object.defineProperty(obj,"age",{
        value:20,  //默认值
        writable:true, //能否修改
        enumerable:true, //是否可枚举
        configurable:false //能否删除
    });
    console.log(obj); //{age: 20}

Object.getOwnPropertyDescriptor():返回指定对象所有自身属性(非继承属性)的描述对象。

    let obj={ name:"Miacael" };
    console.log(Object.getOwnPropertyDescriptor(obj,"name"));
    //{value: "Miacael", writable: true, enumerable: true, configurable: true}

Object.defineProperties():精细化设置一个对象的多个属性

    let obj={};
    Object.defineProperties(obj,{
        "name":{
            value:"wangcai",
            writable:true,
            enumerable:true,
            configurable:false,
        },
        "address":{
            value:"Canada",
            writable:true,
            enumerable:true,
            configurable:false,
        }
    });
    console.log(Object.getOwnPropertyDescriptor(obj,"name"));
    //{value: "wangcai", writable: true, enumerable: true, configurable: false}
    console.log(Object.getOwnPropertyDescriptor(obj,"address"));
    //{value: "Canada", writable: true, enumerable: true, configurable: false}

Object.getOwnPropertyNames():以数组形式返回自身的属性

    let obj = {
        name:"Lucy",
        from:"Canada"
    };
    console.log(Object.getOwnPropertyNames(obj)); // ["name", "from"]

Object.keys():与Object.getOwnpropertyNames()功能类似

    let obj = {
        name:"Kang",
        from:"China"
    };
    console.log(Object.keys(obj)); // ["name", "from"]

Object.values():以数组形式返回对象的属性值

    let obj = {
        name:"Kang",
        from:"China"
    };
    console.log(Object.values(obj)); // ["Kang", "China"]

2.继承相关方法

Object.create():从一个现有对象进行继承得到一个全新的对象,新对象可以访问旧对象的属性与方法

    function Person(name){
        this.name=name;
    };
    Person.prototype.Say=function(){
        console.log(`I am ${this.name}.`)
    };
    let p1=new Person("xiaozhang");
    let p2=Object.create(p1);
    p2.name="xiaowang";
    console.log(p2.Say()); // I am xiaowang.

Object.getPrototypeOf():用于获取指定对象的构造器的prototype属性

    var obj={};
    var arr=[];
    console.log(Object.getPrototypeOf(obj)===Object.prototype); // true
    console.log(Object.getPrototypeOf(arr)===Array.prototype); // true

防篡改方法

       Object.preventExtensions():不允许新增,可以删除和修改

    let obj={ name:"xiaoming" };
    Object.preventExtensions(obj);
    obj.sex="man";
    console.log(obj); // {name: "xiaoming"}

       Object.seal():不允许新增与删除,可以修改

    let obj1={name:"xiaoqiang"};
    Object.seal(obj1);
    obj1.sex="man";
    obj1.name="xiaogang";
    delete obj1.name;
    console.log(obj1); // {name: "xiaogang"}

       Object.freeze():不允许新增、删除与修改

    let obj2={name:"xiaohong"};
    Object.freeze(obj2);
    obj2.hobby="read";
    delete obj2.name;
    obj2.name="xiaoming";
    console.log(obj2); // {name:"xiaohong"}

3.对象的简写

对象属性的简写:
       条件:属性的值为变量且变量名称与键名一致

    let name="Lucy",age=20;
    let obj={
        name,   //等同于name:name
        age     //等同于age:age
    };
    console.log(obj); // {name: "Lucy", age: 20}

对象中方法的简写

    let obj1={
        //简写前
        sayHello:function(){
            console.log("Hello...");
        },
        //简写后
        sayHi(){
            console.log("Hi...");
        }
    };
    obj1.sayHello(); // Hello...
    obj1.sayHi(); // Hi...

4.Object.assign()

用于对象的合并,将源对象的所有的可枚举属性,复制到目标对象。

    let target={};
    let source1={
        name:"Michael",
        age:22
    };
    let source2={
        name:"Mary",
    };
    console.log(Object.assign(target,source1,source2)); // {name: "Mary", age: 22}

注意细节:

  • 第一个参数是目标对象,assign这个方法把其它的参数中的属性全部加在第一个参数身上。
  • 第一个参数在属性复制过程中,可以会被修改,后面的会覆盖前面的属性。
  • assign这个方法的返回值就是第一个参数的引用,也就是返回了第一个参数。
  • assign不能拷贝继承过来的属性与不可枚举的属性。

       ES6中的内容远不止列举出的这些,上文仅为前一阶段学习的总结,希望与正在学习JS的同学一同进步,一起提高。