【JavaScript入门笔记04 Object对象Ⅰ】

笔记参考javascript.info中文站

对象简介

对象(Object)是 Javascript 中最重要的一种数据类型

我们可以用花括号 {} 来创建一个对象,其中包括对象的元素,每个元素又包括一个键 “key”(字符串)和一个值 “value”(任何类型)

我们可以用下面两种语法中的任一种来创建一个空的对象:

let user = new Object(); // “构造函数” 的语法
let user = {};  // “字面量” 的语法,更常用

1. 基本操作

创建对象: 创建新对象的时候就可以进行初始化,将一系列键值对录入对象中,每一对键值最后需要加一个 “,”

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

增删改查: 使用点符号访问属性, delete 是删除的关键词,其余三种操作点符号直接进行即可

user.isAdmin = true;
delete user.age;	// 删
alert( user.name ); // 查
user.sex = "woman"	// 增
user.name = "Ann"	// 改

方括号: 当键的字符串中含有空格时,需要方括号将其括起来在进行点符号操作,内部使用

let user = {};

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

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

此外,方括号中的字符串也可以用变量代替,这样更灵活,但也更麻烦

所以,当属性名是已知且简单的时候,就使用点符号。如果我们需要一些更复杂的内容,那么就用方括号。

2. 属性名称

在开发过程中,会经常遇到属性名跟变量名一样的情况,例如:

function makeUser(name, age) {
  return {
    name: name,
    age: age,
    // ……其他的属性
  };
}

在这种情况下,我们可以简写属性名:

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

除此之外,属性名还有一个特点:没有任何限制
保留字也可以使用,数字也可以使用,因为他们都会默认转化成字符串

3. “in” 操作符

操作符 “in” 可以让我们检查所有属性,即使不存在也没关系,会返回 undefined()

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

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

4. “for…in” 循环

为了遍历一个对象的所有键(key),可以使用一个特殊形式的循环:for..in

举个例子:

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 codes = {
  "49": "Germany",
  "41": "Switzerland",
  "44": "Great Britain",
  // ..,
  "1": "USA"
};

for(let code in codes) {
  alert(code); // 1, 41, 44, 49
}



对象引用和复制

1. 对象复制的特点

普通数据类型的复制都是直接将数据本身复制一份到新的变量中,而对象不同,他复制的是对象的 “引用” ,也就是对象所在的 “地址”,而不是对象本身的内容。

因此普通数据复制后修改新变量并不会影响原有变量的值,但对象所依附的新变量和就变量事实上所指的是同一个对象的地址,那么在修改时就会同步修改,导致不可预测的问题。

2. 通过引用来比较

两个对象比较时,实际上比较的是他们的引用,因此复制对象的两个变量看似不同,但判定相同;键值对完全一致的两个对象看似相同,但判定不是同一个引用,因此不同

let a = {};
let b = a; // 复制引用

alert( a == b ); // true,都引用同一对象
alert( a === b ); // true
let a = {};
let b = {}; // 两个独立的对象

alert( a == b ); // false

3. 克隆与合并

为了避免 1.对象复制的特点 中所说的同步修改的问题,避免复制引用,而是直接复制内容,要怎么做呢?

原理就是用 for...in 语句一个个赋值,但我们不需要重复造轮子,这里有一个函数可以直接用:

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

dest 是目标对象,src数组则是被复制的对象,数组中所有对象的所有属性都会按照顺序拷贝到 dest 对象中,如果被拷贝的属性的属性名已经存在,那么它会被覆盖

当src数组只有一个对象时,就是浅拷贝

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

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

当src数组有多个对象时,则是对象合并

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 }

4. 深层克隆

浅拷贝克隆可以解决大多数问题,但是当对象的属性本身也是对象的时候,拷贝的属性又会变成引用,此时依然存在 “同步修改” 的潜在危险,于是我们需要用到深层拷贝

原理是:监视所有属性,当属性不是对象时,正常拷贝;当属性的值是对象时,在拷贝函数内部再调用一次拷贝函数,递归执行。

同样的,也有现成的函数:lodash 库的 _.cloneDeep(obj)

举个例子:

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false,两个对象已经不是同一个引用



垃圾回收

对于 Javascript,开发者设置的一切数据都是需要占用内存的,因此如果不及时清理,计算机就无法持续运行,于是就有了垃圾回收

1. 可达性(Reachability)

JavaScript 中主要的内存管理概念是可达性
首先,列出一些固定的 “根” ,即函数中的参数和局部变量、代码中的全局变量等
然后就可以判断其余的变量是否可以通过根访问到,如果可以就是可达的

2. 例1
// user 具有对这个对象的引用
let user = {
  name: "John"
};

这里有一个全局对象 user ,它有一个属性 name ,对应的值为 “John”
因此,user 是根,name可以通过 user 访问到,是可达的

如果我们此时重写 user

user = null;

name 这个属性并不会直接消失,而是会和对象 user失去联系,无法被访问到,在下次垃圾回收中被判定为不可达,因此被清理掉

3. 例2

那么,如果一个对象有两个引用它的变量呢?

// user 具有对这个对象的引用
let user = {
  name: "John"
};

let admin = user;

此时再将 user 重写,name 依然可以被 admin 访问到,并没有完全和 “根” 失去联系,是可达的

4. 例3

再看一个更复杂的例子

function marry(man, woman) {
  woman.husband = man;
  man.wife = woman;

  return {
    father: man,
    mother: woman
  }
}

let family = marry({
  name: "John"
}, {
  name: "Ann"
});

我们通过 marry() 函数让两个人(对象)结婚了,并最终返回了一个 family 对象,并赋予了二人各自的身份(wife / husband)

他们的关系就变成这样了:
marry函数,图片来自Javascript.info
现在进行这些操作:

delete family.father;
delete family.mother.husband;

于是,family 中没有了 father ,wife 也不再和 husband 联系
结果就是, 只有 John 认为 Ann 还是他的妻子,但这个家已经没有他的位置了,因为他失去了 “父亲” 和 “丈夫” 两重身份。
在这里插入图片描述
那么现在,John 所在的对象就是不可达的,尽管他还可以访问 Ann,但是已经没有可以访问他的 “根”了,所以他会被清理。

5. 内部算法

垃圾回收的基本算法被称为 “mark-and-sweep”,虽然叫 “根” 但实际上这是一种关系图算法,通过迭代标记来遍历图的所有节点,没有被标记的就是不可达节点,被清理

在此不多介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值