摘要:若数值字符串和布尔值做为待合并数据,合并至目标目标对象时,只有字符串会以数组形式,拷贝到目标对象。上面代码中,布尔值数值字符串分别转成对应的包装对象,可以看到它们的原始值都在包装对象的内部属性上面,这个属性是不会被拷贝的。
属性简写延续之前的关于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() // helloObject.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
如果该参数不是对象,则会先转成对象,然后返回。但undefined和null无法转化为对象,所有以它们为参数时,会报错。
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
但如果undefined或null是作为带合并数据,则不会报错,因为无法转化为对象,所有跳过。
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,就表示某些操作会忽略当前属性。
目前有四个操作会忽略enumerable为false的属性:
for..in循环: 只遍历自身和继承的可枚举的属性
Object.keys(): 返回对象所有可枚举的属性的键名
JSON.stringify: 只字符串化可枚举的属性
Object.assign(): 忽略enumerable为false的属性,只拷贝可枚举的属性
这四个操作之中,前三个是 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
上面代码中,toString和length属性的enumerable都是false,因此for...in不会遍历到这两个继承自原型的属性。
另外,ES6 规定,所有 Class 的原型的方法都是不可枚举的。
Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, "foo").enumerable // false未完待续
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/91812.html
摘要:循环遍历对象自身的和继承的可枚举属性不含属性。返回一个数组,包含对象自身的所有属性的键名。目前,只有对象方法的简写法可以让引擎确认,定义的是对象的方法。showImg(https://user-gold-cdn.xitu.io/2019/5/21/16ada8456223b0e1); 1. 属性的简洁表示法 在ES6中 允许直接写入变量和函数,作为对象的属性和方法,使得代码的书写更为简洁。...
摘要:属性的简洁表示法在中允许直接写入变量和函数,作为对象的属性和方法,使得代码的书写更为简洁。循环遍历对象自身的和继承的可枚举属性不含属性。返回一个数组,包含对象自身的所有属性的键名。 showImg(https://segmentfault.com/img/remote/1460000019259004?w=1282&h=1920); 1. 属性的简洁表示法 在ES6中 允许直接写入变量...
摘要:标准入门读书笔记和命令新增命令,用于声明变量,是块级作用域。用于头部补全,用于尾部补全。函数调用的时候会在内存形成一个调用记录,又称为调用帧,保存调用位置和内部变量等信息。等到执行结束再返回给,的调用帧才消失。 《ES6标准入门》读书笔记 @(StuRep) showImg(https://segmentfault.com/img/remote/1460000006766369?w=3...
摘要:字符串的扩展字符串的遍历器接口字符串可以被循环遍历。即能识别编号大于查询字符串是否包含某个字符返回布尔值,表示是否找到了参数字符串。返回布尔值,表示参数字符串是否在原字符串的头部。 字符串的扩展 1.字符串的遍历器接口 字符串可以被for...of循环遍历。 与es5的比较for循环虽可以遍历字符串,但不能识别大于oxFFFF的编码; 2.位置 --> 字符/码点 根据指定位置返回对应...
摘要:参数的形式为变量名扩展运算符是三个点。传递给函数的一组参数值,被整合成了数组。扩展运算符的应用普通的函数调用上面代码中,和这两行,都是函数的调用,它们的都使用了扩展运算符。这时,扩展运算符可以将其转为真正的数组,原因就在于对象实现了。 rest参数和扩展运算符都是ES6新增的特性。rest参数的形式为:...变量名;扩展运算符是三个点(...)。 rest参数 rest参数用于获取函数...
阅读 2728·2023-04-25 18:06
阅读 2494·2021-11-22 09:34
阅读 1660·2021-11-08 13:16
阅读 1250·2021-09-24 09:47
阅读 3014·2019-08-30 15:44
阅读 2734·2019-08-29 17:24
阅读 2554·2019-08-23 18:37
阅读 2411·2019-08-23 16:55