原型链Object.defineProperty与obj.prototype的区别

786

最近在读vue源码,发现有两种原型链上设置属性的方法:

Vue.prototype.$watch

Object.defineProperty(Vue.prototype, '$data', dataDef)

在疑惑为什么会这么写时,查阅相关资料,有了以下的见解,放出代码,可粘贴到f12中运行:

var obj = {};

Object.defineProperty(obj, 'a', {
    enumerable: true,
    // 当且仅当该属性的 `enumerable` 键值为 `true` 时,该属性才会出现在对象的枚举属性中。
    // 默认为false。
    configurable: false, 
    // 当且仅当该属性的 `configurable` 键值为 `true` 时,
    // 该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
    // 默认为false
    value: { key: 1 }  
});

var obj2 = {}
Object.prototype.b = 'ss'

for(var key in obj){
console.log('key:', key);
}
// b在原型链上,打印出来为空,原型链上可以找到
console.log(obj, obj2, obj.b, obj2.b)

打印下来为: image.png

由此可得出:

  1. XX.prototype.xx 在(class XX)类里可以设置属性,var x = new XX()时,实例化的任何对象可以调用xx这个属性。

  2. Object.defineProperty(x, xx, { value: 'xxx' })只适用于x这个实例化对象

  3. 我们再来看这两句代码:

    Vue.prototype.$watch

    Object.defineProperty(Vue.prototype, '$data', dataDef)

    它的意思为$watch可以在任何new Vue()的实例化对象中调用到。如const app2 = new Vue();app2.$watch();$data只有在Vue类的原型链上拿取,const obj = {}没有$data这个方法。

  4. 两者在条件一致(不可改变。不可遍历)时,都可以用没有区别。