Object

简介:在JavaScript中,我们使用最多的就是对象,但我们很少自定义一个对象去使用,更多的是使用构造函数(函数章节讲解)来new一个对象,其实我们在不知不觉中一直在使用对象,JS中大部分类型都是对象如 String/Number/Math/RegExp/Date 等等。

下面通过代码说明下:

  //下面两种方式定义字符串是等价的
  let st = '字符串';
  //但下面这种通过构造函数,更能说明str是对象
  let str = new String('字符串');

  //再比如Number类型
  let nu = 1;
  let num = new Number(1);

其他类型类似不再代码说明。

创建(声明)对象

两种声明方式,一种是构造函数形式,一种是对象字面量。

  //new Object构造函数方式
  let person = new Object();//与let person = {};相同
  person.name = 'Tom';
  person.age = 20;
  //对象字面量
  let person = {
    name:'Tom',
    age:20
  }

两种声明对象的方式,我们一般都会使用对象字面量表示法。

操作属性

操作属性也有两种方式,点语法和中括号,特别注意使用中括号操作属性,中括号里面必须是字符串形式。

  let person = {
    name: 'Tom',
    age: 20
  }
  console.log(person.name);//点语法
  console.log(person['name']);//中括号形式,必须是字符串

其实我们习惯使用点语法,但有时候无法使用点语法,比如属性名中有空格“first name”,我们就要使用功能更加强大的中括号形式:

  let people = {
    'first name': 'Tom',
    age: 20
  }
  console.log(people['first name']);

使用中括号的主要优势是可以通过变量访问属性:

  let name = 'first name';
  let people = {
    'first name': 'Tom',
    age: 20
  }
  console.log(people[name]);

其实中括号里面可以是字符串,表达式,甚至是函数:

  function nameStr() {
    return 'first name';
  }
  let people = {
    'first name': 'Tom',
    age: 20
  }
  console.log('表达式:' + people['first ' + 'name']);
  console.log('函数:' + people[nameStr()]);

总结:使用.点语法操作属性更简洁,[]中括号主要用于通过变量定义属性的场景

添加属性

let people = {
  name: 'Tom'
}
people.age = 20;
console.log(people);//{name: "Tom", age: 20}

删除属性delete

let people = {
  name: 'Tom',
  age: 20
}
console.log(people);//{name: "Tom", age: 20}
delete people.age;
console.log(people);//{name: "Tom"}

检测属性

hasOwnProperty检测对象自身是否包含指定的属性,不检测原型链上继承的属性。

let people = {
  name: 'Tom',
  age: 20
}
console.log(people.hasOwnProperty('name'));
console.log(Object.hasOwnProperty.call(people, 'name'));

使用 in 可以在原型对象上检测(原型会在下面详细讲解,这里有疑问先不要着急)

先来看下people的原型:

let person = {
  age: 20
}
console.dir(person);
console.log('toString' in person);//toString是原型对象上的属性

获取属性名

使用 Object.getOwnPropertyNames()和Object.keys()可以获取对象的属性名集合

let person = {
  name: 'Tom',
  age: 20
}
console.log(Object.getOwnPropertyNames(person));//["name", "age"]
console.log(Object.keys(person));//["name", "age"]

简写

推荐简写方式:

  let name = 'first name';
  //属性名和对应值变量名称相同可简写为:
  let people = {
    name,//正常应写为:name:name
    age:20
  }
  //对象中的方法简写:
  let person = {
    name:'Tom',
    run(){//正常应写为:run:function(){}
      console.log('跑步');
    }
  }

this

this主要出现在对象和构造函数中,比如:

//this在对象中的体现
let person = {
  name: 'Tom',
  sayName() {
    console.log(this.name);
  }
}
person.sayName();

//this在构造函数中的体现
function Person(name) {
  this.name = name;
  this.sayName = function () {
    console.log(this.name);
  }
}
let per = new Person('Jerry');
per.sayName();

合并对象

Object.assign()

let dest = { a: 'age' };
Object.assign(dest, { b: 'bar' }, { c: 'car' });
console.log(dest);//{a: "age", b: "bar", c: "car"}

展开语法

let bc = { b: 'bar', c: 'car' };
let dest = { a: 'age', ...bc };
console.log(dest);//{a: "age", b: "bar", c: "car"}

对象解构赋值

对象解构就是使用与对象匹配的结构来实现对象属性的赋值。

简单使用

let person = {
  name: 'Tom',
  age: 20
}
let { name: personName, age: personAge } = person;
console.log(personName);//Tom
console.log(personAge);//20

复杂使用

let person = {
  name: 'Tom',
  age: 20,
  hand: {
    left: 'left',
    right: 'right'
  }
}
//1.简写,直接使用属性名作为变量名
let { name, age } = person;
console.log(name, age);//Tom 20
//2.不完全解构,有时候我们只需要对象的部分属性值
let { name: pName } = person;
console.log(pName);//Tom
//3.默认值,如果属性不存在则该变量值为undefined,但可以赋默认值,记住一定要用等号=,不是冒号:
let { job = 'engineer' } = person;
console.log(job);//engineer
//4.嵌套解构
let { hand: { right } } = person;
console.log(right);//right

函数解构传参

数组参数和对象参数

//数组参数,默认值c=3
function arr([a, b, c = 3]) {
  console.log(a, b, c);//1 2 3
}
arr([1, 2]);
//对象参数,默认值title = '对象参数'
function person({ name, age, title = '对象参数' }) {
  console.log(name, age, title);//'Tom' 20 '对象参数'
}
person({ name: 'Tom', 'age': 20 });

对象浅拷贝与深拷贝

对象的浅拷贝,深拷贝是与引用类型相关联的。

浅拷贝

子对象和父对象,引用类型属性指向同一块内存地址,即浅拷贝。改变子对象引用类型属性值,也会影响父对象。

let person = {
  name: 'Tom',
  age: 20,
  memo: {
    title: '拷贝'
  },
  data: [1, 2]
}
let copyObj = {};
//1.遍历方式:只遍历一层
for (const key in person) {
  copyObj[key] = person[key];
}
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2]}
copyObj.memo.title = 'copy';
//修改copyObj中的引用属性值,person也会发生修改
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"copy"},"data":[1,2]}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"copy"},"data":[1,2]}
//2.Object.assign()混入
Object.assign(copyObj, person);
copyObj.memo.title = '复制';
//修改copyObj中的引用属性值,person也会发生修改
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"复制"},"data":[1,2]}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"复制"},"data":[1,2]}
//3.展开语法(点语法)
copyObj = { ...person };
copyObj.memo.title = '展开语法复制';
//修改copyObj中的引用属性值,person也会发生修改
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"展开语法复制"},"data":[1,2]}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"展开语法复制"},"data":[1,2]}

深拷贝

let person = {
  name: 'Tom',
  age: 20,
  memo: {
    title: '拷贝'
  },
  data: [1, 2],
  run() {
    console.log('run')
  }
}
let copyObj = {};
//1.JSON序列化反序列化
copyObj = JSON.parse(JSON.stringify(person));
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2]}
copyObj.memo.title = 'copy';
//修改copyObj中的引用属性值,person不会修改,但我们也发现了一个问题,run函数属性丢失了
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"copy"},"data":[1,2]}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2],run(){}}
//2.递归
function copyFun(obj) {
  let copyObj = obj instanceof Array ? [] : {};
  for (const [k, v] of Object.entries(obj)) {
    copyObj[k] = typeof v === 'object' ? copyFun(v) : v;
  }
  return copyObj;
}
copyObj = copyFun(person);
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2],run(){}}
copyObj.memo.title = 'copy';
//修改copyObj中的引用属性值,person不会修改,而且run函数属性也还在。
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"copy"},"data":[1,2],run(){}}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2],run(){}}

属性的类型

1.数据属性特征

属性包括以下四种特性

特性说明默认值
configurable能否使用delete、能否需改属性特性、或能否修改访问器属性true
enumerable对象属性是否可通过for-in循环,或Object.keys() 读取true
writable对象属性是否可修改true
value对象属性的默认值undefined

设置特征Object.defineProperty()

接收3个参数,对象,属性,属性特征对象。

let person = {};
Object.defineProperty(person, "name", {
  value: 'Tom',
  Configurable: true,
  Enumerable: true,
  Writable: true
});
console.log(person);//{name: "Tom"}

查看属性特征

console.log(Object.getOwnPropertyDescriptor(person, "name"));

2.访问器属性

特性说明默认值
configurable能否使用delete、能否需改属性特性、或能否修改访问器属性true
enumerable对象属性是否可通过for-in循环,或Object.keys() 读取true
get获取函数,在读取属性时调用。undefined
set设置函数,在写入属性时调用。undefined
let person = {
  age_: 20
};
Object.defineProperty(person, "age", {
  configurable: true,
  enumerable: true,
  get() {
    return this.age_;
  },
  set(newValue) {
    if (newValue > 130) {
      throw new Error('年龄设置不合法');
    }
    this.age_ = newValue;
  }
});
person.age = 100;
console.log(person.age);

总结:

本章讲解了对象的基础知识,在下面的Vue章节中,会结合JavaScript基础,并讲解高级应用。

 

 

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐