资讯专栏INFORMATION COLUMN

ES6--对象的扩展

animabear / 2908人阅读

摘要:若数值字符串和布尔值做为待合并数据,合并至目标目标对象时,只有字符串会以数组形式,拷贝到目标对象。上面代码中,布尔值数值字符串分别转成对应的包装对象,可以看到它们的原始值都在包装对象的内部属性上面,这个属性是不会被拷贝的。

延续之前的关于ES6的学习内容整理,该篇主要是整理ES6中关于对象的扩展,希望对大家有帮助。之前已经整理了ES6--字符串扩展和ES6--函数扩展,大家有兴趣可以移步了解。

属性简写

允许直接写入变量/函数,作为对象的属性/方法。

let str = "Clearlove"
let obj = {str}
obj // { str: "Clearlove" }

// 等同于
let str = "Clearlove"
let obj = { str: str }

作为方法时的简写:

let obj = {
  method() {
    return "Hello~"
  }
}

// 等同于
let obj = {
  method: function() {
    return "Hello~"
  }
}

属性和方法的简写一般作为函数函数的返回值对象属性的赋值器和构造器, 以及CommonJS 模块输出一组变量,就非常合适使用简洁写法。

let Obj = {};

function getItem (key) {
  return key in Obj ? Obj[key] : null;
}

function setItem (key, value) {
  Obj[key] = value;
}

function clear () {
  Obj = {};
}

module.exports = { getItem, setItem, clear }

// 等同于
module.exports = {
  getItem: getItem,
  setItem: setItem,
  clear: clear
}
属性表达式

javascript中定义对象属性,最常见的方式如下:

let obj = {}
obj.iseditable = true

ES6中允许用表达式作为对象的属性,将表达式放在一对中括号中,如下:

let key1 = "key1"
let obj = {
  [key1]: "123",
  ["key" + "2"]: "abc"
}

表达式还可以定义方法名:

let obj = {
  ["say" + "hello"]() {
    return "hello"
  }
}

obj.sayhello() // hello
Object.is()

用于比较两个值是否严格相等,与严格比较运算符===基本一致

Object.is("Clearlove", "Clearlove") // true
Object.is({}, {}) // false

与严格比较运算符===的差异主要有两点:1. +0不等于-0, 2. NaN等于自身

+0 === -0 //true
NaN === NaN // false

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

ES5可以通过如下方法扩展Object.is方法:

Object.defineProperty(Object, "is", {
  value: function(x, y) {
    if (x === y) {
      // 针对+0 不等于 -0的情况
      return x !== 0 || 1 / x === 1 / y;
    }
    // 针对NaN的情况
    return x !== x && y !== y;
  },
  configurable: true,
  enumerable: false,
  writable: true
});
Object.assign()

Object.assign方法用于对象合并,将待合并对象的所有可枚举属性,复制到目标对象中。

let target = { name: "Clearlvoe" }

let age = { age: 18 }
let sex = { sex: "男" }

Object.assign(target, age, sex)
target // {name: "Clearlvoe", age: 18, sex: "男"}

如果目标对象与待合并对象有同名属性,或多个待合并对象有同名属性,则后面的属性会覆盖前面的属性。

如果只有一个参数,Object.assign会直接返回该参数。

let target = { name: "Clearlvoe" }
Object.assign(target) //  { name: "Clearlvoe" }
Object.assign(target) === target // true

如果该参数不是对象,则会先转成对象,然后返回。但undefinednull无法转化为对象,所有以它们为参数时,会报错。

typeof Object.assign(2) // "object"

Object.assign(undefined) // Uncaught TypeError: Cannot convert undefined or null to object
Object.assign(null) // Uncaught TypeError: Cannot convert undefined or null to object

但如果undefinednull是作为带合并数据,则不会报错,因为无法转化为对象,所有跳过。

let target = { name: "Clearlvoe" }
Object.assign(target, undefined) === obj // true
Object.assign(target, null) === obj // true

若数值、字符串和布尔值做为待合并数据,合并至目标目标对象时,只有字符串会以数组形式,拷贝到目标对象。而数值和布尔值则会被忽略。

let str = "abc";
let boolean = true;
var num = 10;

let obj = Object.assign({}, str, boolean, num);
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

字符串能被拷贝,是因为字符串的包装对象,会产生可枚举属性。

Object(true) // {[[PrimitiveValue]]: true}
Object(10)  //  {[[PrimitiveValue]]: 10}
Object("abc") // {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}

上面代码中,布尔值、数值、字符串分别转成对应的包装对象,可以看到它们的原始值都在包装对象的内部属性[[PrimitiveValue]]上面,这个属性是不会被Object.assign拷贝的。只有字符串的包装对象,会产生可枚举的实义属性,那些属性则会被拷贝。

Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false

Object.assign({name: "Clearlove"},
  Object.defineProperty({}, "invisible", {
    enumerable: false,
    value: "hello"
  })
)
// {name: "Clearlove"}

上面代码中,Object.assign要拷贝的对象只有一个不可枚举属性invisible,这个属性并没有被拷贝进去。

注意点

Object.assign()是浅拷贝,如果源对象的某个属性值是对象,那么目标对象拷贝到的是这个 对象的引用。

let source = {person: { name: "Clearlove"}}
let target = Object.assign({}, source)

source.person.name = "Meiko"
target.person.name  // "Meiko"  

对于这种嵌套的对象,一旦遇到同名属性,Object.assign()的处理方法是替换,而不是添加。

let source = {person: { name: "Clearlove" }}
let target = {person: { name: "Meiko", age: 18 }}
Object.assign(target, source) // {person: { name: "Clearlove" }} 
常见用途 为对象添加属性
class LOL {
  constructor(name, age) {
    Object.assign(this, {name, age})
  } 
}

上面方法通过Object.assign方法,将name属性和age属性添加到LOL类的对象实例。

为对象添加方法
Object.assign(SomeClass.prototype, {
  addClass(classname) {
    ....
  },
  removeClass(class) {
    ....
  }
})
克隆对象
function clone(origin) {
  return Object.assign({}, origin);
}

上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆。

不过,采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采用下面的代码。

function clone(origin) {
  let originProto = Object.getPrototypeOf(origin)
  return Object.assign(Object.create(originProto), origin) 
}
合并多个对象

将对个对象合并到目标对象中

const merge = (target, ...sources) => Object.assign(target, ...sources)

如果希望合并后返回一个新对象,可以改写上面函数,对一个空对象合并

const merge = (...sources) => Object.assign({}, ...sources)
为属性制定默认值
const DEAFULT = {
  number: 0,
  template: "html"
}

funcition processContent(options) {
  options = Object.assigin({}, DEAFULT, options)
  console.log(options)
}

注意,由于存在浅拷贝的问题,DEFAULT对象和options对象的所有属性的值,最好都是简单类型,不要指向另一个对象。否则,DEFAULT对象的该属性很可能不起作用。

属性的可枚举性和遍历 可枚举性

对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。

let person = { name: "Clearlove" }
Object.getOwnPropertyDescriptor(person, "name")

//  {
//    value: Clearlove,
//    writable: true,
//    enumerable: true,
//    configurable: true
//  }

描述对象的enumerable属性,称为”可枚举性“,如果该属性为false,就表示某些操作会忽略当前属性
目前有四个操作会忽略enumerablefalse的属性:

for..in循环: 只遍历自身和继承的可枚举的属性

Object.keys(): 返回对象所有可枚举的属性的键名

JSON.stringify: 只字符串化可枚举的属性

Object.assign(): 忽略enumerablefalse的属性,只拷贝可枚举的属性

这四个操作之中,前三个是 ES5 就有的,最后一个Object.assign()是 ES6 新增的。其中,只有for...in会返回继承的属性,其他三个方法都会忽略继承的属性,只处理对象自身的属性。实际上,引入“可枚举”(enumerable)这个概念的最初目的,就是让某些属性可以规避掉for...in操作,不然所有内部属性和方法都会被遍历到。

比如,对象原型的toString方法,以及数组的length属性,就通过“可枚举性”,从而避免被for...in遍历到。

Object.getOwnPropertyDescriptor(Object.prototype, "toString").enumerable
// false

Object.getOwnPropertyDescriptor([], "length").enumerable
// false

上面代码中,toStringlength属性的enumerable都是false,因此for...in不会遍历到这两个继承自原型的属性。

另外,ES6 规定,所有 Class 的原型的方法都是不可枚举的。

Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, "foo").enumerable
// false
未完待续

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

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

相关文章

  • ES6入门之对象扩展

    摘要:循环遍历对象自身的和继承的可枚举属性不含属性。返回一个数组,包含对象自身的所有属性的键名。目前,只有对象方法的简写法可以让引擎确认,定义的是对象的方法。showImg(https://user-gold-cdn.xitu.io/2019/5/21/16ada8456223b0e1); 1. 属性的简洁表示法 在ES6中 允许直接写入变量和函数,作为对象的属性和方法,使得代码的书写更为简洁。...

    RiverLi 评论0 收藏0
  • ES6入门之对象扩展

    摘要:属性的简洁表示法在中允许直接写入变量和函数,作为对象的属性和方法,使得代码的书写更为简洁。循环遍历对象自身的和继承的可枚举属性不含属性。返回一个数组,包含对象自身的所有属性的键名。 showImg(https://segmentfault.com/img/remote/1460000019259004?w=1282&h=1920); 1. 属性的简洁表示法 在ES6中 允许直接写入变量...

    AWang 评论0 收藏0
  • ES6标准入门》读书笔记

    摘要:标准入门读书笔记和命令新增命令,用于声明变量,是块级作用域。用于头部补全,用于尾部补全。函数调用的时候会在内存形成一个调用记录,又称为调用帧,保存调用位置和内部变量等信息。等到执行结束再返回给,的调用帧才消失。 《ES6标准入门》读书笔记 @(StuRep) showImg(https://segmentfault.com/img/remote/1460000006766369?w=3...

    HollisChuang 评论0 收藏0
  • es6学习笔记--字符串扩展、数组扩展对象扩展

    摘要:字符串的扩展字符串的遍历器接口字符串可以被循环遍历。即能识别编号大于查询字符串是否包含某个字符返回布尔值,表示是否找到了参数字符串。返回布尔值,表示参数字符串是否在原字符串的头部。 字符串的扩展 1.字符串的遍历器接口 字符串可以被for...of循环遍历。 与es5的比较for循环虽可以遍历字符串,但不能识别大于oxFFFF的编码; 2.位置 --> 字符/码点 根据指定位置返回对应...

    不知名网友 评论0 收藏0
  • ES6rest参数和扩展运算符

    摘要:参数的形式为变量名扩展运算符是三个点。传递给函数的一组参数值,被整合成了数组。扩展运算符的应用普通的函数调用上面代码中,和这两行,都是函数的调用,它们的都使用了扩展运算符。这时,扩展运算符可以将其转为真正的数组,原因就在于对象实现了。 rest参数和扩展运算符都是ES6新增的特性。rest参数的形式为:...变量名;扩展运算符是三个点(...)。 rest参数 rest参数用于获取函数...

    ccj659 评论0 收藏0

发表评论

0条评论

animabear

|高级讲师

TA的文章

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