这是JS 原生方法原理探究系列的第七篇文章。本文会介绍如何实现 Object.assign()
方法。
Object.assign()
的基本用法要实现 Object.assign()
,首先了解它的大概用法:
根据上面所讲的思路,实现的代码就是下面这样的:
需要注意的要点如下:
.
给 Object 添加 myAssign
方法?Object.myAssign()
实际上是 Object 的一个静态方法,但是不要直接通过 .
添加,因为这种方式添加的方法是可以枚举的,而 assign()
方法不可枚举。所以这里使用 Object.defineProperty()
添加,同时设置该方法不可枚举、可读、可配置。
考察参数出现字符串的情况。下面这两种情况容易理解:
但如果是这种情况:
这里尝试把 “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
方法,是最保险的方式。