JavaScript对象的基本用法
本文主要讲述了:
- JS对象声明的方法
- JS对象属性的操作(增删改查)
- JS对象的遍历方法
- 以及一些个小区别
对象是JavaScript的核心概念,也是重要的数据类型,他是JavaScript的其中数据类型(string,number,bool,symbol,null,undefined,object)中唯一一种复杂类型。
甚么是对象?简单说对象就是“键值对"(无序的数据)的集合。
var obj = {
foo: 'Hello',
bar: 'World'
};
一、声明对象的方法
方法一:
上述代码中大括号就定义了一个对象,并赋值给变量obj,即obj就指向一个对象。该对象内部包含两个键值对(又称成员),一个键值对是foo:'Hello',其中foo是键名(成员名称),字符串Hello是键值(成员值),键名和键值之间用冒号分隔。第二个键值对是bar:'World',同上。两个键值对之间用逗号隔开。
对象的所有键名都是字符串(ES6中的Symbol也可以作为键名),所以不加引号也可以(会将其认为是字符串),所以上述声明对象的方式还可以写成这样:
var obj = {
'foo': 'Hello',
'bar': 'World'
};
当然如果键名不符合标识名的条件就必须加上引号:
//报错
var obj = {
1p: 'Hello World'
};
//不报错
var obj = {
'1p': 'Hello World',
'h w': 'Hello World',
'p+q': 'Hello World'
};
方法二:
利用new创建对象:
let obj = new Obj({ name:'arleen; age:18' })
对象的属性名又被称作属性(property),他的键值可以是任何数据类型,包括方法。对象的属性是可以动态创建的,不需要再创建对象的时候就指定。
关于对象的疑问
对象采用大括号表示,这导致了一个问题,如果行首是一个大括号,他到底是表示表达式(视为对象)还是语句(代码块):
{ foo: 123 }
JavaScript 引擎读到上面这行代码,会发现可能有两种含义。第一种可能是,这是一个表达式,表示一个包含foo
属性的对象;第二种可能是,这是一个语句,表示一个代码区块,里面有一个标签foo
,指向表达式123
。
为了避免这种歧义,JavaScript 引擎的做法是,如果遇到这种情况,无法确定是对象还是代码块,一律解释为代码块。
{ console.log(123) } // 123
上面的语句是一个代码块,而且只有解释为代码块,才能执行。
如果要解释为对象,最好在大括号前加上圆括号。因为圆括号的里面,只能是表达式,所以确保大括号只能解释为对象。
({ foo: 123 }) // 正确
({ console.log(123) }) // 报错
二、属性的操作
2.1属性的读取
- 读取一个属性
读取对象属性的方法有两种,一种是使用点运算符,一种是使用方括号运算符。
var obj = {
p: 'Hello World'
};
obj.p // "Hello World"
obj['p'] // "Hello World"
这里需要注意的是点运算符后面可以是标识符可以是字符串,但是[]方括号运算符里面的键名必须放在引号里面,否则会被当作变量来处理(会计算出变量的结果再将其转化为字符串);
var foo = 'bar';
var obj = {
foo: 1,
bar: 2
};
obj.foo // 1
obj[foo] // 2
- 读取对象的所有属性(Object.keys(obj) 不包括原型上的共有属性)
let obj = {
name:'lianghonglei',
age:18
}
console.log(Object.keys(obj))//
age:18
}
console.log(Object.keys(obj))//["name", "age"]
- 读取对象所有的值(Object.values(obj))
let obj = {
name:'lianghonglei',
age:18
}
console.log(Object.values(obj))//["lianghonglei", 18]
- 读取对象所有键值对(Object.entries(obj))
let obj = {
name:'lianghonglei',
age:18
}
console.log(Object.entries(obj))//[["name", "lianghonglei"], ["age", 18]]
- 读取对象的所有属性,包括_proto_
需要注意的是在读取对象上的属性的时候,如果对象本身上并不存在改属性,那么会顺着原型链去查找;但相反,在修改或增加对象的属性的时候,不会按着原型链查找,而是直接作用在对象本身上。
- 判断一个属性是对象自身属性还是原型上的共有属性
如果是对象本身的属性返回true,如果是原型上的属性返回false.
补充:'name' in obj和obj.hasOwnProperty('name') 的区别
in不能区分name是obj原型上的属性还是自身的属性,他只能查看obj是否存在改属性,但无法辨别,而hasOwnProperty只有在属性是obj自身上的时候才会返回true。
2.2 属性的赋值、修改和增加(写属性)
点运算符和方括号运算符不仅可以用来读取值,还可以用来赋值:
var obj = {}
obj.foo = 'hello';
obj['bar'] = 'world';
修改:
var obj = {
name:'lianghonglei',
age:18
}
obj.name = 'arleen';//修改姓名为arleen
obj['age'] = 20;//修改年龄为30
这里修改的都是obj本身的属性,但是如果我们想要修改obj原型(obj.__proto_)上的属性怎么办?
直接obj._proto_.toString = 'xxx'是可以的,但是我们不建议这么做,obj._proto_ 相当于 window.Object.prototype,所以我们可以借助后者去修改。但即使是这样,我们是不建议去修改原型上的共有属性的,因为这会引起很多问题。
可以这样做:
// 创建自己的原型(就可以不用去修改原来的原型了)Object.create
var common = {'国籍':'中国'}
var person = Object.create(common)
增加:
var obj = {
name:'lianghonglei',
age:18
}
obj.idol = 'tom hiddleston'; //添加属性idol
obj['reading'] = '白夜行'; // 添加属性reading
如果要批量赋值(一次赋值好多个属性)Object.assign(obj,{需要添加的成员们})
2.3 属性的删除
delete命令用域删除对象的属性(即属性名和属性值一并删除),删除成功之后返回true。
注意,删除一个不存在的属性,delete不会报错,且返回true。所以我们不能根据delete命令的返回结果去判定一个属性是不是存在。
var obj = {};
delete obj.p // true
只有一种情况,delete命令会返回false,那就是改属性存在且不能删除。
var obj = Object.defineProperty({}, 'p', {
value: 123,
configurable: false//设置为p属性不得修改
});
obj.p // 123
delete obj.p // false
另外,需要注意的是,delete
命令只能删除对象本身的属性,无法删除继承的属性
var obj = {};
delete obj.toString // true
obj.toString // function toString() { [native code] }
上面代码中,toString
是对象obj
继承的属性,虽然delete
命令返回true
,但该属性并没有被删除,依然存在。这个例子还说明,即使delete
返回true
,该属性依然可能读取到值。
2.4 属性是否存在
in
运算符用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回true
,否则返回false
。它的左边是一个字符串,表示属性名,右边是一个对象。
var obj = { p: 1 };
'p' in obj // true
'toString' in obj // true
in
运算符的一个问题是,它不能识别哪些属性是对象自身的,哪些属性是继承的。就像上面代码中,对象obj
本身并没有toString
属性,但是in
运算符会返回true
,因为这个属性是继承的。
这时,可以使用对象的hasOwnProperty
方法判断一下,是否为对象自身的属性。(上面已经提到过hasOwnProperty)
var obj = {};
if ('toString' in obj) {
console.log(obj.hasOwnProperty('toString')) // false
}
2.5 属性的遍历
for...in
循环用来遍历一个对象的全部属性。
var obj = {a: 1, b: 2, c: 3};
for (var i in obj) {
console.log('键名:', i);
console.log('键值:', obj[i]);
}
// 键名: a
// 键值: 1
// 键名: b
// 键值: 2
// 键名: c
// 键值: 3
for...in
循环有两个使用注意点。
- 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
- 它不仅遍历对象自身的属性,还遍历继承的属性。
举例来说,对象都继承了toString
属性,但是for...in
循环不会遍历到这个属性。
var obj = {};
// toString 属性是存在的
obj.toString // toString() { [native code] }
for (var p in obj) {
console.log(p);
} // 没有任何输出
上面代码中,对象obj
继承了toString
属性,该属性不会被for...in
循环遍历到,因为它默认是“不可遍历”的。关于对象属性的可遍历性,参见《标准库》章节中 Object 一章的介绍。
如果继承的属性是可遍历的,那么就会被for...in
循环遍历到。但是,一般情况下,都是只想遍历对象自身的属性,所以使用for...in
的时候,应该结合使用hasOwnProperty
方法,在循环内部判断一下,某个属性是否为对象自身的属性。
var person = { name: '老张' };
for (var key in person) {
if (person.hasOwnProperty(key)) {
console.log(key);
}
}
// name
posted on 2021-02-13 22:27 DreamOnTheGo 阅读(180) 评论(0) 编辑 收藏 举报