关于给对象新增属性的一个小知识点

1,692 阅读2分钟

记此文原因

昨晚看了篇文章,博主说他之前发现有挺多人可能对对象基础`API`不大熟悉,并举个开发中常见的例子,比如,初始化vue项目经常会有类似的封装`http`到原型`Vue.prototype`的操作,而我们可能是这样封装的:

image.png

其中挂载到vue原型的$http就是我们希望在使用vue组件时能全局调用的接口请求方法,而不用再作import了,如果是别的小点我可能看看知道就过了,但他说得人中很明显也包括了我,我以前也这么做过,即使现在的项目也是这么用的,然后他又说这很容易被篡改,虽然一般情况下,大家都不会这么做,但是万一呢?因此,便有了此文:

项目尝试

既然按这样的方式,该方法容易被篡改,那我们就试试看是不是可以篡改以及如何不被篡改,因此,我在项目中作了个小尝试,代码及效果如下:

企业微信截图_16675322238987.png

企业微信截图_16675322504304.png

在上面的两张图中,先展示了在vue原型新增/修改属性的代码,然后对属性值修改前后打印的日志作了分组,很明显通过图2可以看出了,确实被修改了,假设项目中真不小心被人修改了,然后一路绿灯上了线,后果可能会有点严重。

那么我们该怎么新增属性才能避免被人误修改/覆盖呢?

其实我们可以使用Object.defineProperty方法,下面我们对上面代码作下新增属性层面的小改动,代码及日志打印效果如下:

image.png

企业微信截图_16675398879303.png

在这两张截图中,我们只是注释了之前新增属性的操作,转而使用Object.defineProperty方法来新增属性(黄色区域部分),修改及日志打印部分未作改动,从打印日志来看,修改前的日志我们已经打印出来了,但是属性修改后的日志则没有打印出来,因为在属性修改时出现了异常,异常提示我们无法对$zhuzheLog这个属性赋值,原因是它只有getter(即取值),新增属性时我们仅指定了get,而没有setter(即赋值)操作,所以,将不支持修改。

chrome浏览器尝试

下面我将采用同样的方式,在chrome浏览作下上方对象新增属性的尝试: 首先是普通方式的属性新增,代码即日志打印效果如下:

企业微信截图_16675431891190.png 从日志打印效果来看,与我们在项目中的效果一致,新增属性的值成功被篡改了,接下来,我们再用Object.defineProperty方法来操作下,代码即日志打印效果如下:

企业微信截图_16675433064661.png

与项目中的效果稍微不一样的是,这次没有报错,修改后的日志也打印出来了,但是修改前后的属性值并未发生改变,这样也达到了属性值不被修改的目的。

原因

那么这就会产生一个问题,为什么使用Object.defineProperty方法新增的属性不会被修改呢? 带着疑问,我浏览了MDN中对于Object.defineProperty方法的一段描述,见下图:

image.png 相信应该可以给我们解惑了吧?

例证

这个环节主要是想找点例子,来说明下,其实有些权威的库也是这么写的,之前的博主提到vue的路由vue-router里面就有这么在用,于是,我在项目中的vue-router里面找了找,还真找到了,vue-router版本及具体效果见下图:

image.png

image.png vue-router更高版本的方法不知道有否发生变更,相信v3及以下版本应该都是这么处理的。另外,vue-router库dist目录下,除了后缀带min(压缩)的文件外,另外4个都是这么写的。

总结

本文主要是对字面量新增属性及通过Object.defineProperty方法新增属性的区别在项目及浏览器中作了下尝试,了解了下其中的原因以及vue-router库也有同样的写法,这让我们感觉我们不是一个人,似乎有更强大的力量在支持着我们。 最后,大家也可以动手试试~