1.对象的结构:
对象中包含一系列属性,这些属性是无序的。每个属性都有一个字符串key和对应的value。对象有2种访问方式,如下图所示:
var obj = {}; obj[1] = 1; obj['1'] = 2; obj; // Object {1: 2} var obj = {}; obj.y = 2; obj.x = 1; obj ; //{y: 2, x: 1}
2.创建对象的方式
2.1.通过字面量的方式来创建对象,如下图所示,那么访问对象的时候就可以通过obj2.z的方式来访问
var obj2 = { x : 1, y : 2, o : { z : 3, n : 4 } };
2.2.通过new/原型链的方式来创建对象,通过继承的方式来创建对象,下面的代码中,foo相当于父类,obj相当于子类,foo中定义了z属性,当在子类访问一个子类中未定义的属性时,会向上查找,查找父类中的prototype属性中是否存在该属性,能够查找到该属性,但是这个属性并不属于子类。
function foo(){} foo.prototype.z = 3;
//创建对象 var obj =new foo(); obj.y = 2; obj.x = 1; obj.x; // 1 obj.y; // 2 obj.z; // 3 typeof obj.toString; // ‘function' 'z' in obj; // true obj.hasOwnProperty('z'); // false
但是当子类中重新定义prototype中对应的属性时,obj.hasOwnProperty()函数就返回true,删除属性的时候就只能删除自身定义的属性,不能删除父类中定义的属性
obj.z = 5; obj.hasOwnProperty('z'); // true foo.prototype.z; // still 3 obj.z; // 5
obj.z = undefined; obj.z; // undefined delete obj.z; // true obj.z; // 3
2.3通过Object.create方式创建对象,如下面的代码所示,这种 方式和上面的方式是有一点不同的,具体看下面的图。
var obj = Object.create({x : 1}); obj.x // 1 typeof obj.toString // "function" obj.hasOwnProperty('x');// false
var obj = Object.create(null); obj.toString // undefined
3.属性操作的几种方式
3.1属性读写,属性读写一般有2种方式,数组或者通过运算符.来读写属性,如下面的代码所示,一般用运算符.但是出现一次顺序排列的key时,推荐采用数组的形式来访问对象。
var obj = {x : 1, y : 2}; obj.x; // 1 obj["y"]; // 2 obj["x"] = 3; obj.y = 4; var obj = {x1 : 1, x2 : 2}; var i = 1, n = 2; for (; i <= n; i++) { console.log(obj['x' + i]); }
这里,还要注意一个小小的坑,就是用for来对 对象进行遍历时,enumrable属性为false的对象是不会出现在遍历列表中的。
var p; for (p in obj) { console.log(obj[p]); }
还要一个写代码的小技巧是,在对对象访问时候,先判断该对象是否为空,是否具有该属性
var obj = {x : 1}; obj.y; // undefined var yz = obj.y.z; // TypeError: Cannot read property 'z' of undefined obj.y.z = 2; // TypeError: Cannot set property 'z' of undefined
所以推荐下面的方式来访问,先做判断:
var yz; if (obj.y) { yz = obj.y.z; } var yz = obj && obj.y && obj.y.z;
3.2 属性删除,直接用delelte删除对象的属性,configurable为false的属性不能删除,如下图中的Object.prototype
var person = {age : 28, title : 'fe'}; delete person.age; // true delete person['title']; // true person.age; // undefined delete person.age; // true delete Object.prototype; // false, var descriptor = Object.getOwnPropertyDescriptor(Object, 'prototype'); descriptor.configurable; // false
3.3 属性检测,通过属性检测可以判断对象中存不存在对应的属性,通过hasOwnProperty()或者propertyIsEnumerable()方法来判断, 如下图中代码所示:
var cat = new Object; cat.legs = 4; cat.name = "Kitty"; 'legs' in cat; // true 'abc' in cat; // false "toString" in cat; // true, inherited property!!! cat.hasOwnProperty('legs'); // true cat.hasOwnProperty('toString'); // false cat.propertyIsEnumerable('legs'); // true cat.propertyIsEnumerable('toString'); // false
通过Object.defineProperty()方法可以自定义对象的属性,如下图中代码所示:
Object.defineProperty(cat, 'price', {enumerable : false, value : 1000}); cat.propertyIsEnumerable('price'); // false cat.hasOwnProperty('price'); // true
接下来说明!=与!==的区别,如下图中所示,!=模式下,undefined与null相同,但在!==严格模式下,undefined与null不同
3.4 属性枚举,主要用在用for来遍历对象中的属性时,如下图的代码,propertyIsEnumerable属性为false的属性在遍历时,不会被遍历出来。 Object.keys(person)来遍历对象中的key也是一样的
var o = {x : 1, y : 2, z : 3}; 'toString' in o; // true o.propertyIsEnumerable('toString'); // false var key; for (key in o) { console.log(key); // x, y, z } var obj = Object.create(o); obj.a = 4; var key; for (key in obj) { console.log(key); // a, x, y, z } var obj = Object.create(o); obj.a = 4; var key; for (key in obj) { if (obj.hasOwnProperty(key)) { console.log(key); // a } }
4.getter和setter介绍
若对象中的某些属性,不想暴露,可以使用set,get方式来进行属性访问,如下图的代码所示:
var man = { name : 'Bosn', weibo : '@Bosn', get age() { return new Date().getFullYear() - 1988; }, set age(val) { console.log('Age can\'t be set to ' + val); } } console.log(man.age); // 27 man.age = 100; // Age can't be set to 100 console.log(man.age); // still 27
还有更复杂一点的set 和get方式,
var man = { weibo : '@Bosn', $age : null, get age() { if (this.$age == undefined) { return new Date().getFullYear() - 1988; } else { return this.$age; } }, set age(val) { val = +val; if (!isNaN(val) && val > 0 && val < 150) { this.$age = +val; } else { throw new Error('Incorrect val = ' + val); } } } console.log(man.age); // 27 man.age = 100; console.log(man.age); // 100; man.age = 'abc'; // error:Incorrect val = NaN
get和set 方式还可以和原型链进行结合,将帮助我们更好地理解对象的属性
function foo() {} Object.defineProperty(foo.prototype, 'z', {get : function(){return 1;}}); var obj = new foo(); obj.z; // 1 obj.z = 10; obj.z; // still 1
Object.defineProperty(obj, 'z', {value : 100, configurable: true}); obj.z; // 100; delete obj.z; obj.z; // back to 1
var o = {}; Object.defineProperty(o, 'x', {value : 1}); // writable=false, configurable=false var obj = Object.create(o); obj.x; // 1 obj.x = 200; obj.x; // still 1, can't change it
Object.defineProperty(obj, 'x', {writable:true, configurable:true, value : 100}); obj.x; // 100 obj.x = 500; obj.x; // 500
5.属性标签
这里主要介绍通过Object.getOwnPropertyDescriptor( )方法来获取对象的属性的标签
Object.getOwnPropertyDescriptor({pro : true}, 'pro'); // Object {value: true, writable: true, enumerable: true, configurable: true} Object.getOwnPropertyDescriptor({pro : true}, 'a'); // undefined
当需要同时定义多个属性时候,可以通过Object.defineProperties()方式,如下图所示:
Object.defineProperties(person, { title : {value : 'fe', enumerable : true}, corp : {value : 'BABA', enumerable : true}, salary : {value : 50000, enumerable : true, writable : true}, luck : { get : function() { return Math.random() > 0.5 ? 'good' : 'bad'; } }, promote : { set : function (level) { this.salary *= 1 + level * 0.1; } } }); Object.getOwnPropertyDescriptor(person, 'salary'); // Object {value: 50000, writable: true, enumerable: true, configurable: false} Object.getOwnPropertyDescriptor(person, 'corp'); // Object {value: "BABA", writable: false, enumerable: true, configurable: false} person.salary; // 50000 person.promote = 2; person.salary; // 60000
下面这张图详细描述了属性标签
7.序列化和对象方法
通过JSON.stringify()方法来让对象序列化,通过JSON.parse()方法来是json字符串转换为json对象。
var obj = {x : 1, y : true, z : [1, 2, 3], nullVal : null}; JSON.stringify(obj); // "{"x":1,"y":true,"z":[1,2,3],"nullVal":null}" obj = {val : undefined, a : NaN, b : Infinity, c : new Date()}; JSON.stringify(obj); // "{"a":null,"b":null,"c":"2015-01-20T14:15:43.910Z"}" obj = JSON.parse('{"x" : 1}'); obj.x; // 1
通过 字符串+对象的方式可以自动调用对象的toString()或者valueOf()方法,如下图中代码所示:
var obj = {x : 1, y : 2}; obj.toString(); // "[object Object]" obj.toString = function() {return this.x + this.y}; "Result " + obj; // "Result 3", by toString +obj; // 3, from toString obj.valueOf = function() {return this.x + this.y + 100;}; +obj; // 103, from valueOf "Result " + obj; // still "Result 3"