资讯专栏INFORMATION COLUMN

深入理解ES6之《扩展对象》

fireflow / 265人阅读

摘要:属性初始值的简写当对象字面量只有一个属性的名称时,引擎会在可访问作用域中查找其同名变量如果找到则该变量的值被赋给对象字面量里的同名属性对象方法的简写可计算属性名在中如果属性名中包含空格或者是动态的字符串变量作为属性名,则需要用方括号来访问,

属性初始值的简写

当对象字面量只有一个属性的名称时,JS引擎会在可访问作用域中查找其同名变量;如果找到则该变量的值被赋给对象字面量里的同名属性

function createPerson(name, age) {
  return {
    name,
    age
  }
}
对象方法的简写
var person = {
  name: "angela",
  sayName() {
    console.log(this.name)
  }
}
可计算属性名

在ES5中如果属性名中包含空格或者是动态的字符串变量作为属性名,则需要用[]方括号来访问,如下所示

var person = {},
  lastName = "last name";
person["first name"] = "Li"
person[lastName] = "yun hua"

这种方式适用于属性名提前已经或可被字符串字面量表示的情况,如果属性名“first name”被包含在一个变量中或者需要通过计算才得到该变量的值
ES6支持了可计算属性名
比方说上面的代码ES6可简化写成如下:

let lastName = "last name";
var person = {
  "first name": "Li",
  [lastName]: "yun hua"
}

甚至方括号中内容同样可以使用表达式作为属性的可计算名称

var suffix = "name"
var person = {
  ["first " + suffix]: "Li",
  ["last " + suffix]: "yun hua"
}

也就是说任何可用于对象实例括号记法的属性名同样可以作为对象字面量中计算属性名

Object.is

由于全等===有一些特例:1、+0和-0相等 2、NaN和NaN不完全相等
故ES6引用了Object.is方法来弥补全等运算符的不准备运算
对Object.is方法来说,其运算结果大部分情况与===运算符相同,唯一区别在于+0和-0被识别为不相等,NaN和NaN被识别为相等

Object.assign

Object.assign方法接受任意数量的源对象,并按指定的顺序将属性复制到接收对象中,所以如果多个源对象具有同名属性,则排位靠后的源对象会覆盖排位靠前的
有一个需要特别注意的点是Object.assign方法不能将提供者的访问器属性复制到接收对象中,由于Object.assign执行了赋值操作,因此提供者的访问器属性最终会被转变为接收对象中的一个数据属性

var receiver = {},
  supplier = {
    get name() {
      return "file.js"
    }
  }
Object.assign(receiver, supplier)
var desc = Object.getOwnPropertyDescriptor(receiver, "name")
console.log(desc.value)//file.js
console.log(desc.get)//undefined
重复的对象字面量属性

在ES5严格模式下,对于对象字面量重复属性则会抛出错误
但在ES6严格模式下,不会报错,取值会选取最后一个

"use strict"
var person = {
  name: "lisa",
  name: "angela"
}
console.log(person.name)//angela
自有属性的枚举顺序

所有数字键按升序排序

所有字符串按照它们被加入对象的顺序排序

所有symbol键按照它们被加入对象的顺序排序

var obj = {
  a: 1,
  0: 1,
  c: 1,
  2: 1,
  b: 1,
  1: 1
}
obj.d = 1
console.log(Object.getOwnPropertyNames(obj).join(""))//012acbd
改变对象的原型

ES5中可以通过Object.getPrototypeOf来返回任意指定对象的原型
ES6中添加了Object.setPrototypeOf来改变任意指定对象的原型

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.setPrototypeOf(friend, dog)
console.log(friend.getGreeting())//woof
console.log(Object.getPrototypeOf(friend) === dog)//true
简化了原型访问的Super引用

在ES5中如果要调用父类的方法,则一般是通过如果这种方式,也就是获得原型对象再通过call来调用
Object.getPrototypeOf(this).getGreeting.call(this)

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

但是在多重继承的情况下,上述方法则会出错,举例来说

var person = {
  getGreeting() {
    return "hello"
  }
}
var friend = {
  getGreeting() {
    return Object.getPrototypeOf(this).getGreeting.call(this) + ",hi!";
  }
}
Object.setPrototypeOf(friend, person)
var relative = Object.create(friend)
console.log(person.getGreeting())//hello
console.log(friend.getGreeting())//hello,hi!
console.log(relative.getGreeting())// 报错 Uncaught RangeError: Maximum call stack size exceeded

ES6中通过super关键字可轻松解决问题

var person = {
  getGreeting() {
    return "hello"
  }
}
var friend = {
  getGreeting() {
    return super.getGreeting.call(this) + ",hi!";
  }
}
Object.setPrototypeOf(friend, person)
var relative = Object.create(friend)
console.log(person.getGreeting())//hello
console.log(friend.getGreeting())//hello,hi!
console.log(relative.getGreeting())// hello,hi

大家可能会疑惑super是怎么做到知道真正的调用对象是哪个
这其实是因为ES6中正式将方法定义为一个函数,它会有一个内部的[[HomeObject]]属性来容纳这个方法从属的对象

var person = {
  // 是方法
  getGreeting() {
    return "hello"
  }
}
function shareGreeting(params) {
  return "Hi!"
}

person.getGreeting方法的[[HomeObject]]属性为person,而shareGreeting函数未将其赋值给一个对象,因而没有明确定义其[[HomeObject]]属性

super的所有引用都通过[[HomeObject]]属性来确定后续的运行过程

在[[HomeObject]]属性上调用Object.getPrototypeOf方法来检索原型的引用

搜索原型找以同名函数

设置this绑定并调用相应的方法

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/112446.html

相关文章

  • 深入理解ES6扩展对象

    摘要:属性初始值的简写当对象字面量只有一个属性的名称时,引擎会在可访问作用域中查找其同名变量如果找到则该变量的值被赋给对象字面量里的同名属性对象方法的简写可计算属性名在中如果属性名中包含空格或者是动态的字符串变量作为属性名,则需要用方括号来访问, 属性初始值的简写 当对象字面量只有一个属性的名称时,JS引擎会在可访问作用域中查找其同名变量;如果找到则该变量的值被赋给对象字面量里的同名属性 f...

    marek 评论0 收藏0
  • 深入理解ES6扩展对象

    摘要:属性初始值的简写当对象字面量只有一个属性的名称时,引擎会在可访问作用域中查找其同名变量如果找到则该变量的值被赋给对象字面量里的同名属性对象方法的简写可计算属性名在中如果属性名中包含空格或者是动态的字符串变量作为属性名,则需要用方括号来访问, 属性初始值的简写 当对象字面量只有一个属性的名称时,JS引擎会在可访问作用域中查找其同名变量;如果找到则该变量的值被赋给对象字面量里的同名属性 f...

    Scliang 评论0 收藏0
  • 深入理解ES6《用模块封装代码》

    摘要:导入模块的代码执行后,实例化过的模块被保存在内存中,只要另一个语句引用它就可以重复使用它和的一个重要的限制是它们必须在其它语句和函数之外使用,也就是说不允许出现在语句中,不能有条件导出或以任何方式动态导出。 什么是模块 模块是自动运行在严格模式下并且没有办法退出运行的Javascript代码 在模块的顶部this的值是undefined 其模块不支持html风格的代码注释除非用def...

    BigTomato 评论0 收藏0
  • 深入理解ES6《用模块封装代码》

    摘要:导入模块的代码执行后,实例化过的模块被保存在内存中,只要另一个语句引用它就可以重复使用它和的一个重要的限制是它们必须在其它语句和函数之外使用,也就是说不允许出现在语句中,不能有条件导出或以任何方式动态导出。 什么是模块 模块是自动运行在严格模式下并且没有办法退出运行的Javascript代码 在模块的顶部this的值是undefined 其模块不支持html风格的代码注释除非用def...

    muddyway 评论0 收藏0
  • 深入理解ES6《用模块封装代码》

    摘要:导入模块的代码执行后,实例化过的模块被保存在内存中,只要另一个语句引用它就可以重复使用它和的一个重要的限制是它们必须在其它语句和函数之外使用,也就是说不允许出现在语句中,不能有条件导出或以任何方式动态导出。 什么是模块 模块是自动运行在严格模式下并且没有办法退出运行的Javascript代码 在模块的顶部this的值是undefined 其模块不支持html风格的代码注释除非用def...

    AbnerMing 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<