对象

let user = {
  name: "John",
  age: 30,
  "likes birds": true  // 多词属性名必须加引号,
  
};
//----------------
let user = {
  name: "John",
  age: 30
};

let key = prompt("What do you want to know about the user?", "name");

// 获取变量
alert( user[key] ); // John (如果输入 "name" )
1.保留字段可以用作属性名

变量名不能用保留字段,像:“for”, “let”, “return” 等。

对于对象的属性,没有这些限制,都可以的:

 let obj = {
  for: 1,
  let: 2,
  return: 3
}

alert( obj.for + obj.let + obj.return );  // 6

基本上,什么都可以,只有一个特殊的:"__proto__" 因为历史原因要特别对待。比如,我们不能把它设置为非对象的值:

 let obj = {
  for: 1,
  let: 2,
  return: 3
}

alert( obj.for + obj.let + obj.return );  // 6

我们从代码中可以看出来,把它赋值成 5 被忽略了。

如果我们蓄意去存储随机的键值对或者允许一个访问者去指定键,那可能就会产生很多 bug 并且使对象变得危险。

比如,访问者可能选择 “proto” 作为键,这个赋值的逻辑就失败了(像上面那样)。

2.存在值检查

对象的一个显著的特点就是可以访问任何属性,如果这个属性名没有值也不会有错误。访问一个不存在的属性会返回undefined。它提供一种普遍的方法去检查属性是否存在 —— 获得值来与 undefined 比较:

 
let user = {};

alert( user.noSuchProperty === undefined ); // true 意思是没有这个属性

同样也有一个特别的操作符 "in" 来检查是否属性存在。

语法是:

"key" in object
  
//----------------------------------------
let user = { name: "John", age: 30 };
alert( "age" in user ); // true,user.age 存在
alert( "blabla" in user ); // false,user.blabla 不存在。
//-------------------------------------
let user = { age: 30 };
let key = "age";
alert( key in user ); // true,获取键的名字和检查这个键的属性

3.“for…in” 循环

for(key in object) {
  // 各个属性键值的执行区
}
例如,我们列出 user 所有的属性值:

 
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
}

4.像对象一样排序

5.引用复制

6.对象都是按引用存储复制的

   变量存储的不是对象本身,而是对象的“内存地址”,是对象的引用。

   当对象被复制的时候 – 引用被复制了一份, 对象并没有被复制。

7.常量对象

一个被 const 修饰的对象可以被修改

8.复制和合并,Object.assign

复制一个对象的变量也等同于创建了此对象的另一个引用。

那么我们该怎么复制一个对象呢?创建一份独立的拷贝,一份复制?

这也是可行的,但是有一点麻烦,因为JS并没有原生的方法支持这么做。实际上,我们很少这么做。复制引用很多时候是好用的。

如果我们真的想这么做,就需要创建一个新的对象,遍历现有对象的属性,在原始值的状态下复制给新的对象

像这样:

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

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

// 复制所有的属性值
for (let key in user) {
  clone[key] = user[key];
}

// 现在复制是独立的复制了
clone.name = "Pete"; // 改变它的值

alert( user.name ); // 原对象属性值不变

我们也可以用Object.assign 来实现。

语法是:

Object.assign(dest[, src1, src2, src3...])

例如,我们可以用这个方法来把几个对象合并成一个:

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 }
如果接收的对象(user)已经有了同样属性名的属性,前面的会被覆盖:

let user = { name: "John" };

// 覆盖 name,增加 isAdmin
Object.assign(user, { name: "Pete", isAdmin: true });

// 现在 user = { name: "Pete", isAdmin: true }

它复制了 user 对象所有的属性给了一个空对象,然后返回拷贝后的对象。事实上,这跟循环赋值一样,但是更短。

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

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

如果对象属性指向对象

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

alert( user.sizes.height ); // 182
//现在,并不能拷贝 clone.sizes = user.sizes,因为 user.sizes 是一个对象,它按引用拷贝。所以 clone 和 user 共享了一个对象。

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,在这里查看属性的值

总结

对象是具有一些特殊特性的关联数组。

他们存储键值对:

  • 属性的键必须是字符串或者符号(通常是字符串)。
  • 值可以是任何类型。

我们可以用下面的方法获取属性:

  • 点符号: obj.property
  • 方括号 obj["property"],方括号中可以使用变量 obj[varWithKey]

其他操作:

  • 删除属性:delete obj.prop
  • 检查属性是否存在:"key" in obj
  • 遍历对象:for(let key in obj) 循环。

对象根据引用来赋值或者复制。换句话说,变量存的不是对象的"值",而是值的 “引用”(内存地址)。 所以复制变量或者传递变量到方法中只是复制了对象的引用。 所有的引用操作(像增加,删除属性)都作用于同一个对象。

深拷贝的话我们可以使用 Object.assign 或者 _.cloneDeep(obj)

 

  

  

  



posted @ 2019-08-08 14:47  C_XingM  阅读(118)  评论(0)    收藏  举报