This is the seventh article in the series of exploring the principles of JS native methods. This article will introduce how to implement the Object.assign()
method.
Basic usage of Object.assign()
To implement Object.assign()
, first understand its general usage:
- The first parameter accepted represents the target object (the result of shallow copy). If it is null or undefined, report an error directly; if it is an object literal or an array, use it directly; if it is a basic type, it will be boxed as the corresponding object.
- If only the first parameter is accepted, it will be packaged as an object and returned directly; if more than the first parameter is accepted, for example, the second, third, etc. parameters are accepted, then these parameters represent the source object, Their enumerable properties will be added to the target object one by one, and the property with the same name will be subject to the subsequent object, and the property will be overwritten.
- If the parameters after the first parameter are null or undefined, skip directly; in other cases, try to find their enumerable properties, but in fact, only strings, arrays, and object literals are types With enumerable properties.
Implementation code
According to the ideas mentioned above, the implemented code is as follows:
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
})
Points to note
The main points to note are as follows:
Why not add the myAssign
method .
Object.myAssign()
actually a static method of Object, but don't .
, because the method added in this way is enumerable, while the assign()
method is not enumerable. So here use Object.defineProperty()
add, and set the method to be non-enumerable, readable, and configurable.
Why use strict mode?
Investigate the occurrence of strings in the parameters. The following two situations are easy to understand:
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}
But if this is the case:
Object.assign("ab","cd")
// 报错 Cannot assign to read only property '0' of object '[object String]'
Here we try to “cd”
the enumerable attributes 0 and 1 of 060e7f3ff22e71 to the target object, but the problem is that the target object String{“ab”}
also has enumerable attributes 0 and 1, and they are read-only, which means we try to modify the target object. Read-only attribute, so it is reasonable to report an error. However, in non-strict mode, this behavior will only fail silently. In order for it to really throw an error, you must declare the use of strict mode.
Why not use Reflect.ownKeys(obj)
?
Considering the situation where the target object and the source object are both arrays, using Reflect.ownKeys(obj)
can indeed obtain the enumerable properties of obj at one time, but these properties also include the array length in addition to the array index. This will cause the array of the source object as the array length of the target object, but in fact, the two lengths are not necessarily equal. For example, Objetc.myAssign([1,2,3],[8,9])
results will not be obtained a desired [8,9,3]
, but [8,9]
, since the length of the target object is covered.
Why not use obj.hasOwnProperty(key)
directly?
Reflect.ownKeys(obj)
cannot be used, then only use for(let key in obj)
obtain the obj's own attributes + prototype chain attributes, and then use obj.hasOwnProperty(key)
filter out the own attributes. But why not use obj.hasOwnProperty(key)
directly?
This is because we do not know the situation of the source object. On the one hand, it may rewrite the hasOwnProperty
method; on the other hand, it may be based on Object.create(null)
, such an object will not inherit the hasOwnProperty
method from the Object prototype. So borrowing the hasOwnProperty
method of the Object prototype here is the safest way.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。