前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS 原生方法原理探究(七):如何实现 Object.assign()?

JS 原生方法原理探究(七):如何实现 Object.assign()?

作者头像
Chor
发布2021-12-24 14:12:17
2.8K0
发布2021-12-24 14:12:17
举报
文章被收录于专栏:前端之旅前端之旅前端之旅

这是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 方法,是最保险的方式。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-07-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Object.assign() 的基本用法
  • 实现代码
  • 需要注意的要点
    • 为什么不直接通过 . 给 Object 添加 myAssign 方法?
      • 为什么要使用严格模式?
        • 为什么不使用 Reflect.ownKeys(obj)?
          • 为什么不直接使用 obj.hasOwnProperty(key) ?
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档