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可以包含表达式
在之前比较两个值通常使用 ==(比较相等元素运算符)和 ===(严格相等运算符),前者有时会出现强制类型转化,所以一般会使用后者。但是,后者的结果也不一定准确。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并且它不会发生强制类型转换。
混入是指从一个对象接收另一个对象的属性与方法,并且无需继承就可以让另一个对象获得新的属性,在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); //12object.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前面
在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); //trueObject.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__中
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(){} //不是方法