深入理解ES6扩展的对象的方法

对象的类别

ES6规范规定对象的类别:
普通对象:拥有JS对象的所有默认的内部行为。
奇异对象:其内部行为在某些方面有别于默认行为。
标准对象:在ES6中定义的对象。标准对象可以是奇异亦可以是普通的。
内置对象:在脚本开始运行时由JS运行环境提供的对象。

对象字面量语法的扩展

        对象字面量是创建对象的一种简洁语法,ES6让它更强大、更简洁。

属性初始化器的速记法

ES6之前的版本,对象字面量是键/值对的集合,会出现属性初始化重复。ES6属性初始化器的速记法消除了对象名称与本地变量重复的情况,重复省略冒号与值。

function createPerson(name, age) {
      return {
            name,
            age
      };
}

方法简写

        在ES6之前的版本中,必须指定一个名称并用完整的函数定义来为对象添加方法。ES6为对象字面量方法赋值简写 省去 function 和冒号。

var person = {
         name: "lucy",
         sayName() {
             console.log(this.name);
         }
}

需计算属性名

        在ES5中只要用方括号表示法代替小数点表示法即可。方括号允许将变量或字符串字面量指定为属性名,而在字符串中允许存在作为标识符时会导致语法错误的特殊字符。在ES6中需计算属性名是对象字面量语法的一部分,用方括号表示。用法与之前基本一致。

var lastName = "last name";
var person = {
         "first name": "nic",
          [lastName]: "za"
}
console.log(person["first name"]);  //nic
console.log(person[lastName]);  //za
var suffix = " name"; //一定注意name前面有一个空格
var person = {
         ["first" + suffix]: "ddd",
         ["last" + suffix]: "aaa"
}
console.log(person["first name"]);  //ddd
console.log(person["last name"]);  //aaa

可以包含表达式

新的方法

JavaScript比较两个值: Object.is()

        在之前比较两个值通常使用 ==(比较相等元素运算符)和 ===(严格相等运算符),前者有时会出现强制类型转化,所以一般会使用后者。但是,后者的结果也不一定准确。Object.is() 弥补了残留下的怪异点。此方法有两个参数,二者相等(类型相等,值相同)时返回 true。

console.log(5 == "5"); //true 

        此处出现了强制类型转化的情况,将字符串5转化成了数字5,使二者相等。

console.log(+0 === -0); //true
console.log(NaN === NaN); //false

        此处出现了严格等于运算符残留的怪异点。

console.log(Object.is(NaN, NaN)); //true
console.log(Object.is(+0, -0)); //false

        怪异点能够被新的这个方法所解决。

console.log(Object.is(5, "5")); //false
console.log(Object.is(5, 5)); //true

        并且它不会发生强制类型转换。

混入:object.assign()

        混入是指从一个对象接收另一个对象的属性与方法,并且无需继承就可以让另一个对象获得新的属性,在ES6之前存在,只不过ES6就是将它标准化,以及拥有多个供应者(supplier)和可以将访问属性复制到接收者上。

var supplier = {};
function mixin(receiver, supplier) {
// 迭代对象supplier并且遍历其中的每个元素,将supplier的属性复制给receiver
         Object.keys(supplier).forEach(function(key) {
                 receiver[key] = supplier[key];
          })
         return receiver;
}

        把supplier浅复制给receiver

function a() {};
        a.prototype = {
            constructor: a,
            emit: function() {},
            on: function() {}
        }
var myObject = {};
mixin(myObject, a.prototype);
console.log(myObject); //{constructor: ƒ, emit: ƒ, on: ƒ}

        无需继承得到新的属性

 person1 = {
            name: "li",
            age: 12
        }
var my = {};
Object.assign(my, person1.prototype);
console.log(my);
var person2 = {
      name: "liu"
}
Object.assign(my, person1, person2);
console.log(my.age); //"liu"
console.log(my.name); //12

        object.assign()可以替代mixin()并且它可以有多个供给者,只不过重复的属性,后面的会覆盖前面的。

var receiver = {},
supplier = {
    get name() {
         return "liu"
    }
  };
Object.assign(receiver, supplier);
var descriptor = Object.getOwnPropertyDescriptor(receiver, "name");
console.log(descriptor.value);//liu

        未在接收者上创建访问器属性,供应者拥有访问器属性,通过object.assign()使用赋值运算符将供给者中的访问器属性转变成接受者的数据属性。supplier拥有一个name的访问器属性,在使用object.assign()时receiver.name就作为一个数据属性供给者中的存在了。

重复的对象字面量属性

        在ES5严格模式为对象字面量引入了一个检查,若找到重复的属性名,就会报错。而在ES6移除了重复属性的检查,出现重复时后面的属性会成为该属性的实际值。

"use strict";
 var person = {
     name: "liu",
     name: "z" //在ES5中会报错:语法错误而在ES6中并不会报错,只是覆盖了前面那个
 }

自有属性的枚举顺序

        ES5未定义,而抛给了JS引擎厂商。ES6中严格定义了对象自有属性在被枚举时返回的顺序,影响到Object.getOwnPropertyNames()和Reflect.ownKeys和Object.assign()。而for-in 和Object.keys()和JSON.stringify()的枚举顺序未收到影响,未被明确规定。
顺序:
1.数字类型键升序排列
2.字符串类型键按添加对象的顺序排列
3.符号类型的键按添加顺序排列

 var obj = {
            a: 1,
            0: 1,
            c: 1,
            2: 1,
            b: 1,
            1: 1
}
obj.d = 1;
console.log(Object.getOwnPropertyNames(obj).join()); 
//0,1,2,a,c,b,d

        首先先数字升序,然后按添加顺序排列字母,此例子c添加比b早,所以排列在b前面

更强大的原型

修改对象的原型 Object.setPrototypeOf()

在ES6之前原型一旦初始化完成会保持不变,虽然ES5中有一个Object.getPrototypeOf方法获取对象中的原型,但是仍没有修改原型的方法.ES6添加了Object.setPrototypeOf()的方法修改对象的原型,它包含两个参数,被修改原型的对象和将会成为前者原型的对象。前者可以看作是之前的receiver,而后者可以看作是supplier。

 var person = {
     getGreeting() {
          return "hello";
     }
};
var dog = {
    getGreeting() {
       return "woof"
    }
};
let friend = Object.create(person);
console.log(friend.getGreeting()); //hello
console.log(Object.getPrototypeOf(friend) === person); //true

        Object.create()创建原型。因为把创建的person的原型赋给了friend所以它可以调用原型中的属性,并且它们两个的原型相同,所以判断时返回true。

Object.setPrototypeOf(friend, dog);
console.log(friend.getGreeting());
console.log(Object.getPrototypeOf(friend) === person); //false
console.log(Object.getPrototypeOf(friend) === dog); //true

        把friend的原型修改为dog里面的原型。

console.log(friend.__proto__); //{getGreeting: ƒ}

        对象原型的实际值会存储在__proto__中

使用super引用的简单原型访问

ES5

 let person = {
     getGreeting() {
         return "hello"
     }
};
let dog = {
    getGreeting() {
        return "woof"
    }
};
let friend = {
    getGreeting() {
        return Object.getPrototypeOf(this).getGreeting.call(this) + ",hi"
    }
};
Object.setPrototypeOf(friend, person);
console.log(friend.getGreeting());

        friend上的getGreeting()调用了对象上的同名方法。
        Object.getPrototypeOf()方法确保了能调用正确的原型,并在其返回结果上添加了一个字符串,而附加的call(this)代码则能够确保正确设置原型方法内部的this值。此方法看起来比较麻烦,ES6简化了该方法,引入了super,super是指向当前对象的原型的一个指针,实际上就是Object.getPrototypeOf(this)的值

let person = {
            getGreeting() {
                return "hello"
            }
        };
let dog = {
    getGreeting() {
         return "woof"
    }
};
let friend = {
     getGreeting() {
        return super.getGreeting() + ",hi"
      }
};
Object.setPrototypeOf(friend, person);
console.log(friend.getGreeting());

        特别注意:这个引用是位于简写方法之内的,在简写方法外使用super会触发语法错误。

let friend = {
    getGreeting: function() {
         return super.getGreeting() + ",hi"
          // Uncaught SyntaxError: 'super' keyword unexpected here
            }
};
let person = {
            getGreeting() {
                return "hello"
            }
        };
let dog = {
    getGreeting() {
         return "woof"
    }
};
let friend = {
     getGreeting() {
        return super.getGreeting() + ",hi"
        // es5写法 return Object.getPrototypeOf(this).getGreeting.call(this) + ",hi"
      }
};
Object.setPrototypeOf(friend, person);
let relative = Object.create(friend);
console.log(person.getGreeting()); //hello
console.log(friend.getGreeting()); //hello,hi
console.log(relative.getGreeting()); //hello,hi 
//如果采用ES5的写法此处会报错 Uncaught RangeError: Maximum call stack size exceeded

        在多级继承中,ES6的这种方法就尤为强大,super的引用并非动态的,它总是能指向正确的对象,不会发生堆栈错误。

正式“方法”定义

在ES6之前方法仅仅指对象的函数属性,ES6给它下了一个正式的定义。方法是一个拥有[[homeObject]]内部属性的函数,此内部属性指向该方法所属的对象。

let person = {
    //方法
    getGreeting(){
        return "hello"
    }
};
function shareGreeting(){}
//不是方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值