基于《javascript 面向对象精要》整理下思路:

ECMA5 对象的定义是无序属性的集合,属性可以是基本值,对象(包含函数),属性都有一个名字,名字可以是标识符或者是字符串,映射到属性。所以对象也可说是一组名字/属性的组合。
有两种方式创建对象:构造函数,字面量;

//构造函数,先定义,在赋值
var obj1 = new Object();
obj1.name = 'obama';

//字面量,直接赋值
var obj2 = {
        name : 'bush'
    }

读取属性也有两种方式

obj1.name     //常用的是使用 . 点号直接读取属性
obj1['name']    //使用中括号里面是属性的字符串(有引号)也可以读取

//如果属性包含空格或者其他的非合法标识符就只能使用中括号,

属性有两种:
1,数据属性 named data property
2,访问器属性 named accessor property

两者的区别,先看数据属性的例子

var obj  = {
    name : 'obama'
}
obj.name;
consle.log(obj.name)        //obama
//正常情况下,直接访问obj.name 不会输出任何结果,只是引擎访问这个属性,等待下一步的操
//作,如果有下一步操作,就把这属性的值返回出来,提供使用如:console.log()。

也就是说,数据属性包含属性的具体的值,我们可以访问,访问器属性则没有,只供引擎使用,
那么如何描述这两个属性呢,那就是特性,attribute(描述对象属性的属性),正常情况下,不可访问,在内部用[[ ]]包裹。如果想要访问,就用专用的方法,
Object.getOwnPropertyDescriptor(object,property)包含两个参数(对象名称,属性名称),返回一个对象包含具体的特性。

var obj  = {
    name : 'obama'
}
var properties  = Object.getOwnPropertyDescriptor(obj,'name');

console.dir(properties);

chrome

可以看到有四个属性,这些就是属性的数据属性,我们可以访问的到的,也是可以修改的,使用两个特殊的方法
Object.defineProperty(); 定义单个对象的属性
Object.defineProperties(); 定义多个对象的属性

记住使用以上两个函数,会对把有真假值特性默认为false,而正常JS里都是true,如果定义的属性不存在就会创建新的属性!!

var obj1 = { };
Object.defineProperty(obj1,'name',{
    configurable : true,     //决定其他特性是否可以修改,包含直接删除delete属性值即value;
    enumerable : true,     //是否可以枚举
    writable : true,          //value 是否可以修改
    value : 'obama'        //对象属性真正保存值的地方,上面的都是对它的描述
    }
);     
var obj1 = {
    name : 'obama'
}

上面的两个对象是相等的,我们在直接些对象字面量的同时,JS引擎就默认生成了上面的属性,我们也可以修改下

var obj1 = { };
Object.defineProperty(obj1,'name',{
    configurable : true,
    enumerable : false,
    writable : true,
    value : 'obama'   
    }
); 
//下面的函数需要是枚举特性才能使用
obj1.propertyIsEnumerable('name');    //false
console.dir( Object.keys(obj1));        //数组是空
var properties;
for(properties in obj1){
    console.log('it has been search')           // undefined
}
//*以下是误区,in和hasOwnProperty函数查找的是否有属性,不论是否可以枚举*
console.log('name' in obj1);            //true
console.log(obj1.hasOwnProperty('name'))            //true

当然我们也可以同时定义多个属性

var obj = { };
Object.defineProperties(obj,{
        name:{
        configurable : true,
        enumerable : true,
        writable : true,
        value : 'obama'
        },
        age :{
        configurable : true,
        enumerable : true,
        writable : true,
        value : 77
        },
        behavior: {
        configurable : true,
        enumerable : true,
        writable : true,
        value : function(){
            alert('i am the presdent of Amerca')
            }
        }
});
obj = {
    name : 'obama',
    age : 77,
    behavior : function(){ alert('i am the presdent of Amerca')}
}

下面说说访问器属性,目前没有方法,直接查看所有的特性,但是我们可以设置特性,和数据属性使用一样的方法,没有value 和writable这两个属性,但是多[[get]]和[[set]]的方法;

//字面量
var obj = {
    _name : 'obama',  //使用下划线_ 只是约定成俗的写法,表示私有的(实际上我们也能访问)
    get name(){                //get 后面的name就是我们可以访问正常的属性,
        return this._name;
    },
    set name(value){
        this._name  = value;
    }
};
//或者使用函数
var obj = {
    _name : 'obama'
};
Object.defineProperty(obj,'name',{
       get : function (){
           return this._name;
       },
       set : function(value){
           this._name = value;
       },
       configurable : true,
       enumerable : true
 })

console.log(obj.name)        //obama

访问器属性有趣的地方在于如果我们把get的方法换成其他,比如不返回它的值

get : function(){
    return  console.log(’i am Kim Jong-un‘);
}
obj.name      //即使只是写出这个属性也会输出’i am Kim Jong-un’

我们通过obj.name永远得不到想要的值,当然这样设置没有任何意思,只是了解JS是如何取得属性的值,

同时设置数据属性和访问器属性是会得到一个错误。

属性首次添加给对象时,JS就会在对象上调用[[Put]]方法,在对象内部开辟新的节点保存属性,这个新属性有默认的特性,重点是这个属性仅会保存在这对象上,也就是说是这个对象的自有属性!自有!自有![[Extensible]]方法,确定对象是否可以扩展,有三个具体的方法:

1,禁止扩展

var obj = {
    name : 'obama'
};
Object.preventExtensions(obj);
obj.age = 77;
console.log(obj.age)        //undefined;
//无法增加属性,但是可以修改删除原有属性

Object.isExtensible(obj)    //false 表示不可以扩展!

2,对象封印

var obj = {
    name : 'obama'
};
Object.seal(obj);        //不仅不可以扩展也不可删除属性,只能读写
delete obj.name        //false 
obj.name = ' Kim Jong-un';
console.log(obj.name)         // Kim Jong-un
//可以修改属性的writable(修改后只能读取),只能true ->false,不能false ->true;

Object.isSealed(obj);         //true;
Object.isExtensible(obj)    //false;

3,对象冻结

var obj = {
    name : 'obama'
};
Object.freeze(obj);        //冻结后只可以读取值,,不可以修改删除值

Object.isFrozen(obj)            //true;
Object.isSealed(obj);         //true;
Object.isExtensible(obj)    //false;

对象还有一个实用的方法,Object.getOwnPropertyNames();在对象本身的属性不可以枚举的情况下也能列出,返回一个数组,对比Object.keys() 只能列举可以枚举的.


注:上面的例子在严格模式下会抛出错误,非严格模式会失败
使用构造函数创建对象存在一个问题,就是必须使用new 操作符,构造函数也是函数如果直接调用的话,会把内部的this作用域指向全局;

function Fn(args){
    this.args = args;
}
var obj1 = Fn('test');
obj1       //undefined
args       //test

var obj2 = new Fn('test');
obj2.args           //test;

//安全的构造函数
function Fn(args){
    if( this instanceof Fn){
        this.args = args;
    }else{
        return new Fn(args)
    }
}
//也可以使用Object.creat()的方法来创建对象
var obj1 = { };
var obj2 = Object.create(null);
//obj2是一个真正意义上空的对象,没有任何的继承,比obj1更空,obj1继承Object对象的属性和方法。

scupture
35 声望1 粉丝

var me = 'missing you';