javascript 面向对象精要 第三章 理解对象

第三章 理解对象

引言:尽管javascript里有大量内建引用类型,很可能你还是会频繁创建自己的对象。javascript编程一大重点就是管理那些对象。

3.1 定义属性

有两种创建自己的对象的方式:使用Object构造函数或者使用对象的字面形式

你可以在对象定义之后,立即给它添加属性,也可以改变属性的值。你定义的对象总是由你随意修改。

当一个属性第一次被添加给对象时,javascript在对象上调用一个名为[[put]]的内部方法[[put]]方法会在对象上创建一个新节点来保存属性,就像第一次在哈希表上添加一个键一样。当属性在每个对象上第一次被定义时,[[put]]方法都在该对象上被调用了。调用[[put]]的结果是在对象上创建了一个自有属性。一个自有属性表明仅仅该指定的对象实例拥有该属性。自有属性区别于原型属性。

当一个已有的属性被赋予一个新值时,调用一个名为[[set]]的内部方法。该方法将属性的当前值替换为新值。


3.2 属性探测

检查对象是否已经有一个属性,使用in操作符。in操作符在给定对象中查找一个给定名称的属性,如果找到返回true.

方法是值为函数的属性,所以也可以用in操作符来检查一个方法是否存在。

in操作符会检查自有属性和原型属性,而hasOwnProperty()方法仅检查自有属性。

var person={
    name:"hui",
    sayName:function(){
       console.log(this.name);
    }
};
console.log("name" in person);                //true
console.log(person.hasOwnProperty("name"));   //true
console.log("toString" in person);            //true
console.log(person.hasOwnProperty("toString"));  //false

name是person 的一个自有属性,而toString()方法是一个所有对象都具有的原型属性。

3.3 删除属性

(1)设置null并不能从对象中彻底移除那个属性。只是调用[[set]]将null 值替换了该属性原来的值而已。

(2)需要delete操作符彻底移除一个对象的属性。delete操作符针对单个对象属性调用名为[[Delete]]的内部方法。你可以认为该操作在哈希表中移除了一个键值对。delete操作符仅对自有属性起作用,它无法删除一个原型属性。

3.4 枚举属性

所有你添加的属性默认可枚举,可以用for in 遍历要他们。可枚举属性的内部特征[[Enumberable]]都被设置为true。

如果只需要获取一个对象的属性列表,ECMAScript5 引入了Object.keys()方法,它可以获取可枚举属性名字的数组。

for in和Object.keys()返回的可枚举属性有一个区别:for in循环会遍历原型属性和自有属性,而Object.keys()方法只返回自有属性。实际上,对象的大部分原生方法的[[Enumberable]]都被设置为false。

可以用propertyIsEnumberable()方法检查一个属性是否为可枚举的

3.5 属性类型

数据属性:  包含一个值

访问器属性:   不包含值,而是定义了一个当属性被读取和属性被写入时调用的函数(getter/setter)

[[put]]属性的默认行为是创建数据属性。

var person={
 _name:"hui",
 get name(){
     console.log("reading me");
     return this._name;
  },
 set name(value){
      console.log("setting name to ",value);
      this._name=value;
  }
};
console.log(person.name);
person.name="xia";
console.log(person.name);

本例定义了一个访问器属性name.一个数据属性_name保存访问器属性的实际值。getter被期望返回一个值,setter接受一个需要被赋给属性的值作为参数。

运行结果如下:


3. 6 属性特征

通用特征:[[Enumberable]]    [[Configurable]](是否可配置)你声明的所有属性默认都是可枚举、可配置的。

如果想改变属性特征,可以使用Object.defineProperty()方法。该方法接收三个参数:拥有该属性的对象,属性名,包含需要设置的特征的属性描述对象。属性描述对象具有和内部特征同名的属性,但名字中不包含中括号。

var person={
   name:"hui"
};
Object.defineProperty(person,"name",{
    enumerable:false
});
console.log("name" in person);  //true
console.log(person.propertyIsEnumerable("name"));    //false
var properties=Object.keys(person);
console.log(properties.length);  //0
Object.defineProperty(person,"name",{
      configurable:false
});

delete person.name;  
console.log("name" in person);  //true
console.log(person.name);  //hui

Object.defineProperty(person,"name",{
     configurable:true
});               //error!

由于name属性不可配置,试图删除name将会失败,所以name依然存在于person 中。后面几行代码试图重新定义name为可配置的,然而这将抛出错误。

运行结果如下:


(1)数据属性特征

[[Value]]  包含属性的值       [[Writable]]  布尔值,指示该属性是否可以写入(所有的属性默认可写)

以下两段代码是同样的效果。

var person{
    name:"hui"
};
var person={};
Object.defineProperty(person,"name",{
        value:"hui",
        enumerable:true,
        configurable:true,
        writable:true
});

当defineProperty()被调用时,它首先检查属性是否存在。不存在则根据属性描述对象指定的特征创建。当用defineProperty()定义新的属性时记得为所有的特征指定一个值,否则布尔型的值会默认设备false.

var person={};
Object.defineProperty(person,"name",{
      value:"hui"
}); 
console.log("name" in person);    //true
console.log(person.propertyIsEnumerable("name"));  //false
delete person.name;
console.log("name" in person);  //true

person.name="xia";
console.log(person.name);  //"hui"

上例除了读取name属性的值,无法对他作任何事情。运行结果如下:


(2)访问器属性特征

[[get]] 内含getter函数   [[set]] 内含setter函数。和数据属性一样,可以指定访问器属性是否为可配置、可枚举。

var person={
 _name:"hui",
 get name(){
     console.log("reading me");
     return this._name;
  },
 set name(value){
      console.log("setting name to ",value);
      this._name=value;
  }
};

上述代码可以写为如下形式:

var person={
 _name:"hui"
};
Object.defineProperty(person,"name",{
 get: function(){
     console.log("reading me");
     return this._name;
  },
 set: function(value){
      console.log("setting name to ",value);
      this._name=value;
  },
enumerable:true,
configurable:true
});

上述代码中,get 和set关键字,包含函数的数据属性。设置[[Enumerable ]]  [[和Configurable ]]可以改变访问器属性的工作方式。假如name属性只有一个getter的访问器属性,没有setter,它的值职能被读取,不能被改变。

3.6.4 定义多重属性

Object.definePropertise() 可以为一个对象同时定义多个属性。这个方法接受两个参数,需要改变的对象,和一个包含所有属性信息的对象。

3.6.5 获取属性特征

Object.getOwnPropertiseDescriptor() 可以获取属性的特征。这个方法只可用于自有属性。他接受两个参数:对象和属性名。如果属性存在,它会返回一个属性描述对象,内含四个属性:[[Enumerable ]]  [[和Configurable ]],另外两个属性则根据属性类型决定。

var person={
       name:"hui"
};
var descripter=Object.getOwnPropertiseDescriptor(person,"name");
console.log(descripter.enumerable);
console.log(descripter.configurable);
console.log(descripter.writable);
console.log(descripter.value);

运行结果如下:

3.7  禁止修改对象

禁止扩展Object.preventExtensions() 接受一个参数对象不可扩展,不能再给它添加新方法和新属性
对象封印Object.seal() 接受一个参数

对象不可扩展且其所有属性都不可配置。不能给他添加新属性,也不能删除属性或改变

其类型(从数据属性变为访问器属性或相反)

对象冻结Object.freeze()接受一个参数对象不可扩展且被封印,也不能改变属性类型,不能修改和写入任何数据属性

用Object.isExtensible()来检查[[Extensible]]的值。用Object.isSealed()判断一个对象是否被封印。用Object.isFrozen()来判断一个对象是否被冻结。

确保对被封印对象使用严格模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值