1
  • 属性特性(property attribute):每个属性与之相关的值:

    • 可写(writable attribute);

    • 可枚举(enumerable attribute);

    • 可配置(configurable attribute);

  • 对象特性(object attribute):

    • 原型(prototype);

    • 类(class);

    • 扩展标记(extensible flag);

  • 三类js对象:

    • 内置对象(native object):由ECMAScript规范定义的对象或类;

    • 宿主对象(host object):由js解释器所嵌入的宿主环境定义的;

    • 自定义对象(user-defined object):由运行中的js代码创建的对象

  • 两类属性:

    • 自有属性(own property):直接在对象中定义的属性;

    • 继承属性(inherited property):在对象的原型对象中定义的属性;

1 创建对象

三种方法:直接量;newObject.create()函数;

1.1 对象直接量

语法:

var o = {};

1.2 通过new创建对象

语法:

var o = new Object();

1.3 原型

通过Object.prototype获得对原型对象的引用

1.4 Object.create()

第一个参数是这个对象的原型;第二个可选参数是对对象的属性进行进一步描述



//创建一个普通的空对象
var o = Object.create(Object.prototype);

2 属性的查询和设置

[].

2.1 作为关联数组的对象

JavaScript对象都是关联数组(字典、映射、散列等)

2.2 继承

[暂跳]

2.3 属性访问错误

当访问不存在的对象的属性就会报错,可以通过下面方法避免出错:


var book = {};
var len;
if (book.subtitle) {
    len = book.subtitle.length;
}
console.log(len); //undefined

//或者
var book = {subtitle:"toJSON"};
var len;
len = book && book.subtitle && book.subtitle.length; //&&运算符的短路行为
console.log(len); //6
//当左操作数是真值时,“&&”运算符将计算右操作数的值并将其返回作为整个表达式的计算结果

2.4 删除属性

delete运算符不能删除继承属性

3 检测属性

5种方法:

in运算符,检测自有属性和继承属性

var o = {name:"Oliver",age:18,nothing:undefined};
console.log("name" in o); //True
console.log("toString" in o); //True
console.log("nothing" in o); //True

hasOwnProperty方法,检测自有属性

var o = {name:"Oliver",age:18,nothing:undefined};
console.log(o.hasOwnProperty("toString")); //False
console.log(o.hasOwnProperty("name")); //True

propertyIsEnumerable方法,检测自有可枚举的属性

var o = {name:"Oliver",age:18,nothing:undefined};
console.log(o.propertyIsEnumerable("toString")); //False
console.log(o.propertyIsEnumerable("name")); //True

"!=="方法,检测属性是否为undefined

var o = {name:"Oliver",age:18,nothing:undefined};
console.log(o.name !== undefined); //True
console.log(o.nothing !== undefined); //False

有一种场景只能使用in运算符。in可以区分不存在的属性和存在但是值为undefined的属性:

var o = {name:"Oliver",age:18,nothing:undefined};
console.log("nothing" in o); //True
console.log(o.nothing !== undefined); //False
delete o.nothing;
console.log("nothing" in o); //False
console.log(o.nothing !== undefined); //False

需要注意的是,"!=="可以区分undefined和null

4 枚举属性

把p中的可枚举属性赋值到o中,并返回o,如果有同名属性则覆盖o中的属性

function extend (o, p) {
    for (var prop in p) {
        o[prop] = p[prop];
    }
    return o;
}

如:

var p = {name:"Oliver",age:18,nothing:undefined};
var o = {};

function extend (o, p) {
    for (var prop in p) {
        o[prop] = p[prop];
    }
    return o;
}

console.log(extend(o,p));

将p中的可枚举属性复制到o中,并返回o,如果有同名属性则不覆盖o中的属性

function merge (o, p) {
    for (var prop in p) {
        if (o.hasOwnProperty(prop)) {
            continue;
            o[prop] = p[prop];
        }
    }
    return o;
}

如:

var p = {name:"Oliver",age:18,nothing:undefined};
var o = {name:"Oli"};

function merge (o, p) {
    for (var prop in p) {
        if (o.hasOwnProperty(prop)) {
            continue;
            o[prop] = p[prop];
        }
    }
    return o;
}

console.log(merge(o,p).name); //Oli

如果o中的属性在p中没有同名属性,则从o中删除这个属性

function restrict (o, p) {
    for (var prop in o) {
        if (!(prop in p)) {
            delete o[prop];
        }
    }
    return o;
}

如:

var p = {age:18,nothing:undefined};
var o = {name:"Oli"};

function restrict (o, p) {
    for (var prop in o) {
        if (!(prop in p)) {
            delete o[prop];
        }
    }
    return o;
}

console.log(merge(o, p).name); //undefined

如果o中的属性在p中存在同名属性,则从o中删除这个属性

function subtract (o, p) {
    for (var prop in o) {
        if (prop in p) {
            delete o[prop];
        }
    }
    return o;
}

如:

var p = {name:"Oliver",age:18,nothing:undefined};
var o = {name:"Oli"};

function subtract (o, p) {
    for (var prop in o) {
        if (prop in p) {
            delete o[prop];
        }
    }
    return o;
}

console.log(subtract(o, p).name); //undefined

返回一个新对象,这个对象同时拥有o的属性和p的属性,如果有重名属性,使用p中的属性值

function union (o, p) {
    for (var prop in o) {
        if (prop in p) {
            o[prop] = p[prop]
        }
    }
    return o;
}

如:

var p = {name:"Oliver",age:18,nothing:undefined};
var o = {name:"Oli"};

function union (o, p) {
    for (var prop in o) {
        if (prop in p) {
            o[prop] = p[prop]
        }
    }
    return o;
}

console.log(union(o, p).name); //Oliver

返回一个新对象,这个对象同时拥有o的属性和p的属性,如果重名,使用o的值

function intersection (o, p) {
    for (var prop in o) {
        if (prop in p) {
            delete p[prop];
        }
    }
    return o;
}

如:

var p = {name:"Oliver",age:18,nothing:undefined};
var o = {name:"Oli"};

function intersection (o, p) {
    for (var prop in o) {
        if (prop in p) {
            delete p[prop];
        }
    }
    return o;
}

console.log(intersection(o, p).name); //Oliver

返回一个数组,这个数组包含的是o中可枚举的自有属性的名字

5 属性getter和setter

  • 存取器属性(accessor property):由getter和setter定义的属性;它不同于数据属性(data property),数据属性只有一个简单的值;

语法:

var o = {
    data_prop: value,/*这是普通数据属性*/
get accessor_prop(){/*这里是函数体*/},
set accessor_prop(value){/*这里是函数体*/}
};

这个定义没有使用function关键字,而是使用get和(或)set

存取器属性是可以继承的


var o = {
    n: 0,/*这是普通数据属性*/
get next(){return this.n++},
set next(n){this.n = n}
};
o.next = 10; //setter
console.log(o.next) //getter

6 属性的特性

  • 存取器属性的四个特性:读取(get)、写入(set)、可枚举性(enumerable)和可配置性(configurable)

  • 数据属性的四个特性:值(value)、可写性(writable)、可枚举性(enumerable)和可配置性(configurable)

获得某个对象特定属性的属性描述符

Object.getOwnPropertyDescriptor()方法:


//name数据属性
let o = {
    name: "Oliver",
    get transferName(){return this.name},
    set transferName(value){this.name = name}
};
let result = Object.getOwnPropertyDescriptor(o, "name");
console.log(result); //Object
for (let name in result) {
    console.log(name, result[name]);
}
//value Oliver
//writable True
//enumerable True
//configurable True

//transferName存取器属性
let o = {
    name: "Oliver",
    get transferName(){return this.name},
    set transferName(value){this.name = name}
};
let result = Object.getOwnPropertyDescriptor(o, "transferName");
console.log(result); //Object
for (let name in result) {
    console.log(name, result[name]);
}
//get function transferName(){return this.name} 
//set function transferName(value){this.name = name} 
//enumerable True
//configurable True

设置属性的特性

Object.defineProperty()方法:


let o = {
    name: "Oliver",
    get transferName(){return this.name},
    set transferName(value){this.name = name}
};
let result = Object.getOwnPropertyDescriptor(o, "name");
console.log(result); //Object
for (let name in result) {
    console.log(name, result[name]);
}
//value Oliver
//writable True
//enumerable True
//configurable True
Object.defineProperty(o, "name", {
    value: "Oli",
    writable: false,
    enumerable: false,
    configurable: false
});
let result1 = Object.getOwnPropertyDescriptor(o, "name");
console.log(result1); //Object
for (let name in result1) {
    console.log(name, result1[name]);
}
//value Oli 
//writable False 
//enumerable False 
//configurable False 

该方法不能修改继承属性

设置多个属性特性

Object.defineProperties()方法:

语法:Object.defineProperties(Object, props)


var obj = {};
Object.defineProperties(obj, {
    x: {value: 1, writable: false, enumerable: true, configurable: false},
    y: {get: function(){return this.x}, enumerable: true, configurable: false}
});
console.log(obj.y); //1
console.log(obj.x); //1
obj.x = 2;
console.log(obj.x); //严格模式下报错

老式API

在ES5之前,需要用到

  • __lookupGetter()__

  • __lookupSetter()__

  • __defineGetter()__

  • __defineSetter()__

7 对象的三个属性

  • 原型(prototype)

  • 类(class)

  • 可扩展性(extensible)

7.1 原型属性

对象的原型属性是用来继承属性的


var obj = {};
console.log(obj.constructor); //function Object(){ [native code] }
console.log(obj.__proto__); //Object
console.log(Object); //function Object(){ [native code] }
console.log(Object.prototype); //Object
console.log(Object.prototype.isPrototypeOf(obj)); //True

检测一个对象是否是另一个对象的原型

isPrototypeOf()方法


var obj = {};
var anotherObj = Object.create(obj);
console.log(Object.prototype.isPrototypeOf(obj)); //True
console.log(obj.isPrototypeOf(anotherObj)); //True

7.2 类属性

是一个字符串,用以表示对象的类型信息,默认的toString()方法很有可能被修改,所以应该使用下面的classof函数:

查询类

使用classof()函数:


function classof (o) {
    if (o === null) {
        return "Null";
    }
    if (o === undefined) {
        return "Undefined";
    }
    return Object.prototype.toString.call(o).slice(8, -1);
}

例如:

console.log(classof(obj)); //Object
console.log(classof(Number)); //Function
console.log(classof(123)); //Number

7.3 可扩展性

可扩展性表示是否可以给对象添加新属性

设置为不可扩展,检测是否不可扩展

  • Object.preventExtensions()设置为对象不可扩展

  • Object.isExtensible()检测是否可扩展


var obj = {
    name: "Oliver"
};
Object.preventExtensions(obj);
obj.name = "Oli"; //可修改属性的值
delete obj.name; //可配置属性
obj.age = 18; //不可扩展 严格模式下报错

设置为不可扩展且不可配置,检测是否不可扩展且不可配置

  • Object.seal()

  • Object.isSealed()


var obj = {
    name: "Oliver"
};
Object.seal(obj);
obj.name = "Oli"; //可修改属性的值
delete obj.name; //不可配置属性 严格模式下报错
obj.age = 18; //不可扩展 严格模式下报错

设置为不可扩展、不可配置且所有数据属性设置为只读(setter不受影响),以及检测方法

  • Object.freeze()

  • Object.isFrozen()


var obj = {
    name: "Oliver",
    anotherObj: {
        name: "Oliver"
    },
    set setName (value) {
        this.name = value;
    }
};
Object.freeze(obj);
obj.anotherObj.name = "Oli"; //可以修改属性值为对象的子对象的属性
obj.setName = "Oli"; //不可修改setter属性的值
obj.name = "Oli"; //不可修改属性的值
delete obj.name; //不可配置属性 严格模式下报错
obj.age = 18; //不可扩展 严格模式下报错

8 序列化对象

  • 对象序列化(serialization):将对象的状态转换为字符串,或将字符串还原成对象;

    • JSON.stringify()

    • JSON.parse()

  • JSON(JavaScript Object Notation):JavaScript对象表示法;


var date = new Date();
console.log(date.toString()); //与JSON.stringify()的返回值不同
console.log(date.toJSON()); //与JSON.stringify()的返回值一样

9 对象方法

  • toString方法

  • toLocaleString方法

  • toJSON方法(严格意义上不算对象原型的方法)

  • valueOf方法(用在需要将它转换成某种原始值而非字符串的时候)


JS菌
6.4k 声望2k 粉丝