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编辑  收藏  举报