精华内容
下载资源
问答
  • JS对象方法——Object.defineProperty() 我们都知道Vue内部通过Object.defineProperty方法属性拦截的方式,把data对象里每个数据的读写转化成getter/setter,当数据变化时通知视图更新实现双向数据绑定。可我们真的...
  • 对象定义属性-ie8 支持IE8的Object.defineProperty npm i object-defineproperty-ie8
  • 主要介绍了vue源码学习之Object.defineProperty对象属性监听,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • =与Object.defineProperty 为JavaScript对象新增或者修改属性,有两种不同方式:直接使用=赋值或者使用Object.defineProperty()定义。如下: // 示例1 var obj = {}; // 直接使用=赋值 obj.a = 1; // 使用Object....
  • 前言 上次写了一个Object.defineProperty() 不详解,文末说要写用它来写个双向绑定。说话算话,说来就来 前文链接 Object.defineProperty() 不详解 先看最后效果 model演示.gif 什么是双向绑定? 1.当一个对象...
  • 主要为大家详细介绍了vue.js利用Object.defineProperty实现双向绑定,帮大家解析神秘的Object.defineProperty方法
  • 主要介绍了js中Object.defineProperty()方法的不详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 今天小编就为大家分享一篇关于vue.js的双向数据绑定Object.defineProperty方法的神奇之处,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
  • 主要介绍了详谈Object.defineProperty 及实现数据双向绑定,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。下面这篇文章主要给大家介绍了关于使用Object.defineProperty如何巧妙找到修改某个变量的准确代码位置...
  • 主要介绍了vue源码学习之Object.defineProperty 对数组监听,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 主要介绍了Vue Object.defineProperty及ProxyVue实现双向数据绑定,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • js之Object.definePropertyObject.defineProperties详解

    万次阅读 多人点赞 2020-05-28 14:35:37
    Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

     1. Object.defineProperty() 

    Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

    备注:应当直接在 Object 构造器对象上调用此方法,而不是在任意一个 Object 类型的实例上调用。

    语法:

    Object.defineProperty(obj, prop, descriptor)

    obj

    要定义属性的对象。

    prop

    要定义或修改的属性的名称或 Symbol 。

    descriptor

    要定义或修改的属性描述符。

    例子

    在我们平常的使用中,给对象添加一个属性时,直接使用object.param的方式就可以了,或者直接在对象中挂载。

    const person = {
        name: 'hj'
    }
    

    在ECMAScript5中,对每个属性都添加了几个属性类型,来描述这些属性的特点。他们分别是

    • configurable:   默认false

    configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。

    当第一次设置为false后,再改写是不可以的。属性值也是不能被删除的。

    var o = {};
    Object.defineProperty(o, 'a', {
      get() { return 1; },
      configurable: false
    });
    // 定义为false 后  enumerable set get configurable value 都是不能再设置了。 delete o.a 也是删不了的
    Object.defineProperty(o, 'a', {
      configurable: true
    }); // throws a TypeError  抛出错误
    Object.defineProperty(o, 'a', {
      enumerable: true
    }); // 抛出错误
    Object.defineProperty(o, 'a', {
      set() {}
    }); // 报错
    Object.defineProperty(o, 'a', {
      get() { return 1; }
    }); // throws a TypeError
    // (even though the new get does exactly the same thing)
    Object.defineProperty(o, 'a', {
      value: 12
    }); // throws a TypeError // ('value' can be changed when 'configurable' is false but not in this case due to 'get' accessor)
    
    console.log(o.a); // logs 1
    delete o.a; // Nothing happens
    console.log(o.a); // logs 1  还存在说明没删掉

     

    • enumerable:  默认false

    enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。

    for...in 循环和 Object.keys()  定义: 任意顺序遍历一个对象的除Symbol以外的可枚举属性。

    var o = {};
    Object.defineProperty(o, "a", { value : 1, enumerable: true });
    Object.defineProperty(o, "b", { value : 2, enumerable: false });
    Object.defineProperty(o, "c", { value : 3 }); // enumerable 默认为 false
    o.d = 4; // 如果使用直接赋值的方式创建对象的属性,则 enumerable 为 true
    Object.defineProperty(o, Symbol.for('e'), {
      value: 5,
      enumerable: true
    });
    Object.defineProperty(o, Symbol.for('f'), {
      value: 6,
      enumerable: false
    });
    
    for (var i in o) {
      console.log(i);
    }
    // 只会打印a 和 d 
    
    Object.keys(o); // ['a', 'd']
    

    打印 对象 o 在谷歌浏览器中查看 

    o.propertyIsEnumerable('a'); // true
    o.propertyIsEnumerable('b'); // false
    o.propertyIsEnumerable('c'); // false
    o.propertyIsEnumerable('d'); // true
    o.propertyIsEnumerable(Symbol.for('e')); // true
    o.propertyIsEnumerable(Symbol.for('f')); // false
    
    var p = { ...o }
    p.a // 1
    p.b // undefined
    p.c // undefined
    p.d // 4
    p[Symbol.for('e')] // 5
    p[Symbol.for('f')] // undefined
    • writable:  默认false

    当 writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。

    var o = {}; // 创建一个新对象
    
    Object.defineProperty(o, 'a', {
      value: 37,
      writable: false
    });
    
    console.log(o.a); //  37
    o.a = 25; // No error thrown  不会抛出错误,但是也更改不了这个值,因为这个不是在严格模式下
    // (it would throw in strict mode,
    // even if the value had been the same)
    console.log(o.a); // 还是37 
    
    // strict mode
    (function() {
      'use strict';
      var o = {};
      Object.defineProperty(o, 'b', {
        value: 2,
        writable: false
      });
      o.b = 3; // throws TypeError: "b" is read-only
      return o.b; // returns 2 without the line above
    }());
    •  value :  默认undefined

    如果对象中不存在指定的属性,Object.defineProperty() 会创建这个属性。当描述符中省略某些字段时,这些字段将使用它们的默认值。

    var o = {}; // 创建一个新对象
    
    // 在对象中添加一个属性与数据描述符的示例
    Object.defineProperty(o, "a", {
      value : 37,
      writable : true,
      enumerable : true,
      configurable : true
    });
    
    // 对象 o 拥有了属性 a,值为 37
    
    // 在对象中添加一个设置了存取描述符属性的示例
    var bValue;
    Object.defineProperty(o, "b", {
      // 使用了方法名称缩写(ES2015 特性)
      // 下面两个缩写等价于:
      // get : function() { return bValue; },
      // set : function(newValue) { bValue = newValue; },
      get() { return bValue; },
      set(newValue) { bValue = newValue; },
      enumerable : true,
      configurable : true
    });
    
    o.b; // 38
    // 对象 o 拥有了属性 b,值为 38
    // 现在,除非重新定义 o.b,o.b 的值总是与 bValue 相同
    
    // 数据描述符和存取描述符不能混合使用
    Object.defineProperty(o, "conflict", {
      value: 0x9f91102,
      get() { return 0xdeadbeef; } 
    });
    // 抛出错误 TypeError: value appears only in data descriptors, get appears only in accessor descriptors
    • get: 当我们通过person.name访问name的值时,get将被调用。该方法可以自定义返回的具体值是多少。get默认值为undefined
    • set: 当我们通过person.name = 'Jake'设置name的值时,set方法将被调用。该方法可以自定义设置值的具体方式。set默认值为undefined

    考虑特性被赋予的默认特性值非常重要,通常,使用点运算符和 Object.defineProperty() 为对象的属性赋值时,数据描述符中的属性默认值是不同的

    var o = {};
    
    o.a = 1;
    // 默认做了下边这件事,等同于:
    Object.defineProperty(o, "a", {
      value: 1,
      writable: true,
      configurable: true,
      enumerable: true
    });
    
    
    // 如果这样定义,
    Object.defineProperty(o, "a", { value : 1 });
    // 默认做了下边这件事,等同于:
    Object.defineProperty(o, "a", {
      value: 1,
      writable: false,
      configurable: false,
      enumerable: false
    });

    需要注意的是,不能同时设置value、writable 与 get、set的值。

     

    var person = {}
    
    // 通过get与set自定义访问与设置name属性的方式
    Object.defineProperty(person, 'name', {
        get: function() {
            // 一直返回TOM
            return 'TOM'
        },
        set: function(value) {
            // 设置name属性时,返回该字符串,value为新值
            console.log(value + ' in set');
        }
    })
    
    // 第一次访问name,调用get
    console.log(person.name)   // TOM
    
    // 尝试修改name值,此时set方法被调用
    person.name = 'alex'   // alex in set
    
    // 第二次访问name,还是调用get
    console.log(person.name) // TOM
    

    请尽量同时设置get、set。如果仅仅只设置了get,那么我们将无法设置该属性值。如果仅仅只设置了set,我们也无法读取该属性的值。

    2.Object.defineProperties

    当我们想要同时设置多个属性的特性时,需要使用Object.defineProperties

    语法:  Object.defineProperties(obj, props)

    参数说明

    obj

    在其上定义或修改属性的对象。

    props

    要定义其可枚举属性或修改的属性描述符的对象。对象中存在的属性描述符主要有两种:数据描述符和访问器描述符(更多详情,请参阅Object.defineProperty())。描述符具有以下键:

    configurable

    true 当且仅当该属性描述符的类型可以被改变并且该属性可以从对应对象中删除。
    默认为 false

    enumerable

    true 当且仅当在枚举相应对象上的属性时该属性显现。
    默认为 false

    value

    与属性关联的值。可以是任何有效的JavaScript值(数字,对象,函数等)。
    默认为 undefined.

    writable

    true当且仅当与该属性相关联的值可以用assignment operator改变时。
    默认为 false

    get

    作为该属性的 getter 函数,如果没有 getter 则为undefined。函数返回值将被用作属性的值。
    默认为 undefined

    set

    作为属性的 setter 函数,如果没有 setter 则为undefined。函数将仅接受参数赋值给该属性的新值。
    默认为 undefined

    用法除了格式基本与Object.defineProperty相同

    var person = {}
    
    Object.defineProperties(person, {
        name: {
            value: 'Jake',
            configurable: true
        },
        age: {
            get: function() {
                return this.value || 22
            },
            set: function(value) {
                this.value = value
            }
        }
    })
    
    person.name   // Jake
    person.age    // 22
    

    读取属性的特性值

    我们可以使用Object.getOwnPropertyDescriptor方法读取某一个属性的特性值。

     

    var person = {}
    
    Object.defineProperty(person, 'name', {
        value: 'alex',
        writable: false,
        configurable: false
    })
    
    var descripter = Object.getOwnPropertyDescriptor(person, 'name');
    
    console.log(descripter);  // 返回结果如下
    
    descripter = {
        configurable: false,
        enumerable: false,
        value: 'alex',
        writable: false
    }

     

    展开全文
  • Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 语法:Object.defineProperty(obj, prop, descriptor) 参数 obj要定义属性的对象。prop要定义或修改...

    引用于MDN 文档

    Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

    语法:Object.defineProperty(obj, prop, descriptor)

    参数

    obj 要定义属性的对象。
    prop 要定义或修改的属性的名称或 Symbol 。
    descriptor 要定义或修改的属性描述符。

    备注:应当直接在 Object 构造器对象上调用此方法,而不是在任意一个 Object 类型的实例上调用
    在ES6中,由于 Symbol类型的特殊性,用Symbol类型的值来做对象的key与常规的定义或修改不同,而Object.defineProperty 是定义key为Symbol的属性的方法之一。

    描述

    该方法允许精确地添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,在枚举对象属性时会被枚举到(for...in 或 Object.keys 方法),可以改变这些属性的值,也可以删除这些属性。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改(immutable)的。

    对象里目前存在的属性描述符有两种主要形式:数据描述符存取描述符数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。一个描述符只能是这两者其中之一;不能同时是两者。

    这两种描述符都是对象。它们共享以下可选键值(默认值是指在使用 Object.defineProperty() 定义属性时的默认值):

    configurable

    当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
    默认为 false

    enumerable

    当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
    默认为 false

    数据描述符还具有以下可选键值:

    value

    该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
    默认为 undefined

    writable

    当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
    默认为 false

    存取描述符还具有以下可选键值:

    get

    属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
    默认为 undefined

    set

    属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
    默认为 undefined

    描述符默认值汇总

    • 拥有布尔值的键 configurableenumerable 和 writable 的默认值都是 false
    • 属性值和函数的键 valueget 和 set 字段的默认值为 undefined

    描述符可拥有的键值

     
     configurableenumerablevaluewritablegetset
    数据描述符可以可以可以可以不可以不可以
    存取描述符可以可以不可以不可以可以可以

    如果一个描述符不具有 valuewritableget 和 set 中的任意一个键,那么它将被认为是一个数据描述符。如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常。

    记住,这些选项不一定是自身属性,也要考虑继承来的属性。为了确认保留这些默认值,在设置之前,可能要冻结 Object.prototype,明确指定所有的选项,或者通过 Object.create(null) 将 __proto__ (en-US) 属性指向 null

    // 使用 __proto__
    var obj = {};
    var descriptor = Object.create(null); // 没有继承的属性
    // 默认没有 enumerable,没有 configurable,没有 writable
    descriptor.value = 'static';
    Object.defineProperty(obj, 'key', descriptor);
    
    // 显式
    Object.defineProperty(obj, "key", {
      enumerable: false,
      configurable: false,
      writable: false,
      value: "static"
    });
    
    // 循环使用同一对象
    function withValue(value) {
      var d = withValue.d || (
        withValue.d = {
          enumerable: false,
          writable: false,
          configurable: false,
          value: null
        }
      );
      d.value = value;
      return d;
    }
    // ... 并且 ...
    Object.defineProperty(obj, "key", withValue("static"));
    
    // 如果 freeze 可用, 防止后续代码添加或删除对象原型的属性
    // (value, get, set, enumerable, writable, configurable)
    (Object.freeze||Object)(Object.prototype);

    示例

    如果你想了解如何使用 Object.defineProperty 方法和类二进制标记语法,可以看看这些额外示例

    创建属性

    如果对象中不存在指定的属性,Object.defineProperty() 会创建这个属性。当描述符中省略某些字段时,这些字段将使用它们的默认值。

    var o = {}; // 创建一个新对象
    
    // 在对象中添加一个属性与数据描述符的示例
    Object.defineProperty(o, "a", {
      value : 37,
      writable : true,
      enumerable : true,
      configurable : true
    });
    
    // 对象 o 拥有了属性 a,值为 37
    
    // 在对象中添加一个设置了存取描述符属性的示例
    var bValue = 38;
    Object.defineProperty(o, "b", {
      // 使用了方法名称缩写(ES2015 特性)
      // 下面两个缩写等价于:
      // get : function() { return bValue; },
      // set : function(newValue) { bValue = newValue; },
      get() { return bValue; },
      set(newValue) { bValue = newValue; },
      enumerable : true,
      configurable : true
    });
    
    o.b; // 38
    // 对象 o 拥有了属性 b,值为 38
    // 现在,除非重新定义 o.b,o.b 的值总是与 bValue 相同
    
    // 数据描述符和存取描述符不能混合使用
    Object.defineProperty(o, "conflict", {
      value: 0x9f91102,
      get() { return 0xdeadbeef; }
    });
    // 抛出错误 TypeError: value appears only in data descriptors, get appears only in accessor descriptors
    

    修改属性

    如果属性已经存在,Object.defineProperty()将尝试根据描述符中的值以及对象当前的配置来修改这个属性。如果旧描述符将其configurable 属性设置为false,则该属性被认为是“不可配置的”,并且没有属性可以被改变(除了单向改变 writable 为 false)。当属性不可配置时,不能在数据和访问器属性类型之间切换。

    当试图改变不可配置属性(除了 value 和 writable 属性之外)的值时,会抛出TypeError,除非当前值和新值相同。

    Writable 属性

    当 writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。

    var o = {}; // 创建一个新对象
    
    Object.defineProperty(o, 'a', {
      value: 37,
      writable: false
    });
    
    console.log(o.a); // logs 37
    o.a = 25; // No error thrown
    // (it would throw in strict mode,
    // even if the value had been the same)
    console.log(o.a); // logs 37. The assignment didn't work.
    
    // strict mode
    (function() {
      'use strict';
      var o = {};
      Object.defineProperty(o, 'b', {
        value: 2,
        writable: false
      });
      o.b = 3; // throws TypeError: "b" is read-only
      return o.b; // returns 2 without the line above
    }());

    如示例所示,试图写入非可写属性不会改变它,也不会引发错误。

    Enumerable 属性

    enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。

    var o = {};
    Object.defineProperty(o, "a", { value : 1, enumerable: true });
    Object.defineProperty(o, "b", { value : 2, enumerable: false });
    Object.defineProperty(o, "c", { value : 3 }); // enumerable 默认为 false
    o.d = 4; // 如果使用直接赋值的方式创建对象的属性,则 enumerable 为 true
    Object.defineProperty(o, Symbol.for('e'), {
      value: 5,
      enumerable: true
    });
    Object.defineProperty(o, Symbol.for('f'), {
      value: 6,
      enumerable: false
    });
    
    for (var i in o) {
      console.log(i);
    }
    // logs 'a' and 'd' (in undefined order)
    
    Object.keys(o); // ['a', 'd']
    
    o.propertyIsEnumerable('a'); // true
    o.propertyIsEnumerable('b'); // false
    o.propertyIsEnumerable('c'); // false
    o.propertyIsEnumerable('d'); // true
    o.propertyIsEnumerable(Symbol.for('e')); // true
    o.propertyIsEnumerable(Symbol.for('f')); // false
    
    var p = { ...o }
    p.a // 1
    p.b // undefined
    p.c // undefined
    p.d // 4
    p[Symbol.for('e')] // 5
    p[Symbol.for('f')] // undefined

    Configurable 属性

    configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。

    var o = {};
    Object.defineProperty(o, 'a', {
      get() { return 1; },
      configurable: false
    });
    
    Object.defineProperty(o, 'a', {
      configurable: true
    }); // throws a TypeError
    Object.defineProperty(o, 'a', {
      enumerable: true
    }); // throws a TypeError
    Object.defineProperty(o, 'a', {
      set() {}
    }); // throws a TypeError (set was undefined previously)
    Object.defineProperty(o, 'a', {
      get() { return 1; }
    }); // throws a TypeError
    // (even though the new get does exactly the same thing)
    Object.defineProperty(o, 'a', {
      value: 12
    }); // throws a TypeError // ('value' can be changed when 'configurable' is false but not in this case due to 'get' accessor)
    
    console.log(o.a); // logs 1
    delete o.a; // Nothing happens
    console.log(o.a); // logs 1

    如果 o.a 的 configurable 属性为 true,则不会抛出任何错误,并且,最后,该属性会被删除。

    添加多个属性和默认值

    考虑特性被赋予的默认特性值非常重要,通常,使用点运算符和 Object.defineProperty() 为对象的属性赋值时,数据描述符中的属性默认值是不同的,如下例所示。

    var o = {};
    
    o.a = 1;
    // 等同于:
    Object.defineProperty(o, "a", {
      value: 1,
      writable: true,
      configurable: true,
      enumerable: true
    });
    
    
    // 另一方面,
    Object.defineProperty(o, "a", { value : 1 });
    // 等同于:
    Object.defineProperty(o, "a", {
      value: 1,
      writable: false,
      configurable: false,
      enumerable: false
    });
    

    自定义 Setters 和 Getters

    下面的例子展示了如何实现一个自存档对象。当设置temperature 属性时,archive 数组会收到日志条目。

    function Archiver() {
      var temperature = null;
      var archive = [];
    
      Object.defineProperty(this, 'temperature', {
        get: function() {
          console.log('get!');
          return temperature;
        },
        set: function(value) {
          temperature = value;
          archive.push({ val: temperature });
        }
      });
    
      this.getArchive = function() { return archive; };
    }
    
    var arc = new Archiver();
    arc.temperature; // 'get!'
    arc.temperature = 11;
    arc.temperature = 13;
    arc.getArchive(); // [{ val: 11 }, { val: 13 }]

    下面这个例子中,getter 总是会返回一个相同的值。

    var pattern = {
        get: function () {
            return 'I alway return this string,whatever you have assigned';
        },
        set: function () {
            this.myname = 'this is my name string';
        }
    };
    
    
    function TestDefineSetAndGet() {
        Object.defineProperty(this, 'myproperty', pattern);
    }
    
    
    var instance = new TestDefineSetAndGet();
    instance.myproperty = 'test';
    
    // 'I alway return this string,whatever you have assigned'
    console.log(instance.myproperty);
    // 'this is my name string'
    console.log(instance.myname);

    继承属性

    如果访问者的属性是被继承的,它的 get 和 set 方法会在子对象的属性被访问或者修改时被调用。如果这些方法用一个变量存值,该值会被所有对象共享。

    function myclass() {
    }
    
    var value;
    Object.defineProperty(myclass.prototype, "x", {
      get() {
        return value;
      },
      set(x) {
        value = x;
      }
    });
    
    var a = new myclass();
    var b = new myclass();
    a.x = 1;
    console.log(b.x); // 1
    

    这可以通过将值存储在另一个属性中解决。在 get 和 set 方法中,this 指向某个被访问和修改属性的对象。

    function myclass() {
    }
    
    Object.defineProperty(myclass.prototype, "x", {
      get() {
        return this.stored_x;
      },
      set(x) {
        this.stored_x = x;
      }
    });
    
    var a = new myclass();
    var b = new myclass();
    a.x = 1;
    console.log(b.x); // undefined

    不像访问者属性,值属性始终在对象自身上设置,而不是一个原型。然而,如果一个不可写的属性被继承,它仍然可以防止修改对象的属性。

    function myclass() {
    }
    
    myclass.prototype.x = 1;
    Object.defineProperty(myclass.prototype, "y", {
      writable: false,
      value: 1
    });
    
    var a = new myclass();
    a.x = 2;
    console.log(a.x); // 2
    console.log(myclass.prototype.x); // 1
    a.y = 2; // Ignored, throws in strict mode
    console.log(a.y); // 1
    console.log(myclass.prototype.y); // 1
    展开全文
  • 2 Object.defineProperty(user,"name",{ 3 value:"狂奔的蜗牛" 4 }) 5 Object.defineProperty(user,"isSlow",{ 6 value:true 7 }) 8 Object.defineProperty(user,"sayHi",{ 9 value:function () { console.log("Hi ...

     

    出处https://www.cnblogs.com/junjun-001/p/11761252.html#commentform

    或者https://www.cnblogs.com/ldq678/p/13854113.html

      假设我们有个对象 user ; 我们要给它增加一个属性 name , 我们会这么做  

    1 var user = {};
    2 user.name="狂奔的蜗牛";
    3 console.log(user);//{name: "狂奔的蜗牛"}

      如果想要增加一个sayHi方法叻?  

    1 user.sayHi=function () { console.log("Hi !") };
    2 console.log(user);//{name: "狂奔的蜗牛", sayHi: ƒn}

      Object.defineProperty 就是做这个的

      那么Object.defineProperty 怎么用?

      Object.defineProperty 需要三个参数(object , propName , descriptor)

      1 object 对象 => 给谁加
      2 propName 属性名 => 要加的属性的名字 【类型:String】
      3 descriptor 属性描述 => 加的这个属性有什么样的特性【类型:Object】

      那么descriptor这个是个对象 ,他有那些属性呢 ? 别着急我们一个一个说;

      既然可以给一个对象增加属性,那么我们用它来做一下给 user添加 name属性,代码是这样的  

    1 var user = {};
    2 Object.defineProperty(user,"name",{
    3  value:"狂奔的蜗牛"
    4 })
    5 console.log(user);//{name: "狂奔的蜗牛"}

      说明 是的还是那个经典的value属性,他就是设置属性值的。

      等等,属性值只能为字符串吗?我们的 number function Object boolean 等呢?  

    复制代码

     1 var user = {};
     2 Object.defineProperty(user,"name",{
     3  value:"狂奔的蜗牛"
     4 })
     5 Object.defineProperty(user,"isSlow",{
     6  value:true
     7 })
     8 Object.defineProperty(user,"sayHi",{
     9  value:function () { console.log("Hi !") }
    10 })
    11 Object.defineProperty(user,"age",{
    12  value:12
    13 })
    14 Object.defineProperty(user,"birth",{
    15  value:{
    16   date:"2018-06-29",
    17   hour:"15:30"
    18  }
    19 })
    20 console.log(user);

    复制代码

       

       说明 事实证明任何类型的数据都是可以的哦~

      问题又来了,如果 user对象已经有了name属性,我们可以通过Object.defineProperty改变这个值吗?

      我们来试试

    复制代码

    1 var user = {};
    2 Object.defineProperty(user,"name",{
    3  value:"狂奔的蜗牛"
    4 })
    5 console.log(user);
    6 user.name="新=>狂奔的蜗牛"
    7 console.log(user);

    复制代码

      咦??为什么我改了没作用勒??

      原因:上边说了descriptor有很多属性,除了value属性还有个 writable【顾名思义属性是否可以被重新赋值】接受数据类型为 boolean(默认为false) true => 支持被重新赋值 false=>只读

      哦哦,原来如果我没设置writable值的时候就默认只读啊,所以才改不掉

      那我们看看,设置为true,是不是就可以改掉了。

    复制代码

    1 var user = {};
    2 Object.defineProperty(user,"name",{
    3  value:"狂奔的蜗牛",
    4  writable:true
    5 })
    6 console.log(user);
    7 user.name="新=>狂奔的蜗牛"
    8 console.log(user);

    复制代码

     

      这个descriptor还有其他的属性吗?enumerable【顾名思义属性是否可以被枚举】接受数据类型为 boolean(默认为false) true => 支持被枚举 false=>不支持

     

      额。。。枚举??什....什么意思?

      假设我们想知道这个 user对象有哪些属性我们一般会这么做   

    复制代码

     1 var user ={
     2  name:"狂奔的蜗牛",
     3  age:25
     4 } ;
     5  
     6 //es6
     7 var keys=Object.keys(user)
     8 console.log(keys);// ['name','age']
     9 //es5
    10 var keys=[];
    11 for(key in user){
    12  keys.push(key);
    13 } 
    14 console.log(keys);// ['name','age'] 

    复制代码

      如果我们使用 Object.的方式定义属性会发生什么呢?我们来看下输出

    复制代码

     1 var user ={
     2  name:"狂奔的蜗牛",
     3  age:25
     4 } ;
     5 //定义一个性别 可以被枚举
     6 Object.defineProperty(user,"gender",{
     7  value:"男",
     8  enumerable:true
     9 })
    10  
    11 //定义一个出生日期 不可以被枚举
    12 Object.defineProperty(user,"birth",{
    13  value:"1956-05-03",
    14  enumerable:false
    15 })
    16  
    17 //es6
    18 var keys=Object.keys(user)
    19 console.log(keys);
    20 // ["name", "age", "gender"]
    21  
    22 console.log(user);
    23 // {name: "狂奔的蜗牛", age: 25, gender: "男", birth: "1956-05-03"}
    24 console.log(user.birth);
    25 // 1956-05-03 

    复制代码

      说明 很明显,我们定义为 enumerable=falsebirth属性并没有被遍历出来,遍历 => 其实就是枚举(个人理解啦,不喜勿喷哦~)

      总结 enumerable 属性取值为 布尔类型 true | false 默认值为 false,为真属性可以被枚举;反之则不能。此设置不影响属性的调用和 查看对象的值。

      configurable 是接下来我们要讲的一个属性,这个属性有两个作用:

      1 属性是否可以被删除
      2 属性的特性在第一次设置之后可否被重新定义特性

    复制代码

     1 var user ={
     2  name:"狂奔的蜗牛",
     3  age:25
     4 } ;
     5 //定义一个性别 不可以被删除和重新定义特性
     6 Object.defineProperty(user,"gender",{
     7  value:"男",
     8  enumerable:true,
     9  configurable:false
    10 })
    11  
    12 //删除一下
    13 delete user.gender;
    14 console.log(user);//{name: "狂奔的蜗牛", age: 25, gender: "男"}
    15  
    16 //重新定义特性
    17 Object.defineProperty(user,"gender",{
    18  value:"男",
    19  enumerable:true,
    20  configurable:true
    21 })
    22 // Uncaught TypeError: Cannot redefine property: gender
    23 //会报错,如下图

    复制代码

      

     

     

       设置为 true

    复制代码

     1 var user ={
     2  name:"狂奔的蜗牛",
     3  age:25
     4 } ;
     5 //定义一个性别 可以被删除和重新定义特性
     6 Object.defineProperty(user,"gender",{
     7  value:"男",
     8  enumerable:true,
     9  configurable:true
    10 })
    11  
    12 //删除前
    13 console.log(user);
    14 // {name: "狂奔的蜗牛", age: 25, gender: "男"}
    15  
    16 //删除一下
    17 delete user.gender;
    18 console.log(user);
    19 // {name: "狂奔的蜗牛", age: 25}
    20  
    21 //重新定义特性
    22 Object.defineProperty(user,"gender",{
    23  value:"男",
    24  enumerable:true,
    25  configurable:false
    26 })
    27  
    28 //删除前
    29 console.log(user);
    30 // {name: "狂奔的蜗牛", age: 25, gender: "男"}
    31 //删除一下 删除失败
    32 delete user.gender;
    33 console.log(user);
    34 // {name: "狂奔的蜗牛", age: 25, gender: "男"}

    复制代码

      总结 configurable设置为 true 则该属性可以被删除和重新定义特性;反之属性是不可以被删除和重新定义特性的,默认值为false(Ps.除了可以给新定义的属性设置特性,也可以给已有的属性设置特性哈

      最后我们来说说,最重要的两个属性 setget(即存取器描述:定义属性如何被存取),这两个属性是做什么用的呢?我们通过代码来看看

    复制代码

     1 var user ={
     2  name:"狂奔的蜗牛"
     3 } ;
     4 var count = 12;
     5 //定义一个age 获取值时返回定义好的变量count
     6 Object.defineProperty(user,"age",{
     7  get:function(){
     8   return count;
     9  }
    10 })
    11 console.log(user.age);//12
    12  
    13 //如果我每次获取的时候返回count+1呢
    14 var user ={
    15  name:"狂奔的蜗牛"
    16 } ;
    17 var count = 12;
    18 //定义一个age 获取值时返回定义好的变量count
    19 Object.defineProperty(user,"age",{
    20  get:function(){
    21   return count+1;
    22  }
    23 })
    24 console.log(user.age);//13

    复制代码

    我们看看 set,不多说上代码

    复制代码

     1 var user ={
     2  name:"狂奔的蜗牛"
     3 } ;
     4 var count = 12;
     5 //定义一个age 获取值时返回定义好的变量count
     6 Object.defineProperty(user,"age",{
     7  get:function(){
     8   return count;
     9  },
    10  set:function(newVal){
    11   count=newVal;
    12  }
    13 })
    14 console.log(user.age);//12
    15 user.age=145;
    16 console.log(user.age);//145
    17 console.log(count);//145
    18  
    19 //等等,如果我想设置的时候是 自动加1呢?我设置145 实际上设置是146
    20  
    21 var user ={
    22  name:"狂奔的蜗牛"
    23 } ;
    24 var count = 12;
    25 //定义一个age 获取值时返回定义好的变量count
    26 Object.defineProperty(user,"age",{
    27  get:function(){
    28   return count;
    29  },
    30  set:function(newVal){
    31   count=newVal+1;
    32  }
    33 })
    34 console.log(user.age);//12
    35 user.age=145;
    36 console.log(user.age);//146
    37 console.log(count);//146

    复制代码

      说明 注意:当使用了getter或setter方法,不允许使用writable和value这两个属性(如果使用,会直接报错滴)

      get 是获取值的时候的方法,类型为 function ,获取值的时候会被调用,不设置时为 undefined

      set 是设置值的时候的方法,类型为 function ,设置值的时候会被调用,undefined

      get或set不是必须成对出现,任写其一就可以

    复制代码

     1 var user ={
     2  name:"狂奔的蜗牛"
     3 } ;
     4 var count = 12;
     5 //定义一个age 获取值时返回定义好的变量count
     6 Object.defineProperty(user,"age",{
     7  get:function(){
     8   console.log("这个人来获取值了!!");
     9   return count;
    10  },
    11  set:function(newVal){
    12   console.log("这个人来设置值了!!");
    13   count=newVal+1;
    14  }
    15 })
    16 console.log(user.age);//12
    17 user.age=145;
    18 console.log(user.age);//146

    复制代码

      

     

       【完结】

      Object.defineProperty方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象

    • value: 设置属性的值
    • writable: 值是否可以重写。true | false
    • enumerable: 目标属性是否可以被枚举。true | false
    • configurable: 目标属性是否可以被删除或是否可以再次修改特性 true | false
    • set: 目标属性设置值的方法
    • get:目标属性获取值的方法 
    展开全文
  • Object.defineProperty和Proxy区别

    千次阅读 2020-07-15 15:00:26
    Object.defineProperty Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。IE8不兼容。 Object.defineProperty(obj, prop, descriptor) 参数 obj: 要...

    Object.defineProperty

    Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。IE8不兼容。

    Object.defineProperty(obj, prop, descriptor)

    参数
    obj: 要定义属性的对象。
    prop: 要定义或修改的属性的名称或 Symbol 。
    descriptor: 要定义或修改的属性描述符。

    返回值
    被传递给函数的对象。

    Object.defineProperty(obj, 'name', {
      // configurable: false,//默认为false
      // enumerable: false,//默认为false
      value: 'kongzhi',
      // writable: false,/默认为false
      // get(){},
      // set(v){}
    });
    

    定义了 valuewritable , 一定不能有 getset, 反之亦然, 否则报错

    对象里目前存在的属性描述符有两种主要形式:数据描述符存取描述符
    数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。
    存取描述符是由 getter 函数和 setter 函数所描述的属性。
    一个描述符只能是这两者其中之一;不能同时是两者

    这两种描述符都是对象。它们共享以下可选键值(默认值是指在使用 Object.defineProperty() 定义属性时的默认值):

    默认值:

    configurable
    当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
    默认为 false。

    enumerable
    当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
    默认为 false。

    数据描述符还具有以下可选键值:

    value
    该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
    默认为 undefined。

    writable
    当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
    默认为 false。

    存取描述符还具有以下可选键值:

    get
    属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
    默认为 undefined。

    set
    属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
    默认为 undefined。

    描述符默认值汇总

    拥有布尔值的键 configurable、enumerable 和 writable 的默认值都是 false。
    属性值和函数的键 value、get 和 set 字段的默认值为 undefined。

    描述符可拥有的键值

    -configurableenumerablevaluewritablegetset
    数据描述符可以可以可以可以不可以不可以
    存取描述符可以可以不可以不可以可以可以
    let obj={a:2,b:{c:3}};
    Object.defineProperty(obj,'a',{
      configurable:true,
      enumerable:true,
      get(){
        return obj['a']
      },
      set(value){
        return obj['a']=value;
      }
    })
    
    
    let obj={a:2,b:{c:3}};
    Object.defineProperty(obj,'b',{
      writable:false,
      configurable:false
    })
    obj.b=3;
    obj.b.c=4;
    console.log(obj)//{a:2,b:{c:4}}
    
    const obj = {};
    Object.defineProperty(obj, 'name', {
      // configurable: false,//默认为false
      // enumerable: false,//默认为false
      value: 'kongzhi',
      // writable: false,/默认为false
      // get(){},
      // set(v){}
    });
    console.log(obj.name); // 输出 kongzhi
    
    // 改写obj.name 的值
    obj.name = 111;
    console.log(obj.name); // 还是打印出 kongzhi,因为writable默认为false
    
    var o = {};
    
    o.a = 1;
    // 等同于:
    Object.defineProperty(o, "a", {
      value: 1,
      writable: true,
      configurable: true,
      enumerable: true
    });
    
    
    // 另一方面,
    Object.defineProperty(o, "a", { value : 1 });
    // 等同于:
    Object.defineProperty(o, "a", {
      value: 1,
      writable: false,
      configurable: false,
      enumerable: false
    });
    

    全局变量Date不可修改,为了安全性考虑

    Object.defineProperty(window,'Date',{
      writable:false,
      configurable:false
    })
    

    Object.defineProperties

    Object.defineProperties本质上定义了obj 对象上props的可枚举属性相对应的所有属性。

    var obj = {};
    Object.defineProperties(obj, {
      'property1': {
        value: true,
        writable: true
      },
      'property2': {
        value: 'Hello',
        writable: false
      }
      // etc. etc.
    });
    

    Proxy

    Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。IE不兼容

    const p = new Proxy(target, handler)

    参数
    target: 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
    handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

    返回值
    一个Proxy代理的对象,操作这个对象会触发handler对应操作。改变原始对象不会触发。

    handler 对象的方法

    handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。

    所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。

    handler.getPrototypeOf()
    handler.setPrototypeOf()
    handler.isExtensible()
    handler.preventExtensions()
    handler.getOwnPropertyDescriptor()
    handler.defineProperty()
    handler.has()//in 操作符的捕捉器。
    handler.get(target, property)
    handler.set(target, property, value)
    handler.deleteProperty()//delete 操作符的捕捉器。
    handler.ownKeys()
    handler.apply()
    handler.construct()//new 操作符的捕捉器。
    

    基本操作

    const handler = {
        get: function(obj, prop) {
            return prop in obj ? obj[prop] : 37;
        }
    };
    
    const p = new Proxy({}, handler);
    p.a = 1;
    p.b = undefined;
    
    console.log(p.a, p.b);      // 1, undefined
    console.log('c' in p, p.c); // false, 37
    

    Proxy只代理对象外层属性

    let obj={a:1,b:{c:2}};
    let handler={
      get:function(obj,prop){
        const v = Reflect.get(obj,prop);
        return v; // 返回obj[prop]
      },
      set(obj,prop,value){
        return Reflect.set(obj,prop,value);//设置成功返回true
      }
    };
    let p=new Proxy(obj,handler);
    
    p.a//会触发get方法
    p.b.c//会触发get方法获取p.b,不会触发.c的set,因为c没被代理。
    

    递归代理对象内部对象

    let obj={a:1,b:{c:2}};
    let handler={
      get:function(obj,prop){
        const v = Reflect.get(obj,prop);
        if(v !== null && typeof v === 'object'){
          return new Proxy(v,handler);//代理内层
        }else{
          return v; // 返回obj[prop]
        }
      },
      set(obj,prop,value){
        return Reflect.set(obj,prop,value);//设置成功返回true
      }
    };
    let p=new Proxy(obj,handler);
    
    p.a//会触发get方法
    p.b.c//会先触发get方法获取p.b,然后触发返回的新代理对象的.c的set。
    

    可以看出Proxy代理对象时只会在调用时递归,不会一开始就全部递归,优化了性能。

    Proxy对象和原始对象

    let target = {};
    let p = new Proxy(target, {});
    
    p.a = 37;   // 操作转发到目标
    
    console.log(target.a);    // 37. 操作已经被正确地转发
    
    target.a=4;
    console.log(p.a)//4
    
    console.log(target==p)//false
    

    总结

    1. Proxy使用上比Object.defineProperty方便的多。
    2. Proxy代理整个对象,Object.defineProperty只代理对象上的某个属性。
      3. 如果对象内部要全部递归代理,则Proxy可以只在调用时递归,而Object.defineProperty需要在一开始就全部递归,Proxy性能优于Object.defineProperty。
    3. vue中,Proxy在调用时递归,Object.defineProperty在一开始就全部递归,Proxy性能优于Object.defineProperty。
    4. 对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到。
    5. 数组新增删除修改时,Proxy可以监听到,Object.defineProperty监听不到。
    6. Proxy不兼容IE,Object.defineProperty不兼容IE8及以下。
    展开全文
  • Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象,Vue 的底层中很多地方用到了这个方法,比如数据代理、计算属性等等......
  • Object.defineProperty()方法详解

    千次阅读 2020-12-23 19:37:43
    文章目录Object.defineProperty()参数描述创建属性修改属性Enumerable 特性Configurable 特性添加多个属性和默认值Setters 和 Getters Object.defineProperty() Object.defineProperty() 方法直接在一个对象上定义一...
  • 从零认识defineProperty 基本用法与属性 让我们从基本概念说起,这里引用MDN解释: Object.defineProperty方法用于在对象上定义一个新属性,或者修改对象现有属性,并返回此对象。注意,请通过Object构造器调用此...
  • Vue 中 数据劫持 Object.defineProperty()

    千次阅读 2020-02-24 11:24:48
    我们都知道vue是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的,无疑这个方法是本文中最重要、最基础的内容之一,本文将由浅到深...
  • 几乎所有使用vue的开发者都知道,vue的双向绑定是通过Object.defineProperty()实现的,也知道在getter中收集依赖,在setter中通知更新。那么除了知道getter和setter之外,Object.defineProperty()还有哪些值得我们去...
  • OK,这一篇主要想说一下Object.defineProperty这个方法。 这个方法也是Vue数据双向绑定原理的常见面试题 所以也是有必要好好掌握的哦 首先我们知道JS中是支持面向对象编程的,也是有着对象和类这样的概念。 我们...
  • Object.defineProperty是一个作用强大的方法。凡能够实现双向绑定的MVVM框架都是基于此方法!defineProperty的翻译即是“定义属性”,它不仅仅可定义属性,还可通过它来对属性进行拦截、监听 Object....
  • Vue3.0 中,响应式数据部分弃用了Object.defineProperty,使用Proxy来代替它。本文将主要通过以下三个方面来分析为什么 Vue 选择弃用Object.defineProperty。 1.Object.defineProperty真的无法监测数组下标的变化吗...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 42,123
精华内容 16,849
关键字:

object.defineproperty