共计 1965 个字符,预计需要花费 5 分钟才能阅读完成。
这是 JS 原生办法原理探索系列的第七篇文章。本文会介绍如何实现
Object.assign()
办法。
Object.assign()
的根本用法
要实现 Object.assign()
,首先理解它的大略用法:
- 承受的第一个参数示意指标对象(浅拷贝的后果),如果是 null 或者 undefined,间接报错;如果是对象字面量或者数组,间接应用;如果是根本类型,则装箱为对应的对象。
- 如果只承受了第一个参数,则将其包装为对象间接返回;如果不止承受了第一个参数,比如说承受了第二,第三 …… 等多个参数,那么这些参数示意源对象,它们的本身可枚举属性会一一增加到指标对象上,属性同名则以靠后的对象为准,进行属性笼罩。
- 第一个参数往后的参数,如果是 null 或者 undefined,那么间接跳过;其余的状况则尝试找出它们的可枚举属性,但实际上,只有字符串、数组、对象字面量这些类型是具备可枚举属性的。
实现代码
依据下面所讲的思路,实现的代码就是上面这样的:
function myAssign(target,...objs){if(target === null || target === undefined){throw new TypeError("can not convert null or undefined to object")
}
let res = Object(target)
objs.forEach(obj => {
'use strict'
if(obj != null && obj != undefined){for(let key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)){res[key] = obj[key]
}
}
}
})
return res
}
Object.defineProperty(Object,'myAssign',{
value: myAssign,
writable: true,
configurable: true,
enumerable: false
})
须要留神的要点
须要留神的要点如下:
为什么不间接通过 .
给 Object 增加 myAssign
办法?
Object.myAssign()
实际上是 Object 的一个静态方法,然而不要间接通过 .
增加,因为这种形式增加的办法是能够枚举的,而 assign()
办法不可枚举。所以这里应用 Object.defineProperty()
增加,同时设置该办法不可枚举、可读、可配置。
为什么要应用严格模式?
考查参数呈现字符串的状况。上面这两种状况容易了解:
Object.assign({a:1},"cd")
// 把 "cd" 的可枚举属性 0 和 1 增加到指标对象上,最初失去 {a:1,0:“c”,1:"d"}
Object.assign("cd",{a:1})
// 把 {a:1} 的可枚举属性 a 增加到指标对象上,最初失去 String{“cd”,a:1}
但如果是这种状况:
Object.assign("ab","cd")
// 报错 Cannot assign to read only property '0' of object '[object String]'
这里尝试把 “cd”
的可枚举属性 0 和 1 增加到指标对象上,但问题是,指标对象 String{“ab”}
也有可枚举属性 0 和 1,而且是只读的,这意味着咱们尝试去批改指标对象的只读属性,所以报错也就很正当了。然而,在非严格模式下,这种行为只会静默失败,为了让它真的抛出谬误,必须申明应用严格模式。
为什么不应用 Reflect.ownKeys(obj)
?
思考指标对象和源对象都是数组的状况,应用 Reflect.ownKeys(obj)
的确能够一次性取得 obj 的本身可枚举属性,然而这些属性除了数组索引之外,也蕴含数组长度, 这会导致将源对象的数组长度作为指标对象的数组长度 ,但实际上,两者长度不肯定相等。比方,Objetc.myAssign([1,2,3],[8,9])
的后果将不是冀望失去的 [8,9,3]
,而是 [8,9]
,因为指标对象的长度被笼罩了。
为什么不间接应用 obj.hasOwnProperty(key)
?
既然不能应用 Reflect.ownKeys(obj)
,那么就只有先应用 for(let key in obj)
取得 obj 的本身属性 + 原型链属性,再应用 obj.hasOwnProperty(key)
筛选出本身属性了。然而为什么不间接应用 obj.hasOwnProperty(key)
呢?
这是因为,咱们对源对象的状况并不理解。一方面,它可能重写了 hasOwnProperty
办法;另一方面,它可能是基于 Object.create(null)
构建的,这样的对象不会从 Object 原型上继承 hasOwnProperty
办法。所以这里借用 Object 原型的 hasOwnProperty
办法,是最保险的形式。