《javascript现代编程》学习笔记——对象Object和symbol

1 篇文章 0 订阅
1 篇文章 0 订阅

基础

列表中的最后一个属性应以逗号结尾:

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

这叫做尾随(trailing)或悬挂(hanging)逗号。这样便于我们添加、删除和移动属性,因为所有的行都是相似的.

多字词做属性名,用[]访问

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

“likes birds”就是一个多字词做为对象的属性名。
获取他的值得时候,不能像正常的user.name那样获取。
需要使用[]

alert(user["likes birds"])//true

可以先定义后使用

let key = "likes birds";
delete user[key];

但是正常的user.name这种点符号不可以像上面那样定义使用;

let key = "name";
alert( user.key ) // undefined

属性简写

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

存在性检查

  • ===undefined
  • key in Object
let obj = {
  test: undefined
};

alert( obj.test ); // 显示 undefined,所以属性不存在?

alert( "test" in obj ); // true,属性存在!

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
}

如果客户不希望按照整数那么排,我们可以使用非整数属性名来欺骗程序,在每个键名前加一个“+”

        let codes = {
            "+49": "Germany",
            "+41": "Switzerland",
            "+44": "Great Britain",
            // ..,
            "+1": "USA"
        };

        for (let code in codes) {
            console.log(+code); // 1, 41, 44, 49
            console.log(typeof +code);//number
        }
  • 不是整 数属性,按照创建的时候的顺序来排序
let user = {
  name: "John",
  surname: "Smith"
};
user.age = 25; // 增加一个

// 非整数属性是按照创建的顺序来排列的
for (let prop in user) {
  alert( prop ); // name, surname, age
}

对象的引用

引用复制

对象同其他基本类型不同,对象是通过引用存储和复制的。
基本类型的复制:

        let message = "Hello!";
        let phrase = message;
        console.log(message,phrase);//Hello! Hello!
        phrase = "world";
        console.log(message,phrase);//Hello! world

对象通过引用复制:

        let user = {
            name : 'John',
        }
        let admin = user;
        console.log(admin,user);//{name: "John"} {name: "John"}
        admin.name = 'Peter';
        console.log(admin,user)//{name: "Peter"} {name: "Peter"}

当对象被复制的时候——引用被复制了,对象本身并没有被复制。
怎么说呢,对象相当于一个抽屉,ueradmin是两把钥匙,用admin把对象这个抽屉中的内容改变了,那么再用user这本钥匙去开对象抽屉的时候,里面的内容就是改变后的内容。

比较引用

两个对象引用相同时=====才会返回true

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

alert( a == b ); // true,两个变量指向同一个对象
alert( a === b ); // true

两个对象返回的是false

        let a = {};
        let b = {}; // 两个独立的对象

        alert(a == b); // false
        alert(a === b); //false

常量对象

const 修饰过得对象是可以被修改的
这里指的修改是修改值,不是引用

        const user = {
            name: 'aa'
        }
        user.name = 'bb';
        console.log(user.name);//bb
        user = {
            name: 'cc'
        }
        console.log(user.name);//Uncaught TypeError: Assignment to constant variable.

复制和合并 Object.assign

复制一个对象,对其进行克隆,或者对个对象进行合并。

Object.assign(dest,[sec1,sec2])

这个方法将 src1, …, srcN 这些所有的对象复制到 dest。换句话说,从第二个参数开始,所有对象的属性都复制给了第一个参数对象,然后返回 dest.

        let user = { name: "John" };
        let permissions1 = { name: "Peter" };
        let permissions2 = { canEdit: true };

        Object.assign(user,permissions1,permissions2);
        console.log(user);//{name: "Peter", canEdit: true}
        permissions1.name = "Happy";
        console.log(permissions1.name)//Happy
        console.log(user.name);//Peter
  • 如果属性名相同,会被覆盖
  • 合并之后,在修改被复制的对象是行之改变,不会影响克隆后的结果。

Object.assign 来替代循环赋值进行简单的克隆操作。

        let user = { name: "John" };
        let clone = Object.assign({},user);
        console.log(clone)//{name: "John"}

深度克隆

如果一个对象的属性是其他对象的引用,就绪要深度克隆。
例如下面的这个对象

        let user = {
            name: "John",
            sizes: {
                height: 182,
                width: 50
            }
        };
        let clone = Object.assign({},user);
        console.log(clone.sizes);//{height: 182, width: 50}
        console.log(clone.sizes == user.sizes)//true
        user.sizes.height ++;//183
        console.log(clone.sizes.height)//183

像上面这样是不能够克隆出user对象的,因为仅仅复制了sizes的这个引用。
为了解决这个问题,我们在复制的时候应该检查 user[key] 的每一个值,如果它是一个对象,那么把它也复制一遍,这叫做深拷贝(deep cloning)
一个 JavaScript 实现的库 lodash,方法名叫做 _.cloneDeep(obj)。

    <script src="lodash.js"></script>
    <script>
        let user = {
            name: "John",
            sizes: {
                height: 182,
                width: 50
            }
        };
        let clone = _.cloneDeep(user);
        console.log(clone.sizes == user.sizes)//false

对象的键、值、项

  • Object.keys(obj) —— 返回一个包含该对象全部的键的数组。
  • Object.values(obj) —— 返回一个包含该对象全部的值的数组。
  • Object.entries(obj) —— 返回一个包含该对象全部 [key, value] 键值对的数组。
  • Object.***返回的是一个数组对象。
  • 会忽略Symbol作为键得属性
  • 要想获得Symbol类型的键,可以使用Object.gatOwnPropertySymbol返回一个只包含Symbol类型的数组
  • 也可以使用Reflect.ownKeys(obj) 方法会返回「所有」键。
        let id = Symbol('id');
        let user = {
            name: "John",
            age: 30,
            [id]: '123'
        };

        let result = Object.keys(user);

        console.log(result);
        // ["name", "age"]
        // 0: "name"
        // 1: "age"
        // length: 2
        console.log(typeof result); //object  数组对象

        for (let values of Object.values(user)) {
            console.log(values);
        }
        console.log(Object.getOwnPropertySymbols(user)); //[Symbol(id)]
        console.log(Reflect.ownKeys(user));
        //  ["name", "age", Symbol(id)]
        // 0: "name"
        // 1: "age"
        // 2: Symbol(id)
        // length: 3

Symbol类型

“Symbol” 值表示唯一的标识符。

基本使用

  • 创建
        let id = Symbol('id');

Symbol('id')中的id是一个描述。
描述相同值也是不同的。

        let id = Symbol('id');
        let id1 = Symbol('id');
        console.log(id == id1);//false
  • Symbol不会被自动转换成字符串
        alert(id)//Uncaught TypeError: Cannot convert a Symbol value to a string
        alert(id.toString())//Symbol(id)
        alert(id.description);//id

可以调用.toString()symbol.description 只显示描述

隐藏属性

        let user = { // 属于另一个代码
            name: "John"
        };

        let id = Symbol("id");

        user[id] = 1;

        console.log(user[id]); // 1 我们可以使用 Symbol 作为键来访问数据
        let id1 = Symbol("id");

        user[id1] = "Their id value";
        console.log(user)// {name: "John", Symbol(id): 1, Symbol(id): "Their id value"}

在字符串 “id” 上使用 Symbol(“id”) 有什么好处?
因为 user 属于另一个代码,另一个代码也使用它执行一些操作,所以我们不应该在它上面加任何字段,这样很不安全。但是 Symbol 不会被意外访问到,所以第三方代码看不到它,所以使用 Symbol 也许不会有什么问题。

对象字面量中的Symbol

  • 需要使用方括号把它括起来。
  • 不能用点运算符。
let id = Symbol("id");

let user = {
  name: "John",
  [id]: 123 // 而不是 "id:123"
};
alert(user[id])//123

for …in 跳过 Object.keys也忽略

let id = Symbol("id");
let user = {
  name: "John",
  age: 30,
  [id]: 123
};

for (let key in user) alert(key); // name, age (no symbols)

// 使用 Symbol 任务直接访问
alert( "Direct: " + user[id] )

Object.assign 会同时复制字符串和 symbol 属性:

let id = Symbol("id");
let user = {
  [id]: 123
};

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

alert( clone[id] ); // 123

全局Symbol

Symbol.for()

有一个全局 Symbol 注册表
要从注册表中读取(不存在则创建)Symbol,请使用 Symbol.for(key)
该调用会检查全局注册表,如果有一个描述为 keySymbol,则返回该 Symbol,否则将创建一个新 Symbol(Symbol(key)),并通过给定的 key 将其存储在注册表中。

// 从全局注册表中读取
let id = Symbol.for("id"); // 如果该 Symbol 不存在,则创建它

// 再次读取(可能是在代码中的另一个位置)
let idAgain = Symbol.for("id");

// 相同的 Symbol
alert( id === idAgain ); // true

Symbol.keyFor()

根据注册表的键返回一个名字

// 通过 name 获取 Symbol
let sym = Symbol.for("name");
let sym2 = Symbol.for("id");

// 通过 Symbol 获取 name
alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id

所以它不适用于非全局 Symbol。

let globalSymbol = Symbol.for("name");
let localSymbol = Symbol("name");

alert( Symbol.keyFor(globalSymbol) ); // name,全局 Symbol
alert( Symbol.keyFor(localSymbol) ); // undefined,非全局

alert( localSymbol.description ); // name

如果 Symbol 不是全局的,它将无法找到它并返回 undefined。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值