js对象

在前面,我们有介绍过,在JavaScript中,数据类型整体上来讲可以分为两大类:简单数据类型 和复杂数据类型。

简单数据类型一共有6种,分别是我们前面介绍过的

string , number , boolean , null , undefined 以及本章将会介绍的 symbol

而复杂数据类型就只有1种

object

也就是我们本章将会向大家所介绍的对象。事实上,我们前面已经遇到过一些对象了。例如之前 所介绍过的数组就是一种对象,不过它是JavaScript语言中内置的对象。在本章中我们将学习到 如何自定义对象,以及一些其他的内置对象。

本章将学习如下内容:

・创建对象的方式

・访问对象属性的方式

・对象常用的属性和方法

・对象的嵌套与解构

  • this关键字

・JSON对象

  • Math对象
  • Date对象

•正则表达式

6-1对象基础介绍

6-1-1 JS对象概述

JavaScript里面的对象就是一组键值对的集合。这些键一般由字符串构成,而值可以是任意数据 类型。比如字符串,数字,布尔,数组或者函数。一般来讲,如果一个键映射的是一个非函数的 值,我们将这个值称之为该对象的属性,而如果一个键映射的是一个函数的值,那么我们将其称 之为方法。

6-1-2创建对象

 

要创建一个对象,我们只需要输入一对大括号即可。这样我们就可以创建一个空的对象,如下:

let objName = {};

创建好对象以后,我们就可以给该对象添加相应的属性,例如这里我们给xiejie这个对象添加 相应的属性

let xiejie = {};

xiejie.name = "xiejie";

xiejie.age = 18;

xiejie.gender = "male";

xiejie.score = 100;

当然,和前面为大家介绍过的数组一样,我们可以在创建对象时就给对象添加好属性信息,如 下:

let xiejie = {

name : "xiejie",

age : 18,

gender : "male",

score : 100

};

可以看到,当我们创建包含属性的对象的时候,属性与属性之间是以逗号隔开的。这里我们可以 将属性名称之为键,属性对应的称之为值。所以,正如开头我们所介绍的那样,对象是由一个一 个键值对组成的。

6-1-3访问对象属性

访问对象的属性的方法有3种:点访问法,中括号访问法,symbol访问法

  1. 点访问法

我们可以通过一个点.来访问到对象的属性,如下:

let xiejie = {

name : "xiejie",

age : 18,

gender : "male",

score : 100

};

console.log(xiejie.name);//xiejie

console.log(xiejie.age);//18 console.log(xiejie.gender);//rnale

console.log(xiejie.score);//100

  1. 中括号访问法

第二种方法,是使用中括号法来访问对象的属性,如下:

let xiejie = {

name : "xiejie",

age : 18,

gender : "male",

score : 100

};

console.log(xiejie["name"]);//xiejie console.log(xiejie["age"]);//18

console.log(xiejie["gender"]);//male console.log(xiejie["score"]);//100

—般来讲,访问对象属性的时候使用点访问法的情况要多一些,那什么时候使用中括号访问方法 呢?当我们的属性名来自于变量的时候,这个时候中括号就要比点要灵活许多。来看下面的例 子:

let xiejie = {

name : "xiejie",

age : 18,

gender : "male",

score : 100

};

let str = "name"; console.log(xiejie[str]);//xiejie

既然讲到了对象属性的中括号访问法,那我们就顺带介绍一下伪数组对象的原理。前面给大家介 绍过的argument s就是一个伪数组对象。伪数组对象的原理就在于对象的键都是数字。如果属性 名是数字的话,通过中括号法来访问时可以不用添加引号,如下:

let obj = {

1 : "Bill",

2 : "Lucy",

3 : "David"

}

console.log(obj[1]);//Bill

console.log(obj[2]);//Lucy

console.log(obj[3]);//David

这样,就形成了给人感觉像是数组,但是并不是数组的伪数组对象。

  1. symbol访问法

在ES6之前,对象的属性名都只能是字符串。但是这样很容易造成属性名的冲突。比如我们使用 了一个别人提供的对象,然后我们想在这个对象的基础上进行一定的扩展,添加新的属性,这个 时候由于并不知道原来的对象里面包含哪些属性名,所以很容易就把别人的对象所具有的属性给 覆盖掉了。示例如下:

//假设person对象是从外部库引入的一个对象

let person = {

name : "xiejie"

}

console.log(person.name);//xiejie

person.name = "yajing"; console.log(person.name);//yajing

可以看到,这里两个name就产生了冲突,下面的name就把上面的name给覆盖掉了。

从ES6开始,新增了symbol这种数据类型,专门来解决这样的问题。创建symbol,需要使 Symbol。函数,其语法如下:

let sym = Symbol(描述信息);

示例:

let name = Symbol("这是一个名字");

console.log(name);//Symbol(这是一个名字) console.log(typeof name);//symbol

这里的描述信息是可选的,是对我们自己创建的symb。l的一个描述。接下来我们来用symb。l 为对象的属性,示例如下:

let person = {

name : "xiejie"

}

let name = Symbol("这是一个名字");

person[name] = "yajing";

console.log(person.name);//xiejie console.log(person[name]);//yajing

可以看到,使用symbol来作为对象的属性,避免了同名的属性名发生冲突。

有些时候我们希望在不同的代码中共享一个symbol,那么这个时候可以使用Symbol.for()方法 来创建一个共享的symbol。ES6提供了一个可以随时访问的全局symb。l注册表。当我们使 Symbol.for()方法注册一个symbo l的时候,系统会首先在全局表里面查找对应的参数的 symbol是否存在,如果存在,直接返回已经有的symbol,如果不存在,则在全局表里面创建一 个新的symbol

let obj = {};

let name = Symbol.for("test");

obj[name] = "xiejie";

let name2 = Symbol.for("test"); console.log(obj[name2]);//xiejie

如果使用Symbol.for()方法创建symbo l的时候没有传递任何参数,那么也会将undefined作为 全局表里面的键来进行注册,证明如下:

let obj = {};

let name = Symbol.for();

obj[name] = "xiejie";

let name2 = Symbol.for(undefined); console.log(obj[name2]);//xiejie

ES6里面还提供了 Symbol.keyFor()方法来查找一个symbo l的键是什么。但是需要注意的是, 该方法只能找到注册到全局表里面的symbol的键。如果是通过Symbol。方法创建的symbol, 无法找到的。这其实也很好理解,通过Symbol()方法创建的symbo l都不存在有键。

let obj = {};

let name1 = Symbol("test1");

let name2 = Symbol.for("test2");

let i = Symbol.keyFor(namel);

let j = Symbol.keyFor(name2);

console.log(i);//udnefined console.log(j);//test2

前面有提到,如果一个对象的属性对应的是一个函数,那么这个函数被称之为对象的方法。访问 对象方法的方式和上面介绍的访问对象属性的方式是一样的,可以通过点访问法,中括号访问法 以及symbo l访问法来进行对象方法的调用。

let walk = Symbol("this is a test"); let person = {

name : "xiejie", walk : function(){ console.log("I'm walking");

},

[walk] : function(){ console.log("I'm walking,too");

}

}

person.walk();//I'rn walking person["walk"]();//I'm walking person[walk]();//I'm walking,too

6-1-4删除对象属性

对象的任何属性都可以通过delete运算符来从对象中删除。示例如下:

let person = {

name : "xiejie",

age : 18,

walk : function(){

console.log("I'm walking");

}

}

console.log(person.age);//8

delete person.age;//删除age 这个属性

console.log(person.age);//undefined

person.walk();//I'm walking

delete person.walk; //删除walk方法 person.walk();//指错

//TypeError: person.walk is not a function

如果是删除的是属性,那么再次访问值为变为undefined,而如果删除的是方法,那么调用时会 直接报错

6-1-5对象常用属性和方法

1. in操作符

该操作符用于判断一个对象是否含有某一个属性,如果有返回true,没有返回false。需要注意的 是目前为止还无法判断对象的symb。l属性的包含情况,如果属性是symbol,那么会直接报错

let person = {

name : "xiejie",

age : 18,

walk : function(){

console.log("I'm walking");

}

}

let gender = Symbol("person's gender");

person[gender] = "male";

console.log("name" in person);//true console.log("age" in person);//true console.log([gender] in person);//灰错

//TypeError: Cannot convert a Symbol value to a string

但是需要注意,虽然上面给出了无法转换的错误,不过如果我们按照下面的方式来查看的话,是

会返回true的

let person = {

name : "xiejie",

age : 18,

walk : function(){

console.log("I'm walking");

}

}

let gender = Symbol("person's gender");

person[gender] = "male"; console.log("name" in person); // true console.log("age" in person); // true console.log(gender in person); // true

2. for..in

这个for..in我们在前面讲解遍历数组的时候已经见到过了。可以使用for..in来取出数组的键。除此 之外,我们还可以使用for..in来循环遍历一个对象的所有属性,示例如下:

let person = {

name : "xiejie",

age : 18,

walk : function(){

console.log("I'm walking");

}

}

for(let i in person){

console.log(i);

}

// name

// age

// walk

需要注意的是,使用for..in虽然说可以遍历出一个对象的所有的属性和方法(包括继承的,关于继 承后面会介绍),但是无法遍历出用symbol来定义的属性,证明如下:

let person = {

name : "xiejie",

age : 18,

walk : function(){

console.log("I'm walking");

}

}

let gender = Symbol("person's gender");

person[gender] = "male";

for(let i in person){

console.log(i);

}

// name

// age

// walk

那么,这个时候可能有人会问了,那我如何才能遍历出一个对象的s ymbo l属性呢?这里介绍两种 方式。

第一种是使用Object.getOwnPropertySymbols()来返回一^对象所有的symbo l属性,如下:

let person = {

name : "xiejie",

age : 18,

walk : function(){

console.log("I'm walking");

}

}

let gender = Symbol("person's gender");

person[gender] = "male";

console.log(Object.getOwnPropertySymbols(person));

//[ Symbol(person's gender)]

除了上面的方法以外,ES6中还提供了一个叫做Reflect.ownkeys()方法。该方法可以遍历出 —个对象的所有类型的键名,包括字符串的键名以及symbo l键名

let person = { name : "xiejie",

age : 18,

walk : function(){

console.log("I'm walking");

}

}

let gender = Symbol("person's gender"); person[gender] = "male";

console.log(Reflect.ownKeys(person));

//[ 'name', 'age', 'walk', Symbol(person's gender)]

3. keys。,values。,entries

前面在介绍遍历数组,集合以及映射的时候,有介绍过这3个方法,分别用于找出可迭代对象的 键,值,以及键和值。实际上,我们的对象也是属于可迭代对象的一种,所以也可以使用这3 方法来找出对象的键和值

Object.keyO

let person = {

name : "xiejie",

age : 18,

walk : function(){

console.log("I'm walking");

}

}

let gender = Symbol("person's gender"); person[gender] = "male";

for(let i of Object.keys(person)){

console.log(i);

}

// name

// age

// walk

Object.valuesO

let person = { name : "xiejie", age : 18,

walk : function(){

console.log("I'm walking");

}

let gender = Symbol("person's gender"); person[gender] = "male";

for(let i of Object.values(person)){ console.log(i);

}

// xiejie

// 18

// [Function: walk]

Object.entriesO

let person = { name : "xiejie", age : 18,

walk : function(){

console.log("I'm walking");

}

}

let gender = Symbol("person's gender"); person[gender] = "male";

for(let i of Object.entries(person)){ console.log(i);

}

// [ 'name', 'xiejie' ]

// [ 'age', 18 ]

// [ 'walk', [Function: walk] ]

6-1-6嵌套对象

—个对象里面可以包含其他的对象,这个我们称之为对象的嵌套。示例如下:

let family = { xiejie : {

age : 18,

gender : "male"

},

song : {

age : 20,

gender : "female"

}

};

当我们访问嵌套对象里面的值的时候,和访问单个对象的方式是一样的。

 

let family = {

xiejie : {

age : 18, gender : "male"

},

song : {

age : 20, gender : "female"

}

};

console.log(family.xiejie.gender);//male 点访问法 console.log(family["song"]["age"]);//20 中括号访问法

对象的解构

在前面介绍解构的时候,我们有介绍过数组的解构。实际上对象我们也是可以将其解构的。解构 的方式也是和解构数组是类似的,示例如下:

let a = {name:"xiejie",age:18};

let b = {name:"song",age:20};

let {name:aName,age:aAge} = a; let {name:bName,age:bAge} = b; console.log(aName);//xiejie console.log(aAge);//18 console.log(bName);//song console.log(bAge);//20

当属性名和变量名一致的时候,可以进行简写,示例如下:

let a = {name:"xiejie",age:18};

let {name,age} = a;

console.log(name);//xiejie console.log(age);//18

和数组一样,同样可以解构嵌套的对象,如下:

let family = { xiejie : {

age : 18, gender : "male"

},

song : {

age : 20,

gender : "female"

}

};

let {xiejie,song} = family;

console.log(xiejie);//f age: 18, gender: 'male' } console.log(song);//f age: 20, gender: 'female' }

顺便一提的是,解构我们也是可以像函数一样设置一个默认值的,这里一起来看一下,如下:

let {name="xiejie",age} = {}; console.log(name);//xiejie console.log(age);//undefined

这里我们为name变量设置了一个默认值为xiejie,当我们解构一个空对象的时候,name变量的值 就使用了默认的xiejie这个值,而age这个变量由于没有设置默认值,所以值为undefined。

当然,既然叫做默认值,和函数一样,如果有解构的值传过来的话,肯定就是使用解构传过来的 值,如下:

let {name="xiejie",age} = {name:"song",age:10}; console.log(name);//song console.log(age);//10

6-1-7对象作为函数参数

对象字面量也可以作为函数的参数进行传递。这在有很多形式参数的时候非常有用,因为它允许 我们在调用函数时不用记住参数的顺序。

我们先来看一下我们一般函数调用的例子,如下:

let test = function(name,age){

console.log('我叫${name},我今年${age}');

}

test("xiejie", 18);//我叫xiejie,我今年 18 test(18,"xiejie");//我叫 18,我今年xiejie

可以看到,以前我们调用函数传递参数时,参数的顺序是必须要和形式参数的顺序一致的。否则 就会出现上面第2次调用函数的情况,输出不符合预期的结果。

当我们使用对象字面量来最为形式参数时,就可以不用按照定义函数时形式参数的顺序,只要名 字相同即可,如下:

 

let test = function({name,age}){

console.log('我叫${name},我今年${age}');

}

test({name:"xiejie",age:18});我今年 18  test({age:18,name:"xiejie"});//^^AXiejie,我今年 18

可以看到,只要参数名能对上号,位置是可以随意放置的。

和前面介绍函数的参数默认值一样,当对象字面量作为参数的时候,我们也可以为字面量的每一 项设置一个默认值,甚至我们还可以给整个对象字面量一个默认值,示例如下:

//给整个对象字面量一个默认值{ name:"BilT,age:20}

let test = function({name = "xiejie",age = 18} = {name:"Bill",age:20}){ console.log('我叫${name},我今年${age}');

}

test();//我叫Bill,我今年20

test({});//我叫xiejie,我今年 18 test({name:"yajing"});//我〃V/ajing,我今年 18  test({age:1,name:"xizhi"});//我〃AXizhi,我今年 1

这种技术被称之为命名参数,经常被用在函数有很多可选参数的时候。

6-1-8 this关键字

既然学习到了对象,那么有必要介绍一下this关键字。this ,翻译成中文就是这个的意思。 当我们在一个对象中使用this关键字时,该关键字就代表的是当前对象。来看下面的例子:

let person = {

name : 'xiejie',

age : 18,

intro : function(){

console.log(this);

// { name: 'xiejie', age: 18, intro: [Function: intro] } console.log('My name is ${this.name},I'm ${this.age} years old'); // My name is xiejie,I'm 18 years old

}

}

person.intro();

这里我们调用了 person对象的intro方法,里面涉及到了 this关键字。由于是在对象里面,所 this指向当前对象,也就是person这个对象。所以this.name等价

person.name , this.age 等价于 person.age。

6-1-9命名空间(扩展)

当相同的变量和函数名被共享在同一作用域的时候,就会发生命名冲突。这看起来不太可能,但 是我们可以想象一下,随着时间的推移,我们已经写了很多的代码,可能不知不觉就重用了一个 变量名。如果是使用的其他开发者的代码库,这种问题就变得更加有可能。

解决命名冲突的方式,就是使用对象字面量来为一组相关函数创建一个命名空间。这样在调用这 些函数的时候需要先写上对象名,这里的对象名就充当了命名空间的角色。示例如下:

let myMaths = {

//求平方函数

square : function(x){

return x * x;

},

//传入数组求平均值函数

avg : function(arr){

let total = arr.reduce((a,b) => a + b);

return total / arr.length;

}

}

let arr = [1,2,3,4,5];

console.log(myMaths.avg(arr));//3

console.log(myMaths.square(5));//25

这里我们的myMaths就是我们的命名空间,这样就不用担心和其他人的变量或者函数名发生命 名冲突。

posted on 2019-08-23 15:58  dazhongma233  阅读(177)  评论(0编辑  收藏  举报