js中的对象理解和使用起来都很简单,并且很频繁的使用。但是,总有细节,是我们可能会忽略的、或者是拿捏不定的
参考链接:http://javascript.ruanyifeng.com/grammar/object.html
1. 概述#
1.1对象的含义
所谓对象,就是一种无序的数据集合,由若干个“键值对”(key-value)构成。
对象的生成方法,通常有三种方法:
var o1 = {};
var o2 = new Object();
var o3 = Object.create(null);
1.2 对象的引用
如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。
var o1 = {};
var o2 = o1;
o1.a = 1;
o2.a // 1
o2.b = 2;
o1.b // 2
此时,如果取消某一个变量对于原对象的引用,不会影响到另一个变量。
var o1 = {};
var o2 = o1;
o1 = 1;
o2 // {}
但是,这种引用只局限于<code>对象</code>,对于原始类型的数据则是<code>传值引用</code>,也就是说,都是值的拷贝。
var x = 1;
var y = x;
x = 2;
y // 1
1.3 表达式还是语句区别
对象采用大括号表示,这导致了一个问题:如果行首是一个大括号,它到底是表达式还是语句?
{ foo: 123 }
JavaScript引擎读到上面这行代码,会发现可能有两种含义。第一种可能是,这是一个表达式,表示一个包含foo属性的对象;第二种可能是,这是一个语句,表示一个代码区块,里面有一个标签foo,指向表达式123。
为了避免这种歧义,JavaScript规定,如果行首是<b>大括号</b>,一律解释为语句(<b>即代码块</b>)。如果要解释为表达式(<b>即对象</b>),必须在大括号前加上<b>圆括号</b>。
这种差异在eval语句中反映得最明显:
eval('{foo: 123}') // 123
eval('({foo: 123})') // {foo: 123}
2. 相关操作#
2.1 查看所有key
var o = { key1: 1, key2: 2};
Object.keys(o);// ['key1', 'key2']
2.2 删除属性
delet命令用于删除对象的属性,删除成功后返回true。
var o = {p: 1};
Object.keys(o) // ["p"]
delete o.p // true
o.p // undefined
Object.keys(o) // []
注意,删除一个不存在的属性,delete不报错,而且返回true。
var o = {};
delete o.p // true
因此,不能根据delete命令的结果,认定某个属性是存在的。
var o = Object.defineProperty({}, 'p', { value: 123, configurable: false});
o.p // 123
delete o.p // false
<code>delete命令只能删除对象本身的属性!!!</code>
2.3 in运算符
in运算符用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回true,否则返回false。in运算符的一个问题是,它不能识别对象<i>继承</i>的属性。
var o = new Object();
o.hasOwnProperty('toString') // false
'toString' in o // true
使用for in遍历对象
var o = {a: 1, b: 2, c: 3};
for (var i in o) {
console.log(o[i]);
}
//提取对象属性
var obj = { x: 1, y: 2};
var props = [];
var i = 0;
for (props[i++] in obj);
props // ['x', 'y']
2.4 with语句
(1)它的作用是操作同一个对象的多个属性时,提供一些书写的方便。
// 例一
with (o) {
p1 = 1;
p2 = 2;
}
// 等同于
o.p1 = 1;
o.p2 = 2;
// 例二
with (document.links[0]){
console.log(href);
console.log(title);
console.log(style);
}
// 等同于
console.log(document.links[0].href);
console.log(document.links[0].title);
console.log(document.links[0].style);
注意,with区块内部的变量,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量。这是因为with区块没有改变作用域,它的内部依然是当前作用域。
var o = {};
with (o) {
x = "abc";
}
o.x // undefined
x // "abc"
(2)这是with语句的一个很大的弊病,就是绑定对象不明确。
with (o) { console.log(x);}
单纯从上面的代码块,根本无法判断x到底是全局变量,还是o对象的一个属性。这非常不利于代码的除错和模块化,编译器也无法对这段代码进行优化,只能留到运行时判断,这就拖慢了运行速度。因此,建议不要使用with
语句,可以考虑用一个<code>临时变量</code>代替with。
with(o1.o2.o3) { console.log(p1 + p2);}
// 可以写成
var temp = o1.o2.o3;console.log(temp.p1 + temp.p2);
(3)with语句少数有用场合之一,就是替换模板变量。