JS【详解】对象(含对象的存储原理,对象的 getter 和 setter,对象的常用操作,判断对象是否为空对象,对象的深拷贝,五种创建对象的方法、遍历、合并、拷贝等)

简介

任何事物都可以看作一个对象,用属性描述它的特征,用方法描述它的行为,如下方代码所示:

let obj = {
  name: "朝阳",
  sayHi: function () {
    console.log("你好!");
  },
};
typeOf obj  // object

变量 obj 被赋值了一个对象,它有属性 name,属性值为 朝阳,方法为 sayHi,具有在控制台打印 你好! 的行为。

对象的储存原理

对象的值保存在堆内存中,变量 obj 内存储的是对象的引用(对象在堆内存中存储的地址)

对象的内部属性和内部方法
https://blog.csdn.net/weixin_41192489/article/details/141022779

对象的 getter 和 setter

https://blog.csdn.net/weixin_43845090/article/details/117563999

常用的对象操作

创建对象

1. 通过对象字面量创建【常用】

原型链为: Object.prototype 》 对象

// 创建空对象:自身无任何属性和方法的对象 (因空对象继承自 Object ,所以还具有一些继承来的方法和属性)
let obj1 = {};

// 创建自带属性和方法的对象
let obj2 = {
  // 属性
  name: "朝阳",
  //   方法
  sayHi: function () {
    console.log("你好!");
  },
};

ES6 的简写方式

  • 对象名和属性名相同时,name:name 可简写为 name
  • 方法的 :function 可省略不写
let name = "朝阳";
let obj2 = {
  name,
  sayHi() {
    console.log("你好!");
  },
};

ES6 开始支持动态属性和方法
即用变量作为对象的属性和方法名

let type = "book";
let obj = {
  [type + "Name"]: "《朝阳传》",
  [type + "Sale"]: function () {
    console.log("免费领取啦!");
  },
};

2. 通过构造函数创建 new

  • 通过内置的构造器函数创建

原型链为: Object.prototype 》 对象

// Object 是 JS 内置的构造函数,若无参数,则创建一个空对象,效果同 {}
let obj = new Object(); 

new Object() 可以传入参数,‌参数可以是任何类型,‌如字符串、‌数字、‌对象等。‌当传入不同类型的参数时,‌Object() 构造函数会根据参数的类型返回相应的基本包装类型的实例(‌如 String、‌Number 等)‌。

  • 通过自定义的构造函数创建

原型链为: Object.prototype 》 构造函数.prototype 》 对象

function Person(name) {
  // 用 new 创建对象时,此处的 this 指向新创建的对象实例
  this.name = name;
}

let me = new Person("朝阳");
console.log(me.name); // 控制台打印  "朝阳"

通过构造器函数创建对象的好处:可以用同一个构造器创建不同的对象实例

3. 通过 Object.create() 创建

以一个现有对象作为原型,创建一个新对象

原型链为: 现有对象的原型 》 现有对象 》 新对象

其底层实现为

Object.create = function create(proto) {
    function F(){}
    F.prototype = proto
    return new F()
}

Object.create() 的第一个参数为原型,第二个参数(可选)为属性对象,使用方法如下:

原型链:null 》新对象

let newObj1 = Object.create(null) // 以 null 为原型创建对象, 该对象无任何属性,不会继承Object的任何东西
Object.getPrototypeOf(newObj1)  // 结果为 null
newObj1.__proto__ // 因无任何属性,所以值为 undefined

原型链:Object.prototype 》新对象

Object.create(Object.prototype) // 以 Object.prototype 为原型创建对象, 与用字面量 {} 创建对象,效果相同

原型链:Object.prototype 》{} 》新对象

Object.create({}) // 以 {} 为原型创建对象

原型链:Object.prototype 》Person.prototype 》p1 》新对象

function Person(name) {
  this.name = name;
}

let p1 = new Person("朝阳");

let newObj3 = Object.create(p1);

第二个参数的使用范例:

let newObj4 = Object.create(Object.prototype, {
  name: {
    writable: true,
    value: "朝阳",
  },
  age: {
    writable: true,
    value: 35,
  },
});

其效果与字面量创建对象类似

let newObj4 = {
	name:"朝阳",
	age:35
}

4. 通过类创建

原型链为: Object.prototype 》 类.prototype 》 对象
(类的本质上构造函数)

class Car {
  constructor(model, year) {
    this.model = model;
    this.year = year;
  }
}
const fiesta = new Car('Fiesta', '2010');

5. 通过工厂函数创建

原型链为: 由工厂函数返回的对象决定

function fac(name){
	return { name:name }
}

fac('朝阳')

访问属性

// 属性为字符串时,用 . 
obj.name // 得到属性值 '朝阳'

let type = 'hobby'
// 属性为变量时,用 []
obj[type]
  • 访问对象中不存在的属性,返回 undefined

在对象的方法内部访问该对象的属性,可以使用this,此时 this 就是当前对象。

let me = {
  name: '朝阳',
  sayName: function() {
    return this.name;
  }
};

获取对象所有的属性 Object.keys()

let obj = {
    a: 1,
    b: 2
}let keys = Object.keys(obj) // ['a', 'b']

获取对象所有的属性值 Object.values()

let obj = {
    a: 1,
    b: 2
}let values = Object.values(obj) // [1, 2]

添加属性

// 属性为字符串时,用 . 
obj.age = 35

let type = 'hobby'
// 属性为变量时,用 []
obj[type] = '编程'

删除属性

// 属性为字符串时,用 . 
delete obj.age

let type = 'hobby'
// 属性为变量时,用 []
delete obj[type]

遍历对象 for in

for (let key in obj) {
    console.log("属性名:" + key );
    console.log("属性值:" + obj[key ]);
}

合并对象 Object.assign

let a = { gender: "male"}
Object.assign(a, { age: 25 })
console.log(a)  // {"age":25, "gender":"male"}
  • 第一个参数是发起合并的对象
  • 之后的参数是被合并的对象
  • 可以一次合并多个对象
let obj = { a: 1 };
Object.assign(obj, { b: 2 }, { c: 3 });
console.log(obj); // { a: 1, b: 2, c: 3 }
  • Object.assign() 的返回值为合并后的对象
  • Object.assign() 有副作用(会改变原对象)

拷贝对象

浅拷贝

let obj1 = {num:1}
let obj2 = obj1

此时变量 obj2 内存的是对象 {num:1} 的地址,变量 obj1 内存的也是对象 {num:1} 的地址,当变量改变时,obj1 和 obj2 都会改变。

深拷贝
为了避免变量后期改变时,对拷贝后的对象产生影响,经常需要进行深拷贝。

// 简易深拷贝 -- 存在缺陷,但对大部分简单的对象适用
let obj2 = JSON.parse(JSON.stringify(obj1));

更多深拷贝的方法见
https://blog.csdn.net/weixin_41192489/article/details/119633624

【实战】判断变量是否为空对象

if(JSON.stringify(obj)==="{}"){
  // 是空对象
}

【实战】对比对象的差异

推荐使用 js 库 jiff
https://github.com/cujojs/iiff

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朝阳39

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>