-
对象的创建
- 对象字面量
var obj = { "key1" : "value1", "key2" : " value2" }
如果对象的键不是javascript保留字的话可以不加引号
- 函数对象
function createObject(){ this.key1 = "value1"; this.key2 = "value2"; // some code here } var funcObj = new createObject();
在javascript中函数也是对象,它可以通过new关键字将函数作为一个构造器创建对象。
-
属性
- 属性的初始化
在上面代码中key1,key2就是属性的初始化创建,分别初始化为value1和value2。在对象被创建的同时,key1和key2也被创建。 - 属性的读取
无论是字面量对象还是函数对象,属性的访问都是一致的。
// 方式一: console.log(obj.key1); // value1 console.log(funcObj.key1); // value1 // 方式二: console.log(obj["key1"]); // value1 console.log(funcObj["key1"]); // value1 // 方式三: var attrName = "key1"; console.log(obj[attrName]); // value1 console.log(funcObj[attrName]); // value1
其实,方式二和方式三是本质上是一样的,都是通过字符串进行属性访问,不过为了显示使用变量作为键名来访问属性的方式,这里将它们分开以便说明。
注意:1. 如果读取的属性不存在,会返回undefined
2. 如果在不存在的属性返回值undefined中再读取属性,程序会抛出TypeError异常。比如:
obj.key3.name就会抛出异常。可以使用obj.key3 && obj.key3.name避免异常。
- 属性的赋值(更新)
属性的赋值很简单,就是在读取方式的基础上添加赋值语句。
// 方式一: obj.key1 = "newValue1"; funcObj.key1 = "newValue1"; // 方式二: obj["key1"] = "newValue1"; funcObj["key1"] = "newValue1"; // 方式三: var attrName = "key1"; obj[attrName] = "newValue1"; funcObj[attrName] = "newValue1";
注意:如果赋值给一个对象本身没有的属性,javascript会把它自动添加到对象的属性列表中
- 属性的删除
// 方式一: delete obj.key1; delete funcObj.key1; // 方式二: delete obj["key1"]; delete funcObj["key1"]; // 方式三: var attrName = "key1"; delete obj[attrName]; delete funcObj[attrName];
注意:删除对象属性可能让来自原型链中的同名属性渗透出来
- 属性的初始化
-
原型
每个对象都连接到一个原型对象,并且它可以从中继承属性,所有通过对象字面量创建的对象都连接到Object.prototype;而所有通过函数创建的对象都连接到Function.prototype(该原型本身连接到Object.prototype)。
使用赋值语句可以轻易地改变对象的原型对象。比如:Object.create = function(o){ var F = function(){}; //创建新对象构造器 F.prototype = o; //新对象的原型为o,即原对象 return new F(); //返回一个新对象 }; var newObj = Object.create(obj);
上面代码创建了一个原型对象是obj的函数对象。
在对象读取属性时,读取属性的顺序是本身--原型--原型......--Object.prototype。这个过程称为委托。
直到找到读取的属性时,才返回属性值,并且不再往下搜索属性。如果直到Object.prototype都没有找到该属性,返回undefined。
注意:1.原型连接只有在读取时才会有用,更新时是不会触及和影响到原型连接的。
2.原型是一种动态关系,如果添加一个新属性到原型中,那么该属性对所有基于该原型创建的对象可见。
- 反射
原型链存在着一些不必要的属性,比如toString,constructor
有两种方法过滤这些属性:// 方式一 for(var attr in obj){ if(typeof attr !== 'function'){ console.log(attr + ": " + obj[attr]); } } // 方式二 for(var attr in obj){ if(person.hasOwnProperty(attr)){ console.log(attr + ": " + obj[attr]); } }
- 遍历
for in语句可用于遍历对象中所有属性名。该枚举过程会列出所有的属性,包括函数和你可能不关心的原型中的属性for(var attr in obj){ if(typeof attr !== 'function'){ console.log(attr + ": " + obj[attr]); } }
注意:for in遍历属性的顺序是不确定的。如果需要以特定的顺序读取属性,最好不用for in。
属性按一定顺序遍历:var i; var properties = [ 'key1', 'key2' ]; for(i = 0; i < properties.length; i++){ console.log(properties[i] + ": " + obj[properties[i]]); }
- 引用
对象通过引用传递,对象永远不会被赋值
上面代码原意是希望拷贝obj对象,但是直接使用赋值语句仅仅表示cloneObj变量引用了obj对象,即cloneObj指向了obj的内存地址,并没有实现对象的拷贝。var cloneObj = obj;
- 拷贝
浅拷贝
上面代码仅仅拷贝了obj对象的一层,如果obj的某个属性时引用类型,那么并没有彻底解决对象拷贝时存在属性引用的问题。function shallowClone(obj){ var newObj = {}; for(var attr in obj){ newObj[attr] = obj[attr]; } return newObj; } var cloneObj = shallowClone(obj);
深拷贝function deepClone(obj){ var objString = JSON.stringify(obj); var newObjString = objString; var newObj = JSON.parse(newObjString); return newObj; } var cloneObj = deepClone(obj);
网友评论