JavaScript 对象 - 与属性的相关知识

function inherit(p){
    if(p == null) throw TypeError();
    if(Object.create)
        return Object.create(p);
    var t = typeof p;
    if(t !== "object" && t !== "function") throw TypeError();
    function f(){};
    f.prototype = p ;
    return new f();
};

创建对象

  对象创建的三种方式: 

    对象自面量、构造函数、ECMAScript5中引入的 Object.create()

    自面量的方式:

var o = {name:"wj",age:"20"};

    构造函数:

function FunctionName(){}

     Object.create()

Object.create(proto, [ propertiesObject ])
proto 一个对象,作为新创建对象的原型。
propertiesObject
    可选。该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称,值是属性描述符(这些属性描述符的结构与Object.defineProperties()的第二个参数一样)。
注意:该参数对象不能是 undefined,另外只有该对象中自身拥有的可枚举的属性才有效,也就是说该对象的原型链上属性是无效的。

    如果 proto 参数不是 null 或一个对象值,则抛出一个 TypeError 异常。

实例一:

//Shape - superclass
function Shape() {
  this.x = 0;
  this.y = 0;
}

Shape.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
    console.info("Shape moved.");
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); //call super constructor.
}

Rectangle.prototype = Object.create(Shape.prototype);

var rect = new Rectangle();

rect instanceof Rectangle //true.
rect instanceof Shape //true.

rect.move(1, 1); //Outputs, "Shape moved."

 

实例二: proto属性与 propertiesObject 结合使用

  

var o;

// 创建一个原型为null的空对象
o = Object.create(null);


o = {};
// 以字面量方式创建的空对象就相当于:
o = Object.create(Object.prototype);


o = Object.create(Object.prototype, {
  // foo会成为所创建对象的数据属性
  foo: { writable:true, configurable:true, value: "hello" },
  // bar会成为所创建对象的访问器属性
  bar: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) { console.log("Setting `o.bar` to", value) }
}})


function Constructor(){}
o = new Constructor();
// 上面的一句就相当于:
o = Object.create(Constructor.prototype);
// 当然,如果在Constructor函数中有一些初始化代码,Object.create不能执行那些代码


// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
o = Object.create({}, { p: { value: 42 } })

// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
o.p = 24
o.p
//42

o.q = 12
for (var prop in o) {
   console.log(prop)
}
//"q"

delete o.p
//false

//创建一个可写的,可枚举的,可配置的属性p
o2 = Object.create({}, { p: { value: 42, writable: true, enumerable: true, configurable: true } });

 

属性的查询和设置

   查询与设置两种方式: . 或 [] 方式

   对象给属性赋值时,首先会检查原型链上是否允许赋值操作。 如果 o 继承来的x是一个只读属性,那么是不允许赋值的,严格模式下会报错。 如果允许的话,只会在原对象上添加或修改,不会去修改原型链。

案例一:通过字面方式定义属性,默认属性特性是: 可配置、可枚举、可读/可写

var person = {name:"wj"};
var o = inherit(person);
    o.name = "wjj";
    console.log(o.name); // wjj
     console.log(person.name); //wj

案例二:defineProperty 修改 name 的特性时

var person = {name:"wj"};
Object.defineProperty(person,"name",{
    writable:false
})
var sub = inherit(person);
sub.name = "wjj"; //TypeError: Cannot assign to read only property 'name' of object '#<Object>'
console.log(sub.name);
console.log(person.name);

   注意:1:JavaScript中,只有在查询属性时才会体会到继承的存在,在设置属性则和继承无关,这是JavaScript的一个特性,该特性让程序员可以有选择地覆盖(override)继承的属性。

      2:属性的赋值要么失败,要么创建一个属性,要么在原始对象中设置属性。

删除属性

  delete  操作符 删除自有属性 并且是 configable:true; 

  delete 操作符只能删除自有属性,而不能删除继承属性(如果要删除继承属性必须通过原型对象来删除,删除同时所有继承该原型的对象都会受到影响)

检测属性 与 枚举属性

  

 

存取器属性 setter getter

   基本组成  

      enumerable
      configurable
      set
      get

     注意:存取器属性不具有可写性(writeable ), 如果属性同时拥有 set、get 则其可写、可读, 如果只 “set” 可写 如果只添加了 “get” 可读;

 

属性的特性

  属性除了包含名字和值之外,属性还包含一些标识它们可写、可枚举、可配置的特性。在ECMAScript3无法设置这些特性,其属性都是可读可写、可枚举、可配置的根本没有提供API供修改。

在ECMAScript5中引入了 查询 和 修改这些属性的API。

   这些给库开发者带来好处是:

1 可以通过这些API给原型对象添加方法,并设置其不可枚举,这让其看起来像内置方法

2 通过API设置属性不能修改和删除。

   ECMAScript5为了获取和设置这些特性,引入描述对象,而描述对象获取通过 Object.getOwnPropertyDescriptor;

根据属性类型不同,描述对象返回的内容也不一样:

  数据属性: 值 value 读\写 writeable、枚举 enumerable、可配置 configurable 

  存取器属性: set*、get*、枚举 enumerable、可配置 configurable 

先来了解下 getOwnPropertyDescriptor

  语法:

   /**
      * Gets the own property descriptor of the specified object.
      * An own property descriptor is one that is defined directly on the object and is not inherited from the object's prototype.
      * @param o Object that contains the property.
      * @param p Name of the property.
    */
    getOwnPropertyDescriptor(o: any, p: string): PropertyDescriptor;

从指定对象,获取自身属性描述对象; 从名字看出来,只能返回自生的属性,而继承而来的属性则只能通过获取其原型对象了

  下面看看具体实例

var o = {name:"HD"};
Object.defineProperty(o,"age",{
    configurable:true,
    enumerable:true,
    set:function(age){
        this.age = age;
    },
    get:function(){
        return this.age;
    }
});

var oDesc_name = Object.getOwnPropertyDescriptor(o,"name");

var oDesc_age = Object.getOwnPropertyDescriptor(o,"age");

var oDesc_money = Object.getOwnPropertyDescriptor(o,"toString");

var none = Object.getOwnPropertyDescriptor(o,"none");
// { get: [Function: get],set: [Function: set],enumerable: true,configurable: true }
console.log(oDesc_age);
// { value: 'HD',writable: true,enumerable: true, configurable: true }
console.log(oDesc_name);

// undefined console.log(oDesc_money);
// undefined
console.log(none); 
 

 

 

   如果要设置或修改描述对象通过 Object.defineProperty 和 Object.defineProperties  前者是单个,后者为批量;这两个区别是后者属性是同时添加的。

先了解下 Object.defineProperty 语法

 /**
      * Adds a property to an object, or modifies attributes of an existing property.
      * @param o Object on which to add or modify the property. This can be a native JavaScript object (that is, a user-defined object or a built in object) or a DOM object.
      * @param p The property name.
      * @param attributes Descriptor for the property. It can be for a data property or an accessor property.
      */
    defineProperty(o: any, p: string, attributes: PropertyDescriptor): any;
Object.defineProperty 添加或者修改自有属性,不能修改继承来的属性



 
 1 var o = {name:"HD"};
 2 //添加
 3 Object.defineProperty(o,"custom",{
 4     writable:true,
 5     configurable:true,
 6     enumerable:true,
 7     value:"我是先添加的"
 8 });
 9 console.log(Object.getOwnPropertyDescriptor(o,"custom"));
10 //修改
11 Object.defineProperty(o,"custom",{
12     writable:true,
13     configurable:true,
14     enumerable:true,
15      value:"被修改了 这么神奇"
16 });
17 
18 console.log(Object.getOwnPropertyDescriptor(o,"custom"));
{ value: '我是先添加的',writable: true,enumerable: true,configurable: true }

{ value: '被修改了 这么神奇', writable: true, enumerable: true,configurable: true }

 

  一种特殊情况,当属性configurable 只能从 true -> false ,当configurable为false时 除了writable可以被修改外 其它特新均不能被更改

 

 1 var o = {name:"HD"};
 2 //添加
 3 Object.defineProperty(o,"custom",{
 4     writable:true,
 5     configurable:false,
 6     enumerable:true,
 7     value:"我是先添加的"
 8 });
 9 //{ value: '我是先添加的',writable: true,enumerable: true,configurable: false }
10 console.log(Object.getOwnPropertyDescriptor(o,"custom"));
11 //修改 configurable
12 Object.defineProperty(o,"custom",{
13     writable:true,
14     configurable:true,  //TypeError: Cannot redefine property: custom
15     enumerable:true,
16     value:"被修改了 这么神奇"
17 });
18 //修改 enumerable
19 Object.defineProperty(o,"custom",{
20     writable:true,
21     configurable:false,  
22     enumerable:false,//TypeError: Cannot redefine property: custom
23     value:"被修改了 这么神奇"
24 });
25 //修改 writable
26 Object.defineProperty(o,"custom",{
27     writable:false,
28     configurable:false,  
29     enumerable:true,
30     value:"被修改了 这么神奇"
31 });
32 
33 console.log(Object.getOwnPropertyDescriptor(o,"custom"));
34 
35 // { value: '被修改了 这么神奇',writable: false,enumerable: true,configurable: false }

 

当需要一次添加或修改多个属性时,我们可能里用 defineProperties() 先来看看语法

   /**
      * Adds one or more properties to an object, and/or modifies attributes of existing properties.
      * @param o Object on which to add or modify the properties. This can be a native JavaScript object or a DOM object.
      * @param properties JavaScript object that contains one or more descriptor objects. Each descriptor object describes a data property or an accessor property.
      */
    defineProperties(o: any, properties: PropertyDescriptorMap): any;

  先看看下面实例:

 1 var now = Object.defineProperties({},{
 2     "custom":{
 3         writable:false,
 4         configurable:false,  
 5         enumerable:true,
 6         value:"被修改了 这么神奇"
 7     },
 8     "custom2":{
 9        writable:false,
10        configurable:false,  
11        enumerable:true,
12        value:"被修改了 这么神奇"
13     }
14 });
15 
16 console.log(now); //{ custom: '被修改了 这么神奇', custom2: '被修改了 这么神奇' }

 

 在不允许创建或修改的属性来说,如果用 Object.defineProperty()和 Object.defineProperties()会抛出错误!!!!

 问题汇总:

1     如果对象不可配置,可以编辑已有自有属性,但是不能添加新属性;
2     当属性configurable 只能从 true -> false ,当configurable为false时 除了writable可以被修改外 其它特新均不能被更改;
3     当属性不可配置时,数据属性 存取器属性 间不能相互转换;
4     当数据属性不可写时,修改其值会报错;

 

posted @ 2016-09-20 14:06  czhyuwj  阅读(274)  评论(0编辑  收藏  举报