2021-05-28JS 对象(一)基本概念及拷贝

对象

创建

在这里插入代码let user = new Object(); // “构造函数” 的语法
let user = {};  // “字面量” 的语法片
let user = {     // 一个对象
  name: "John",  // 键 "name",值 "John"
  age: 30        // 键 "age",值 30
  // 读取文件的属性:
alert( user.name ); // John
alert( user.age ); // 30

删除
delete user.age;

可以用多字词语来作为属性名
let user = {
  name: "John",
  age: 30,
  "likes birds": true  // 多词属性名必须加引号
};
对于多词属性,点操作就不能用了:
// 这将提示有语法错误
user.likes birds = true
};

使用 const 声明的对象是可以被修改的

const user = {
  name: "John"
};

user.name = "Pete"; // (*)

alert(user.name); // Pete
仅当我们尝试将 user=... 作为一个整体进行赋值时,const 会抛出错误。

点符号要求 key 是有效的变量标识符。这意味着:不包含空格,不以数字开头,也不包含特殊字符(允许使用 $ 和 _)。
使用方括号,可用于任何字符串,可以通过任意表达式来获取属性名的方法:

let user = {};

// 设置
user["likes birds"] = true;

// 读取
alert(user["likes birds"]); // true

// 删除
delete user["likes birds"];

当创建一个对象时,我们可以在对象字面量中使用方括号。这叫做 计算属性

let fruit = prompt("Which fruit to buy?", "apple");

let bag = {
  [fruit]: 5, // 属性名是从 fruit 变量中得到的
};

alert( bag.apple ); // 5 如果 fruit="apple"
计算属性的含义很简单:[fruit] 含义是属性名应该从 fruit 变量中获取。

所以,如果一个用户输入 "apple",bag 将变为 {apple: 5}

属性名简写

function makeUser(name, age) {
  return {
    name, // 与 name: name 相同
    age,  // 与 age: age 相同
    // ...
  };
}

属性名可以是任何字符串或者 symbol(一种特殊的标志符类型,将在后面介绍)。
其他类型会被自动地转换为字符串。
例如,当数字 0 被用作对象的属性的键时,会被转换为字符串 “0”:

属性存在性测试,“in” 操作符

例如:

let user = { name: "John", age: 30 };

alert( "age" in user ); // true,user.age 存在
alert( "blabla" in user ); // false,user.blabla 不存在。

遍历对象所有键

for (key in object) {
  // 对此对象属性中的每个键执行的代码
}
let user = {
  name: "John",
  age: 30,
  isAdmin: true
};

for (let key in user) {
  // keys
  alert( key );  // name, age, isAdmin
  // 属性键的值
  alert( user[key] ); // John, 30, true
}

引用和复制

let user = { name: 'John' };

let admin = user;

admin.name = 'Pete'; // 通过 "admin" 引用来修改

alert(user.name); // 'Pete',修改能通过 "user" 引用看到

比较

当两个对象为同一对象时,两者才相等。

克隆与合并,Object.assign

复制新建一个独立的对象

方法一

let user = {
  name: "John",
  age: 30
};

let clone = {}; // 新的空对象

// 将 user 中所有的属性拷贝到其中
for (let key in user) {
  clone[key] = user[key];
}

// 现在 clone 是带有相同内容的完全独立的对象
clone.name = "Pete"; // 改变了其中的数据

alert( user.name ); // 原来的对象中的 name 属性依然是 John

方法二
Object.assign(dest, [src1, src2, src3…])
第一个参数 dest 是指目标对象。
更后面的参数 src1, …, srcN(可按需传递多个参数)是源对象。
该方法将所有源对象的属性拷贝到目标对象 dest 中。换句话说,从第二个开始的所有参数的属性都被拷贝到第一个参数的对象中。
调用结果返回 dest。

例如

合并多个对象
let user = { name: "John" };

let permissions1 = { canView: true };
let permissions2 = { canEdit: true };

// 将 permissions1 和 permissions2 中的所有属性都拷贝到 user 中
Object.assign(user, permissions1, permissions2);

// 现在 user = { name: "John", canView: true, canEdit: true }

如果被拷贝的属性的属性名已经存在,那么它会被覆盖:

let user = { name: "John" };

Object.assign(user, { name: "Pete" });

alert(user.name); // 现在 user = { name: "Pete" }

深层克隆

当对象属性是对其他对象的引用,使用拷贝 clone.sizes = user.sizes 已经不足够了,拷贝的仍然是引用对象的地址

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

alert( user.sizes.height ); // 182

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

let clone = Object.assign({}, user);

alert( user.sizes === clone.sizes ); // true,同一个对象

// user 和 clone 分享同一个 sizes
user.sizes.width++;       // 通过其中一个改变属性值
alert(clone.sizes.width); // 51,能从另外一个看到变更的结果



为了解决此问题,我们应该使用会检查每个 user[key] 的值的克隆循环,如果值是一个对象,那么也要复制它的结构。这就叫“深拷贝”。

对象通过引用被赋值和拷贝。换句话说,一个变量存储的不是“对象的值”,而是一个对值的“引用”(内存地址)。因此,拷贝此类变量或将其作为函数参数传递时,所拷贝的是引用,而不是对象本身。

所有通过被拷贝的引用的操作(如添加、删除属性)都作用在同一个对象上。

为了创建“真正的拷贝”(一个克隆),我们可以使用 Object.assign 来做所谓的“浅拷贝”(嵌套对象被通过引用进行拷贝)或者使用“深拷贝”函数,例如 _.cloneDeep(obj)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值