深入理解ES6 004【学习笔记】

扩展对象的功能

  • 普通对象 具有js对象所有默认内部行为的
  • 特异对象 具有某些与默认行为不符的内部行为
  • 标准对象 es6规范中定义的对象,Array/Date等
  • 内建对象 脚本开始执行时存在于javascript执行环境的对象,所有标准对象都是内建对象

对象字面量语法扩展

  • 属性初始值的简写,当一个对象的属性与本地变量同名时,不必再写冒号和值
  • 对象方法的简写语法
  • 可计算属性名
// javascript 引擎会在可访问作用域中查找其同名变量;找到,则该量变的值被赋给对象字面量里的同名属性,在现在的js开发中,为对象字面量的属性赋同名局部变量的值是一种常见的做法,这种简写方法有助于消除命名错误
function createPerson(name,age){
   return {
      name,
   age
   }
}
// 对象方法的简写 消除冒号和function关键字。如下
var person = {
  name:"Nicholas",
  sayName(){
     console.log(this.name)
  }
}
// 通过对象方法简写语法创建的方法有一个name属性,其值为小括号前的名称,上例中person.sayName()方法的name属性的值为"sayName"

es5有些属性名要通过[]方括号来设置和访问其值,如

var person = {},lastName = "last name"
person["first name"] = "Nicholas"
person[lastName] = "Zakas"

console.log(person["first name"]); // Nicholas
console.log(person[lastName]); //Zakas

因为属性名称中都含有空格,因而不可使用点的方式引用,却可以使用方括号,因为它支持通过任何字符串值作为名称访问属性值。

在对象字面量中,可以直接使用字符串字面量作为属性名称,如下

var person = {
  "first name": "Nicholas"
}
console.log(person["first name"]); // "Nicholas"
// Es5 无法为通过计算得到的变量值,作为对象的字面量定义该属性
// es6 通过中括号方式可以定义这样的字面量
let lastName = "last name";
let person  = {
  "first name": "Nicholas",
  [lastName]:"Zakas"
}
console.log(person["first name"]); // Nicholas
console.log(person[lastName]); // Zakas
console.log(person["last name"]) // Zakas

Object.is()

该方法来弥补全等运算的不准确运算。这个方法接受两个参数,如果这两个参数类型相同有相同的值,则返回true。

Object.is(NaN,NaN) // true
NaN === Nan //false

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

console.log(NaN==NaN) //false
console.log(NaN==NaN) //true
console.log(Object.is(NaN,Nan)) //true

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

Object.assign()

混合(Mixin)是javascript中实现对象组合最流行的一种模式。在一个mixin方法中,一个对象接收来自另一个对象的属性和方法,许多javascript库中都有类似的mixin方法:

// 浅复制
function minxin(receiver, supplier){
  Object.keys(supplier).forEach(function(key){
    receiver[key] = supplier[key]
  })
  return receiver
}

Object.assign()方法来实现相同的功能,这个方法接受一个接收对象和任意数量的源对象,mixin()方法使用赋值操作符=来复制相关属性,却不能复制访问器属性到接收对象中,因此最终添加的方法弃用mixin而改用assign作为方法名。

Object.assign()方法可以接受任意数量的源对象,并按指定顺序将属性复制到接收对象中。如果多个源对象具有同名属性,则排位靠后的源对象会覆盖排位靠前的。

Object.assign()方法不能将提供者的访问器属性复制到接收对象中。由于Object.assign()方法执行了赋值操作,因此提供者的访问器属性终会转变为接收对象中的一个数据属性。

var receiver = {},supplier = {
      get name() {
       return "file.js"
   }
};
Object.assign(receiver,supplier);
var descriptor = Object.getOwnPropertyDescriptior(receiver,"name")
console.log(descriptor.value); //file.js
console.log(descriptor.get); // undefined

重复的对象字面量属性

es5 属性重名 会报错,es6不再做这样强制的约束,对于每一组重复属性,都会取最后一个取值。

自有属性枚举顺序

es6严格规定了对象的自有属性被枚举时的返回顺序,这会影响到Object.getOwnPropertyName()方法及Reflect.ownKeys返回属性的方式,Object.assign()方法处理属性的顺序也将随之改变,规则如下:

  • 所有数字键按升序排序
  • 所有字符串键按照它们被加入对象的顺序排序
  • 所有symbol键,按照它们被加入对象的顺序排序。

增强对象原型

es5都是javascript编程最重要的设定之一,虽然在es5中添加了Object.getPrototypeOf()方法来返回任意对象的原型,但仍缺少对象在实例化后改变原型的标准方法。es6中添加了Object.setPrototypeOf()方法来改变这一现状,通过这一方法可以改变任意指定对象的原型,它接受两个参数:被改变原型的对象及替代第一个参数原型对象。

let person={
  getGreeting(){
    return "Hello";
  }
}
let dog = {
  getGreeting(){
    return "Woof";
  }
}

// 以person对象为原型
let friend = Ojbect.create(person);
console.log(friend.getGreeting()); // Hello
console.log(Object.getPrototypeOf(friend) === person) // true

// 将原型设置为dog
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting()) // Woof
console.log(Object.getPrototypeOf(friend)===dog) // true

对象原型的真实值被储存在内部专用属性[[Prototype]]中,调用Object.getPrototypeOf()方法返回储存在其中的值,调用Ojbect.setPrototypeOf()方法改变其中的值。然而,这不是操作[[Prototype]]值的唯一方法。

prototype

  1. 我们需要牢记两点:①__proto__constructor属性是对象所独有的;② prototype属性是函数所独有的,因为函数也是一种对象,所以函数也拥有__proto__constructor属性。
  2. __proto__属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(父对象)里找,一直找,直到__proto__属性的终点null,再往上找就相当于在null上取值,会报错。通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链。
  3. prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法,即f1.__proto__ === Foo.prototype
  4. constructor属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function。

简化原型访问的Super作用

子类方法覆写父类方法,还要调用传参给父类方法; ECMAScript 6引入了Super引用的特性,使用它可以更便捷地访问对象原型

let person={
  getGreeting(){
    return "Hello";
  }
}
let dog = {
  getGreeting(){
    return "Woof";
  }
}
let friend = {
  getGreeting(){
    return Object.getPrototypeOf(this).getGreeting.call(this)+', hi!'
  }
}

// 以person对象为原型
Object.setPrototypeOf(friend,person)
console.log(friend.getGreeting()); // Hello,hi!
console.log(Object.getPrototypeOf(friend) === person) // true

// 将原型设置为dog
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting()) // Woof,hi!
console.log(Object.getPrototypeOf(friend)===dog) // true

es6简化了这种写法:

let friend = {
  getGreeting(){
    // return Object.getPrototypeOf(this).getGreeting.call(this)+', hi!'
    return super.getGreeting()+", hi~"
  }
}
// 注意要使用简写方法对象中使用super引用,如下会报错
let friend = {
  getGreeting:function(){
    // return Object.getPrototypeOf(this).getGreeting.call(this)+', hi!'
    return super.getGreeting()+", hi~"
  }
}

super引用不是动态变化的,它总是指向正确的对象,在这个示例中,无论有多少其他方法继承了getGreeting方法,super.getGreeting()始终指向

正式的方法定义

es6中正式将方法定义为一个函数,它会有一个内部的[[HomeObject]]属性来容纳这个方法从属性的对象。如下:

let person = {
  // 这是方法
  getGreeting(){
    return "Hello"
  }
};

// 不是方法
function shareGreeting(){
  return "Hi~";
}

理解:这示例中定义了person对象,它有一个getGreeting()方法,由于直接把函数赋值给了person对象,因而getGreeting()方法的[[HomeObject]]属性值为person。而下面的方法shareGreeting创建时未将其赋值给一个对象,因而该方法没有明确定义[[HomeObject]]属性。在大多数情况下这点小差别无关紧要,但是当使用Super引用时就变得非常重要了。

super的所有引入都是通过[[HomeObject]]属性来确定后续运行过程。第一步在[[HomeObject]]属性上调用Object.getPrototypeOf()方法来检索原型引用;然后搜寻原型找到同名函数,最后,设置this绑定并且调用相应的方法。

//  自己分析一下
let person={
  getGreeting(){
    return "Hello";
  }
}

let friend = {
  getGreeting(){
    // return Object.getPrototypeOf(this).getGreeting.call(this)+', hi!'
    return super.getGreeting()+", hi~"
  }
}
Object.setPrototypeOf(friend,person)
console.log(friend.getGreeting()) // "Hello hi~"

总结

  • 属性
  • 简化属性定义语法,使将当前作用域中的同名变量赋值给对象的语法变得更加简洁;
  • 添加可计算属性名特性,允许为对象指定非字面量属性名;
  • 添加对象方法简写语法,在对象字面量中定义方法时可以省略冒号和function关键字
  • es6严格模式下对象字面量重复名称校验,即使在同一个对象字面量中定义两个同名属性也不会抛出错误
  • Object.assign()方法可以一次性更改对象中的多个属性,如果使用混入(mixin)模式这将非常有用
  • Object.is()方法对于所有值进行严格等价判断,当将其用于处理javascript值问题时比===更加安全
  • Object.setPrototypeOf()方法,对象被创建后修改它的原型
  • super关键字调用原型上的方法,此时的this绑定会被自动设置为当前作用域的this值

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://joyjs.cn/archives/4329

(0)
Walker的头像Walker
上一篇 2025年3月8日 12:51
下一篇 2025年3月8日 10:59

相关推荐

  • Go工程师体系课 protoc-gen-validate【学习笔记】

    protoc-gen-validate 简介与使用指南 ✅ 什么是 protoc-gen-validate protoc-gen-validate(简称 PGV)是一个 Protocol Buffers 插件,用于在生成的 Go 代码中添加结构体字段的验证逻辑。 它通过在 .proto 文件中添加 validate 规则,自动为每个字段生成验证代码,避免你手…

    个人 2025年4月27日
    20900
  • 深入理解ES6 012【学习笔记】

    代理(Proxy)和反射(Reflection)API 代理是一种可以拦截并改变底层javascript引擎操作的包装器,在新语言中通过它暴露内部运作对象,从而让开发者可以创建内建的对象。 代理陷阱 覆写的特性 默认特性 get 读取一个属性值 Reflect.get() set 写入一个属性值 Reflect.set() has in操作符 Reflect…

    个人 2025年3月8日
    39300
  • 【开篇】

    我是Walker,生于八十年代初,代码与生活的旅者。全栈开发工程师,游走于前端与后端的边界,执着于技术与艺术的交汇点。 代码,是我编织梦想的语言;项目,是我刻画未来的画布。在键盘的敲击声中,我探索技术的无尽可能,让灵感在代码里永恒绽放。 深度咖啡爱好者,迷恋每一杯手冲的诗意与仪式感。在咖啡的醇香与苦涩中,寻找专注与灵感,亦如在开发的世界中追求极致与平衡。 骑…

    2025年2月6日 个人
    65400
  • 深入理解ES6 013【学习笔记】

    用模块封装代码 javascript用“共享一切”的方法加载代码,这是该语言中最容易出错且另人感到困惑的地方。其他语言使用诸如包这样的概念来定义代码作用域。在es6以前,在应用程序的每一个js中定义的一切都共享一个全局作用域。随着web应用程序变得更加复杂,js代码的使用量也开始增长,这一做法会引起问题,如命名冲突和安全问题。es6的一个目标是解决作用域问题…

    个人 2025年3月8日
    41400
  • 从0到1落地微前端架构 001【学习笔记】

    微前端 js 隔离css 隔离元素隔离生命周期预加载数据通信应用跳转多层嵌套 说明 使用的是 Mermaid 的 flowchart 语法,Markdown 渲染器如 Typora、VitePress、一些 Git 平台都支持。 保留了: 基座应用 main-vue3 各子应用:child-nuxt2-home、child-vue2-job、child-vu…

    2025年4月20日
    28800

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
欢迎🌹 Coding never stops, keep learning! 💡💻 光临🌹