GVKun编程网logo

为什么是Object.defineProperty()而不是this.defineProperty()(对于对象)?(为什么object to doing)

12

如果您想了解为什么是Object.defineProperty的相关知识,那么本文是一篇不可错过的文章,我们将对而不是this.defineProperty进行全面详尽的解释,并且为您提供关于API之

如果您想了解为什么是Object.defineProperty的相关知识,那么本文是一篇不可错过的文章,我们将对而不是this.defineProperty进行全面详尽的解释,并且为您提供关于API之Object.defineProperty()、javascript – 为什么它是Object.defineProperty()而不是this.defineProperty()(对象)?、JavaScript中的Object.defineProperty()和defineProperties()、js Object.defineProperty 使用的有价值的信息。

本文目录一览:

为什么是Object.defineProperty()而不是this.defineProperty()(对于对象)?(为什么object to doing)

为什么是Object.defineProperty()而不是this.defineProperty()(对于对象)?(为什么object to doing)

我正在一个JavaScript项目上,只是想知道为什么对象实例不继承defineProperty()和其他方法,而不必调用超类(superobject?)Object方法。

我看过了MDN文档,实际上有“非标准”属性方法。

但这些已被弃用。为什么要转向Object方法?

在我看来,类似的东西instance.defineProperty(...)比更好Object.defineProperty(instance,...)。对于其他一些Object方法,我也会说同样的话。

答案1

小编典典

这是为了避免发生冲突-通常情况下,对象的问题不具有所需值的属性。
JS中的对象通常用作键-值映射,键可以是任意字符串-例如__defineGetter__hasOwnProperty或不太特殊的东西。现在,当您想在未知对象上调用此类函数时(就像hasOwnProperty泛型枚举函数中经常使用的那样,可能会传入任何JSON),您永远无法确定自己是否获得了被覆盖的属性(甚至可能不是函数))或所需的原始对象,或者该对象是否完全继承了该属性。为了避免这个问题,您必须使用Object.prototype.hasOwnProperty.call-很难看。

因此,命名所有这些功能Object仅是有用的,它是一种更清洁的API,用于将反射方法与对象的应用程序界面分开。这还有助于优化(简化静态分析),并使限制沙箱中对反射API的访问更加容易-
至少这是设计思想。

您可能会很乐意defineProperty在原型中添加一个环,但是只有在使用已知对象时才能安全地使用它。如果您仍然想要它(如您所知何时使用和何时不使用),则可以使用

Object.defineProperty(Object.prototype, "defineProperty", {    writable: true,    enumberable: false,    value: function(prop, descr) {        return Object.defineProperty(this, prop, descr);     }});

API之Object.defineProperty()

API之Object.defineProperty()

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

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

Object.defineProperty(obj, prop, descriptor)

参数

obj

要定义属性的对象。

prop

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

descriptor

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

返回值

被传递给函数的对象。打印newObj就是被返回的对象。

const object = {};
const newObj = Object.defineProperty(object,''name'',{
  value:''董文杰'',
  writable:true
})
object.name = "施瓦辛格";
console.log(object.name) // 施瓦辛格
console.log(newObj) // {name: "施瓦辛格"}

首先看看writable (默认为false)

const object = {};
Object.defineProperty(object,''name'',{
  value:''董文杰'',
  writable:false
})
object.name = "施瓦辛格";
console.log(object.name) // 董文杰

 

const object = {};
Object.defineProperty(object,''name'',{
  value:''董文杰'',
  writable:true
})
object.name = "施瓦辛格";
console.log(object.name) // 施瓦辛格

由上述代码可知, writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。(默认为false)

在来看看:enumerable 为false可以被枚举,true不能被枚举
const object = {};
Object.defineProperty(object,''name'',{
  value:''董文杰'',
  enumerable:false
})
let res = Object.keys(object)
console.log(res) // []  enumerable为false时不可被枚举
const object = {};
Object.defineProperty(object,''name'',{
  value:''董文杰'',
  enumerable:true
})
let res = Object.keys(object)
console.log(res) // [''name'']  enumerable为true时可被枚举

configurable配置为false,不能被删除,true可以被删除(默认为false)

const object = {};
Object.defineProperty(object,''name'',{
   value:''董文杰'',
   configurable:false
})
delete object.name;
console.log(object) //{name: "董文杰"}
const object = {};
Object.defineProperty(object,''name'',{
   value:''董文杰'',
   configurable:true
})
delete object.name;
console.log(object) //{}

 

数据驱动视图最简单的例子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>set & get 数据驱动视图</title>
  </head>
  <body>
    <div id="name"></div>
    <div id="skills"></div>
    <script type="text/javascript">
    const profile = {};
    Object.defineProperty(profile, ''name'', {
      enumerable: true,
      configurable: true,
      get: function () {
        return document.querySelector(''#name'').innerHTML;
      },
      set: function (newVal) {
        document.querySelector(''#name'').innerHTML = newVal;
      }
    });
    Object.defineProperty(profile, ''skills'', {
      get: () => document.querySelector(''#skills'').innerHTML.split('',''),
      set: newVal => document.querySelector(''#skills'').innerHTML = newVal.toString()
    });
  </script>
  </body>
</html>

由上图例子可知,js数据改变,会驱动视图改变。利用了

Object.defineProperty

get set函数。

这个也是vue2.0版本数据驱动视图的核心api,3.0换成了更高效的proxy,我们改天有空再说,睡觉

javascript – 为什么它是Object.defineProperty()而不是this.defineProperty()(对象)?

javascript – 为什么它是Object.defineProperty()而不是this.defineProperty()(对象)?

我正在研究一个 JavaScript项目,并且只是想知道为什么对象实例不继承defineproperty()和其他方法,而不是必须调用超类(superobject?)Object方法.

我看过MDN docs,实际上有“非标准”属性方法.

但那些被弃用了.为什么移动是Object方法?

在我看来,像instance.defineProperty(…)这样的东西比Object.defineProperty(instance,…)更好.我也会对其他一些Object方法说同样的话.

解决方法

这是为了避免冲突 – 通常,对象没有具有您期望值的属性的问题.
JS中的对象通常用作键值映射,键可以是任意字符串 – 例如__defineGetter __,hasOwnProperty或更不特殊的字符串.现在,当你想在一个未知对象上调用这样一个函数时 – 比如hasOwnProperty常用于泛型枚举函数,其中任何JSON都可以传入 – 你永远无法确定你是否有一个覆盖的属性(甚至可能不是函数)或您想要的原始文件,或者对象是否继承该属性.要避免这个问题(或者也是 this IE bug),你必须使用Object.prototype.hasOwnProperty.call – 这很难看.

因此,命名空间对象上的所有这些函数只是有用的,它是一个更清晰的API,它将反射方法与对象的应用程序接口分开.这也有助于优化(简化静态分析),并且更容易限制对沙箱中反射API的访问 – 至少是design idea.

您可能很高兴在原型中有一个defineProperty,但您只能在使用已知对象时安全地使用它.如果您仍然想要它(如您所知,何时使用,何时不使用),您可以使用

Object.defineProperty(Object.prototype,"defineProperty",{
    writable: true,enumberable: false,value: function(prop,descr) {
        return Object.defineProperty(this,prop,descr); 
    }
});

JavaScript中的Object.defineProperty()和defineProperties()

JavaScript中的Object.defineProperty()和defineProperties()

文章同步到github

ECMAS-262第5版在定义只有内部采用的特性时,提供了描述了属性特征的几种属性。ECMAScript对象中目前存在的属性描述符主要有两种,数据描述符(数据属性)和存取描述符(访问器属性),数据描述符是一个拥有可写或不可写值的属性。存取描述符是由一对 getter-setter 函数功能来描述的属性。

Object的definePropertydefineProperties这两个方法在js中的重要性十分重要,主要功能就是用来定义或修改这些内部属性,与之相对应的getOwnPropertyDescriptorgetOwnPropertyDescriptors就是获取这行内部属性的描述。

下面文章我先介绍数据描述符和存取描述符的属性代表的含义,然后简单介绍以上四个方法的基本功能,这些如果了解可直接跳过,最后我会举例扩展及说明各内部属性在各种场景下产生的实际效果,那才是这篇文章的核心内容。本文章关于概念性的描述还是会尽量使用《javaScript高级教程》、MDN网站等概念,保证准确和易于大家理解,讲解部分则结合个人理解和举例说明。

数据(数据描述符)属性

数据属性有4个描述内部属性的特性

[[Configurable]]

表示能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使用字面量定义对象,默认值为true

[[Enumerable]]

表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使用字面量定义对象,默认值为true

[[Writable]]

能否修改属性的值,如果直接使用字面量定义对象,默认值为true

[[Value]]

该属性对应的值,默认为undefined

访问器(存取描述符)属性

访问器属性也有4个描述内部属性的特性

[[Configurable]]

和数据属性的[[Configurable]]一样,表示能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使用字面量定义对象,默认值为true

[[Enumerable]]

和数据属性的[[Configurable]]一样,表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使用字面量定义对象,默认值为true

[[Get]]

一个给属性提供 getter 的方法(访问对象属性时调用的函数,返回值就是当前属性的值),如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined

[[Set]]

一个给属性提供 setter 的方法(给对象属性设置值时调用的函数),如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined

创建/修改/获取属性的方法

Object.defineProperty()

功能:
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。如果不指定configurable, writable, enumerable ,则这些属性默认值为false,如果不指定value, get, set,则这些属性默认值为undefined

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

obj: 需要被操作的目标对象
prop: 目标对象需要定义或修改的属性的名称
descriptor: 将被定义或修改的属性的描述符

var obj = new Object();

Object.defineProperty(obj, ''name'', {
    configurable: false,
    writable: true,
    enumerable: true,
    value: ''张三''
})

console.log(obj.name)  //张三

Object.defineProperties()

功能:
方法直接在一个对象上定义一个或多个新的属性或修改现有属性,并返回该对象。

语法: Object.defineProperties(obj, props)

obj: 将要被添加属性或修改属性的对象
props: 该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置

var obj = new Object();
Object.defineProperties(obj, {
    name: {
        value: ''张三'',
        configurable: false,
        writable: true,
        enumerable: true
    },
    age: {
        value: 18,
        configurable: true
    }
})

console.log(obj.name, obj.age) // 张三, 18

Object.getOwnPropertyDescriptor()

功能:
该方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

语法: Object.getOwnPropertyDescriptor(obj, prop)

obj: 需要查找的目标对象
prop: 目标对象内属性名称

var person = {
    name: ''张三'',
    age: 18
}

var desc = Object.getOwnPropertyDescriptor(person, ''name''); 
console.log(desc)  结果如下
// {
//     configurable: true,
//     enumerable: true,
//     writable: true,
//     value: "张三"
// }

Object. getOwnPropertyDescriptors()

功能:
所指定对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。

语法: Object.getOwnPropertyDescriptors(obj)

obj: 需要查找的目标对象

var person = {
    name: ''张三'',
    age: 18
}
var desc = Object.getOwnPropertyDescriptors(person, ''name'');
console.log(desc) 
//{
//    configurable: true,
//    enumerable: true,
//    value: ''张三'',
//    writable: true
//}

各种场景下描述符属性的的扩展示例讲解

. configurable

如果设置configurable属性为false,则不可使用delete操作符(在严格模式下抛出错误), 修改所有内部属性值会抛出错误,在《javaScript高级教程中》说只可以改变writable的值,现在改变writable的值也会抛出错误

在对象中添加一个数据描述符属性

var person = {};

Object.defineProperty(person, ''name'', {
    configurable: false,
    value: ''John''
}) ;

delete person.name   // 严格模式下抛出错误

console.log(person.name)  // ''John''  没有删除

Object.defineProperty(person, ''name'', {
    configurable: true  //报错
});

Object.defineProperty(person, ''name'', {
    enumerable: 2  //报错
});

Object.defineProperty(person, ''name'', {
    writable: true  //报错
});

Object.defineProperty(person, ''name'', {
    value: 2  //报错
});

注意:
以上是最开始定义属性描述符时,writabl默认为false,才会出现上述效果,如果writable定义为true, 则可以修改[[writable]]和[[value]]属性值,修改另外两个属性值报错

var obj = {};

Object.defineProperty(obj, ''a'', {
    configurable: false,
    writable: true,
    value: 1
});

Object.defineProperty(obj, ''a'', {
    // configurable: true, //报错
    // enumerable: true,  //报错
    writable: false,
    value: 2
});
var d = Object.getOwnPropertyDescriptor(obj, ''a'')
console.log(d);
// {
//     value: 2, 
//     writable: false, 
// }

在对象中添加存取描述符属性

var obj = {};
var aValue; //如果不初始化变量, 不给下面的a属性设置值,直接读取会报错aValue is not defined
var b;
Object.defineProperty(obj, ''a'', {
    configurable : true,
    enumerable : true,
    get: function() {
        return aValue
    },
    set: function(newValue) {
        aValue = newValue;
        b = newValue + 1
    }
})
console.log(b) // undefined
console.log(obj.a)  // undefined, 当读取属性值时,调用get方法,返回undefined
obj.a = 2;  // 当设置属性值时,调用set方法,aValue为2

console.log(obj.a) // 2  读取属性值,调用get方法,此时aValue为2
console.log(b) // 3  再给obj.a赋值时,执行set方法,b的值被修改为2,额外说一句,vue中的计算属性就是利用setter来实现的

注意:
1.getter和setter可以不同时使用,但在严格模式下只其中一个,会抛出错误
2.数据描述符与存取描述符不可混用,会抛出错误

var obj = {};
Object.defineProperty(obj, ''a'', {
    value: ''a1'',
    get: function() {
       return ''a2''
    }    
});

3.全局环境下:

var a = 1;  // a属于window, 相当于window.a

让我们来看看a的描述符属性

var d = Object.getOwnPropertyDescriptor(window, ''a'');
console.log(d)
// {
//     configurable: false,
//     value: 1,
//     writable: true,
//     enumerable: true
// }

在来看一下另一种不适用var声明的方式初始化a变量

a = 1; //a相当于window的一个属性, window.a

再来看看此时a的描述符属性

var d = Object.getOwnPropertyDescriptor(window, ''a'');
console.log(d)
// {
//     configurable: true,   // 此时configurable属性值为true
//     value: 1,
//     writable: true,
//     enumerable: true
// }

注意:

只有使用var, let等操作符才是定义变量,而不使用var,直接a=1;,这样a的含义为window的一个属性,并不是我们所说的变量的概念。使用 var定义的任何变量,其configurable属性值都为false,定义对象也是一样

var b = {
    name: ''bbb''
}
var d = Object.getOwnPropertyDescriptor(window, ''b'');
console.log(d)
// {
//     configurable: false
//     value: 1,
//     writable: true,
//     enumerable: true
// }

但是这里需要说明的一点是,使用字面量定义的对象,该对象内部的属性的数据描述符属性都为true

var b = {
    name: ''bbb''
}
var d = Object.getOwnPropertyDescriptor(b, ''name'');
console.log(d)
// {
//     configurable: true
//     writable: true,
//     enumerable: true
//     value: ''bbb''
// }

Writable

当writable为false(并且configurable为true),[[value]]可以通过defineeProperty修改, 但不能直接赋值修改

var obj = {};

Object.defineProperty(obj, ''a'', {
    configurable: true,
    enumerable: false,
    writable: false,
    value: 1
});

Object.defineProperty(obj, ''a'', {
    configurable: false,
    enumerable: true,
    writable: false ,
    value: 2
});
var d = Object.getOwnPropertyDescriptor(obj, ''a'')

console.log(d); // 结果如下
// {
//     value: 2, 
//     writable: false, 
//     enumerable: true, 
//     configurable: false
// }


但是如果直接复制修改
var obj = {}

Object.defineProperty(obj, ''a'', {
    configurable: true,
    enumerable: false,
    writable: false,
    value: 1
});
obj.a=2;
var d = Object.getOwnPropertyDescriptor(obj, ''a'')

console.log(d); // 结果如下

// {
//     value: 1,  // 没有做出修改
//     writable: false, 
//     enumerable: true, 
//     configurable: false
// }

Enumerable

直接上例子

var obj = {};
Object.defineProperties(obj, {
    a: {
        value: 1,
        enumerable: false
    }, 
    b: {
        value: 2,
        enumerable: true
    },
    c: {
        value: 3,
        enumerable: false
    }
})

obj.d = 4;

//等同于

//Object.defineProperty(obj, ''d'', {
//    configurable: true,
//    enumerable: true,
//    writable: true,
//    value: 4
//})

for(var key in obj) {
    console.log(key);  
    // 打印一次b, 一次d, a和c属性enumerable为false,不可被枚举
} 

var arr = Object.keys(obj);
console.log(arr);  // [''b'', ''d'']

get和set

简易的数据双向绑定

在线demo地址: http://www.sunzhaoye.com/demo...

html代码:

<body>
    <p>
        input1=><input type="text" id="input1">
    </p>
    <p>
        input2=>
        <input type="text" id="input2">
    </p>
    <div>
        我每次比input1的值加1=>
        <span id="span"></span>
    </div>
</body>

js代码:

var oInput1 = document.getElementById(''input1'');
var oInput2 = document.getElementById(''input2'');
var oSpan = document.getElementById(''span'');
var obj = {};
Object.defineProperties(obj, {
    val1: {
        configurable: true,
        get: function() {
            oInput1.value = 0;
            oInput2.value = 0;
            oSpan.innerHTML = 0;
            return 0
        },
        set: function(newValue) {
            oInput2.value = newValue;
            oSpan.innerHTML = Number(newValue) ? Number(newValue) : 0
        }
    },
    val2: {
        configurable: true,
        get: function() {
            oInput1.value = 0;
            oInput2.value = 0;
            oSpan.innerHTML = 0;
            return 0
        },
        set: function(newValue) {
            oInput1.value = newValue;
            oSpan.innerHTML = Number(newValue)+1;
        }
    }
})
oInput1.value = obj.val1;
oInput1.addEventListener(''keyup'', function() {
    obj.val1 = oInput1.value;
}, false)
oInput2.addEventListener(''keyup'', function() {
    obj.val2 = oInput2.value;
}, false)

总结

终于到了最后了,就不具体梳理总结了。虽然我们在开过过程中不怎么使用几种方法,但理解之后对于我们理解js中对象有很大帮助,对后续进步也很有帮助,比如vue的实现原理等。个人能力有限,还希望大家发现问题后能多多指点,共同进步。

js Object.defineProperty 使用

js Object.defineProperty 使用

语法

Object.defineProperty(obj, prop, descriptor)

参数说明:

obj:必需。目标对象 
prop:必需。需定义或修改的属性的名字
descriptor:必需。目标属性所拥有的特性

返回值:

传入函数的对象。即第一个参数obj。

针对属性,我们可以给这个属性设置一些特性,比如是否只读不可以写;是否可以被for..inObject.keys()遍历。

示例1:

 

<!DOCTYPE html>
<html lang="zh">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Object.defineProperty 示例</title>
    </head>

    <body>

        <script type="text/javascript">
            var ss = {
                age: 10
            };
            var name = ''mfg'';
            Object.defineProperty(ss, ''name'', {
                //设置是否可以枚举
                enumerable: false,
                //是否可以删除目标属性
                configurable: false,
                // writable 控制是否可以修改(赋值)
                //获取属性值  
                get() {
                    return name;
                },
                //设置属性值  
                set(val) {
                    name = val;
                }
            })
            console.log(ss.name)
            ss.name = ''new value'';
            console.log(ss.name);
        </script>
    </body>

</html>

 

示例2:

<!DOCTYPE html>
<html lang="zh">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Object.defineProperty 示例</title>
    </head>

    <body>

        <script type="text/javascript">
            Object.defineProperties(Object.prototype, ''allkeys'', {
                value: function() {
                    let result = [];
                    for(let i in this) {
                        result.push(i)
                    }
                    return result;
                },
                writable: true,
                //关键配置,不可枚举,这样就可以在for in中遍历不到了
                enumerable: false,
                configurable: true
            });
        </script>
    </body>

</html>

说明:

示例2的例子,在Object.prototype上增加了方法,同时保证了不被for in遍历到。

 

 

关于为什么是Object.defineProperty而不是this.defineProperty的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于API之Object.defineProperty()、javascript – 为什么它是Object.defineProperty()而不是this.defineProperty()(对象)?、JavaScript中的Object.defineProperty()和defineProperties()、js Object.defineProperty 使用等相关知识的信息别忘了在本站进行查找喔。

本文标签: