JavaScript Object.defineProperty()学习笔记。

Ruby
• 阅读 1014

属性类型

ECMAScript中有两种属性:数据属性和访问器属性。
数据属性:
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性。

[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。在对象上直接定义的属性,它们的这个特性默认值为true。
[[Enumerable]]:表示能否通过for-in循环返回属性。在对象上直接定义的属性,它们的这个特性默认值为true。
[[Writable]]:表示能否修改属性的值。在对象上直接定义的属性,它们的这个特性默认为true.
[[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为undefined。

要修改属性默认的特性,必须使用ECMAScript5的Object.defineProperty()方法。这个方法接受三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符对象的属性必须是:configurable、enumerable、writable和value。设置其中的一个或多个值,可以修改对应的特性值。例如:

var person = {};
Obejct.defineproperty(person,'name',{
    writable:false,
    value:'Nics'
})
console.log(person.name)//Nics
person.name = 'tom';
console.log(person.name)//Nics

这个例子创建了一个明为name的属性,它的值是只读的,如果为它指定新的值,在非严格模式下,赋值操作将被忽略;在严格模式下赋值操作将会抛出错误。
如果把configurable设置为false,表示不能从对象中删除属性,而且一旦把属性定义为不可配置的,就不能再把它变为可配置了。此时再调用Object.defineProperty()方法修改writable之外的特性都会抛出错误。
也就是说,可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable特性设置为false之后就会有限制了。
再调用Object.defineProperty()方法创建一个新的属性的时候,如果不指定configurable、enumerable、writable特性的默认值都是false。
Obejct.defineProperty(obj,prop,descriptor)方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。
参数:

obj:要在其上定义属性的对象。
prop:要定义或修改的属性的名称。
descriptor:将被定义或修改的属性描述符。

返回值:

被传递给函数的对象。

属性描述符:

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。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即改属性新的参数值。
var o = {}
//在对象中添加一个属性与数据描述符的示例。
Obejct.defineProperty(o,'a',{
    value:37,
    writable:true,
    enumerable:true,
    configurable:true
})
//对象o拥有了属性a,值为37

//在对象中添加一个属性与存取描述符的示例。
var bValue;
Obejct.defineProperyty(o,'b',{
    get:function(){
        return bValue;
    },
    set:function(newValue){
        bValue = newValue;
    },
    enumerable:true,
    configurable:true
})
o.b = 38;
//对象o拥有了属性b,值为38.
//数据描述符和存取描述符不能混合使用。

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

function Archiver(){
    var temperatrue = null;
    var aechive = [];
    Obejct.defineProperty(this,'temperatrue',{
        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}]

或:

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';
console.log(instance.myproperty);
console.log(instance.myname)

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

function myclass(){}
var value;
Obejct.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(){}
Obejct.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
点赞
收藏
评论区
推荐文章
海军 海军
4年前
关于JavaScript 对象的理解
关于JavaScript对象的理解对象理解对象ECMA262把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。我们可以把ECMAScript的对象想象成散列表:无非就是一组名值对,其中的值可以是
Easter79 Easter79
4年前
Spring引用properties文件
  Srping提供了PropertyPlaceholderConfigurer,它是一个容器后处理器,负责读取properties属性文件里的属性值,并将这些属性值设置成Spring配置文件的元数据。如定义Properties类:packagecom.custle.spring;/Created
Stella981 Stella981
4年前
JavaScript学习总结(十七)——Javascript原型链的原理
一、JavaScript原型链ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。在JavaScript中,用__proto__属性来表示一个对象的原型链。当查找一个对象的属性时,JavaScript会向上遍历原型
Stella981 Stella981
4年前
JavaScript Prototype
定义和用法prototype属性使您有能力向对象添加属性和方法。实例在本例中,将展示如何使用prototype属性来向对象添加属性:<scripttype"text/javascript"functionemployee(name,job,born){this.n
Wesley13 Wesley13
4年前
CSS基本语法及页面引用
css基本语法及页面引用(1)css基本语法css的定义方法是:选择器{属性:值;属性:值;属性:值;}选择器是将样式和页面元素关联起来的名称,属性是希望设置的样式属性每个属性有一个或多个值。代码示例:/css注释ctrlshift"/"/d
Stella981 Stella981
4年前
Python中的property()函数
property() 函数的作用是在新式类中返回属性值1.语法: classproperty(fget,fset,fdel,doc)2.参数:fget获取属性值的函数fset设置属性值的函数fdel删除属性值函数doc属性描述信息
Wesley13 Wesley13
4年前
CSS基础_CSS样式的几种书写形式
1.内嵌式将CSS代码集中写在HTML文档的head头部标签中,并且用style标签定义,其基本语法格式如下:<head<styletype"text/CSS"标签名/选择器{属性1:属性值1;属性2:属性值2;属性3:属性值3;
Wesley13 Wesley13
4年前
HTML表格的基本结构标记
<table标记1.基本格式:<table属性1"属性值1"属性2"属性值2"......表格内容</table2.table标记的属性  width属性  表示表格的宽度,他的值可以是像素(px)也可以是父级元素的百分比(%)  height属性  表示表格的高度,他的值可以是像素(px
Easter79 Easter79
4年前
Spring两种依赖注入方式的比较
我们知道,Spring对象属性的注入方式有两种:设值注入和构造注入。先看代码:  假设有个类为People,该对象包含三个属性,name和school还有age,这些属性都有各自的setter和getter方法,还有一个包含这三个属性的构造方法。如果用spring来管理这个对象,那么有以下两种方式为People设置属性:  1.设值注入:
Easter79 Easter79
4年前
Swift讲解专题十一——属性
Swift讲解专题十一——属性一、引言      属性将值与类,结构体,枚举进行关联。Swift中的属性分为存储属性和计算属性两种,存储属性用于存储一个值,其只能用于类与结构体,计算属性用于计算一个值,其可以用于类,结构体和枚举。二、存储属性      存储属性使用变量或者常量来存储一个
小万哥 小万哥
2年前
深入剖析 Java 类属性与类方法的应用
Java类属性Java类属性,也称为字段,是类中的变量。它们用于存储与类相关的数据。创建类属性在类定义中声明属性:javapublicclassMainintx;//属性Stringname;//属性访问类属性使用点语法访问对象的属性:javaMainmy