现代JavaScript教程 对象笔记
发表于:2021-05-26分类:JavaScript笔记对象
//创建对象
let user = new Object(); // “构造函数” 的语法
let user = {}; // “字面量” 的语法
let user = { // 创建对象
name: "John", // 属性 键 "name",值 "John"
age: 30, // 属性 键 "age",值 30
num: 4,
"likes cat": true, //多词属性
};
user.isAdmin = true; //添加属性
delete user.num;//移除属性
//访问对象
alert( user.name ); // John
alert( user.age ); // 30
alert( user.isAdmin ); // true
alert( user["likes cat"] );//访问多词属性,删除也一样
let key = "name";
alert(user[key]);//当使用变量当名称访问时应该加[]
//计算属性
let fruit = "age";
let bag = {
[fruit]: 5, // 属性名是从 fruit 变量中得到的
[fruit + 'Num'] : 5 //组成ageNum
};
console.log(bag.age);//得到5
console.log(bag.ageNum);//得到5
//属性值简写
function makeUser(name, age) {
return {
name: name,
age: age,
};
}
let user = makeUser("John", 30);
console.log(user.name); // John
//可以简写成:
function makeUser(name, age) {
return {
name,
age,
num : 30 //可以混用
};
}
//in操作符
//JavaScript中不存在的属性也不会报错,会返回undefined
let user = {};
console.log( user.noSuchProperty === undefined ); //true 没有这个属性
console.log("noSuchProperty" in user) //in用法 false 不存在(左边可以是个变量,检查与值同名的属性)
//以上2个方法区别类似于空值合并的情况,当属性存在但值时undefined是第一个方法无法知道。
for...in循环
//遍历对象中所有的键(当键是整数或“整数”的情况下,会被排序)
let user = {
name: "John",
age: 30,
isAdmin: true,
1 :1
};
for (let key in user) {
console.log( key ); //键 name, age, isAdmin
console.log( user[key] ); //值 John, 30, true
}
对象的引用和复制
let user1 = {name: "John"};
let user2 = user1;//并不是复制,而是引用
user2.name = 'leon';
console.log(user1.name);//leon
console.log(user2.name);//leon
let a = {};
let b = {}; // 两个独立的对象
alert( a == b ); // false 看起来是2个一样空的对象,但是实际情况是内存地址不同,是2个对象
克隆与合并
怎么才能复制一个对象呢?用for in
let user = {
name: "John",
age: 30
};
let clone = {}; // 新的空对象
// 将 user 中所有的属性拷贝到其中
for (let key in user) {
clone[key] = user[key];//clone的user键=user键的值
}
//还可以使用Object.assign(浅拷贝)
let user = {
name: "John",
age: 30
};
let clone = {}; // 新的空对象
Object.assign(clone, user);
//其实就是把user合并到clone,可以合并多个对象,更多,user1,user2 这样
//注意同名属性会被后面的覆盖
let clone = Object.assign({}, user);//另一种写法
深度克隆
当对象里包含对象,克隆那个属性说包含的对象实际上就是==引用,所以需要用递归来实现。或者不自己造轮子,使用现成的实现,例如 JavaScript 库 lodash 中的 _.cloneDeep(obj)。
垃圾回收
JavaScript是自动完成内存管理的。
可达性:可以被访问到或可用的值一定是存在内存中的,不可达就会被删除
let user = 1;//可达
user = null; //不可达了 删除
let user = {
name: "John"
};
let admin = user;//引用对象
user = null; //user 不可达了,但是admin依旧可达,内存还在
对象方法
//对象属性中可以创建方法
let user = {
name: "John",
age: 30
};
user.sayHi = function() {
alert("Hello!");
};
user.sayHi(); // Hello!
//更多写法
user = {
sayHi: function() {
alert("Hello");
}
};
//简写
let user = {
sayHi() { // 与 "sayHi: function()" 一样
alert("Hello");
}
};
this
对象中的方法需要访问对象中的其他属性时,就用this
let user = {
name: "John",
age: 30,
sayHi() {
// "this" 指的是“当前的对象”,访问name
alert(this.name);
}
};
user.sayHi(); // John
“this” 不受限制,不是对象也能用,所以可以先写在预先声明的函数中,这并没有语法错误(实际运行时,非严格模式下,不在对象中使用this,就是全局对象,严格模式会报错)
构造器 new
内部机制的步骤:1.新建空对象,并分配this。2.函数内部开始执行,为this增加属性。3.返回this
function User(name) {
// this = {};(相当于隐式创建)
this.name = name;
this.isAdmin = false;
// return this;(相当于隐式返回)
}
//构造函数必须是大写开头
let user = new User("Jack");
alert(user.name); // Jack
alert(user.isAdmin); // false
//也可以这样写,user成了对象,但这种方法只能创建单个,毕竟是匿名函数
let user = new function() {
this.name = "John";
this.isAdmin = false;
};
构造器的return
构造器可以没有return的,构造器中如果返回的是一个对象,就返回这个对象,其他情况就返回自身
//返回对象的情况
function BigUser() {
this.name = "John";
return { name: "Godzilla" }; // <-- 返回这个对象
}
alert( new BigUser().name ); // Godzilla,得到了那个对象的name
//返回非对象的情况
function SmallUser() {
this.name = "John";
return; // <-- 返回 this
}
alert( new SmallUser().name ); // John
可选链 ?.
let user = {}; // 一个没有 "address" 属性的 user 对象
alert(user.address); // undefined! 没有这个属性所以未定义
alert(user.address.street); // Error! 没有定义这个属性的对象属性报错
//简单的2种方法,不优雅难理解
console.log(user.address ? user.address.street : undefined); //判断是否存在对象再去拿值,不存在就是未定义,存在但没有属性还是未定义
console.log( user.address && user.address.street && user.address.street.name ); //遇到未定义就返回了,不会触发报错
这时候就需要可选链?.(请注意:?.
语法使其前面的值成为可选值,但不会对其后面的起作用)
let user = null; // user都不存在
console.log( user?.address?.street ); // undefined(不报错)
//判断方法
let userGuest = {};
userGuest.admin?.(); // 啥都没有(没有这样的方法)
let user1 = {
firstName: "John"
};
let user2 = null; // 为空
let key = "firstName";
alert( user1?.[key] ); // John 成功
alert( user2?.[key] ); // undefined
Symbol 类型
之前简单说过,这是唯一标识符,对象的属性键只能是字符串(整数键其实被转为字符串了)或者Symbol ,它不参与for...in,Object.keys(user)也不会有,但是Object.assign会复制
//使用symbol 增加隐藏属性
let user = { // 属于另一个代码
name: "John"
};
let id = Symbol("id");
user[id] = 1;
user[id] = 1;
console.log(user[Symbol("id")]);//无法访问
console.log(user[id]);//可以访问
//对象字面量种使用
let id = Symbol("id");
let user = {
name: "John",
[id]: 123 // 而不是 "id":123
};
//全局注册表,可以通过id访问完全相同的属性
// 从全局注册表中读取
let id = Symbol.for("id"); // 如果该 Symbol 不存在,则创建它
// 再次读取(可能是在代码中的另一个位置)
let idAgain = Symbol.for("id");
// 相同的 Symbol
alert( id === idAgain ); // true
//更多用法不再深入
对象原始值转换
对象之间运算,对象的布尔值都是true,所以只存在字符串和数数值转换。
除了Date 对象之外,所有内建对象都以和 "number" 相同的方式实现 "default" 转换。我们也可以这样做。
评论已关闭