什么是普通对象
- JavaScript 普通对象是拥有一系列属性的引用数据类型,这些属性主要以键值对(键-属性名/值-属性值)的形式呈现
- 类似生活场景,一辆汽车可以看做一个对象,其重量、颜色等是属性,汽车的启动、停止等动作可以叫做方法
- 核心来说,普通对象就是一系列键值对的集合
创建普通对象
字面量创建
- 明确给定要创建的键值对,如果是创建空普通对象,则只需要{}
//eg.1 创建一个空普通对象
var emptyObj = {}
emptyObj.name = "James" // 空对象也可后期添加成员
//eg.2 创建一个非空普通对象
var conObj = {
name:"James",
age:20
}
构造函数创建
- JavaScript 内置了 Object() 的内置函数,可以通过关键字 new 创建一个普通对象,但成员需要在创建之后添加
var personObj = new Object()
personObj.name = "James"
personObj.age = 30
键(key)- 注意事项
任意设置:可以是字符串、数字、Symbol等基本类型,也可以是对象、函数等引用数据类型[Symbol("age")]:如果是Symbol、对象、函数等作为key,需要加上[],否则报错
var carObj = {
name:"Volvo",
time:2018,
"nation":"American",
[Symbol("serial")]:1204613151,
[function(){}]:"内置防伪",
[{engineering:"volvo"}]:"发动机防伪",
}
for (const key in carObj) {
if (Object.hasOwnProperty.call(carObj, key)) {
const element = carObj[key];
console.log(`key:${key} - valua:${carObj[key]}`)
}
}
//key:name - valua:Volvo
//key:time - valua:2018
//key:nation - valua:American
//key:function(){} - valua:内置防伪
//key:[object Object] - valua:发动机防伪
基本操作 - CRUD
借助点语法 .
var personObj = new Object()
//Create
personObj.name = "James"
personObj.age = 30
//Read
document.write(personObj.name)
document.write(personObj.age)
//Update
personObj.name = "Charles"
personObj.nameNick = "Jane" //如果key不一样,就会变成sCreate
//Delete
personObj.name = null //假删除 --> key还存在,value为null(空)
delete personObj.name //真删除 --> key和value都不存在了
借助中括号 []
var personObj = new Object()
//Create
personObj["name"] = "James" //使用[],必须要将name用引号,否则会将name当做全局变量查找,而不会作为对象key
personObj["age"] = 30
//Read
document.write(personObj["name"])
document.write(personObj["age"])
//Update
personObj["name"] = "Charles"
personObj["nameNick"] = "Jane" //如果key不一样,就会变成Create
//Delete
personObj["name"] = null //假删除 --> key还存在,value为null(空)
delete personObj["name"] //真删除 --> key和value都不存在了
两种寻址:点语法VS中括号
- 如果是规范合理命名对象的key,这两种方法效果相同
- 如果对象key命名剑走偏锋,使用点语法可能会导致代码运行错误,中括号引用能防止怪异属性名带来的错误
var homeObj = {
$tag:"No.25",
"#seconds":56,
"a+b":"equal"
}
console.log(homeObj.$tag) //No.25
console.log(homeObj["#seconds"]) //56
console.log(homeObj["a+b"]) //equal
console.log(homeObj.#seconds)
//SyntaxError: Private field '#seconds' must be declared in an enclosing class
console.log(homeObj.a+b)
//ReferenceError: b is not defined 这里把+当成为运算符
遍历操作 - for in
var personObj = new Object()
personObj["name"] = "James"
personObj["age"] = 30
personObj["post"] = "adviser"
for (const key in personObj) {
console.log(`key:${key} - value:${personObj[key]}`)
}
// key:name - value:James
// key:age - value:30
// key:post - value:adviser
栈(Stack)与堆(Heap)存储
问题场景
- 场景1:将一个对象赋值给另一个变量名,修改其中任意一个变量的属性,两者都被修改了
/* 场景1:将一个对象赋值给另一个变量名,修改其中任意一个变量的属性,两者都被修改了 */
var personObj = new Object()
personObj["name"] = "James"
personObj["age"] = 30
personObj["post"] = "adviser"
var personObjCop = personObj
//未修改
console.log(personObj) //{name: "James", age: 30, post: "adviser"}
console.log(personObjCop) //{name: "James", age: 30, post: "adviser"}
//修改personObj
personObj.name = "Charles"
console.log(personObj) //{name: "Charles", age: 30, post: "adviser"}
console.log(personObjCop) //{name: "Charles", age: 30, post: "adviser"}
//修改personObjCop
personObjCop.age = 50
console.log(personObj) //{name: "Charles", age: 50, post: "adviser"}
console.log(personObjCop) //{name: "Charles", age: 50, post: "adviser"}
- 场景2:声明两个字面量完全相同的普通对象,但进行等性比较的时候,依然是false
/* 场景2:声明两个字面量完全相同的普通对象,但进行等性比较的时候,依然是false */
var targetObj1 = {target:"money"}
var targetObj2 = {target:"money"}
//以下两者都是false
console.log(targetObj1 == targetObj2)
console.log(targetObj1 === targetObj2)
- 场景3:将一个基本数据类型的值传给另一个变量名,修改任意一个,不会影响另外一个
/* 场景3:声明将一个基本数据类型的值传给另一个变量名,修改任意一个,不会影响另外一个 */
var param01 = "parameter"
var param02 = param01
//修改param01,没有影响到param02
param01 = "variable"
console.log(param02) //parammeter
堆栈图解
拷贝对象
复制对象不能够存在修改其中一个对象,导致另外一个对象也被修改了,因此,不能单纯地赋值,因为对象是引用类型,栈内存放的只是堆中的地址值,需要将对象的元素逐个赋值到被复制对象的元素中
var objPrime = {
name:"James",
age:50
}
var objUltimate = new Object()
// var objUltimate = objPrime //只是复制了地址值
//复制对象(遍历对象内的元素)
for (const key in objPrime) {
if (Object.hasOwnProperty.call(objPrime, key)) {
const element = objPrime[key];
objUltimate[key] = element;
}
}
console.log(objPrime,objUltimate)
//检测复制结果(检测是赋值的元素,还是只是复制的地址值)
objPrime["name"] = "Test"
if(objPrime["name"] == objUltimate["name"]){
console.log("复制失败")
}else{
console.log("复制成功")
}
浅拷贝
- 含义:在拷贝对象的时候只能正确拷贝第一维的数据,如果是二维对象,仅能拷贝地址值
let objOri = {name:"James",age:20};
let objCopy = {};
//浅拷贝
function shallowCopy(objCopy, objOri){
for(let key in objOri){
objCopy[key] = objOri[key];
}
return objCopy;
}
console.log(shallowCopy(objCopy,objOri)); //{name: 'James', age: 20}
console.log(objOri.name = "Joker", objOri); //Joker {name: 'Joker', age: 20} -> 拷贝成功
let objOri = { name: "James", age: 20, address: { home: "town", job: "county" } };
let objCopy = {};
//浅拷贝 -> 利用展开运算符
objCopy = { ...objOri };
objOri.name = "Joker";
objOri.address.home = "city";
console.log(objOri);
// {name: 'Joker', age: 20, address: {…}}
// address: {home: 'city', job: 'county'}
// age: 20
// name: "James"
// [[Prototype]]: Object
console.log(objCopy);
// {name: 'James', age: 20, address: {…}}
// address: {home: 'city', job: 'county'} -> 因为浅拷贝,导致全被修改了
// age: 20
// name: "James"
// [[Prototype]]: Object
深拷贝
- 含义:在拷贝对象的时候能够通过递归,把多维对象的字段都拷贝到
let objOri = { name: "James", age: 20, hobby: ["篮球", "唱跳", "Rap"], location: { posfirst: "county", posecond: "home" } };
let objCopy = {};
//深拷贝
function deepCopy(objCopy, objOri) {
for (let key in objOri) {
// `?` 表示如果前面的为假,就不会走后面的`.`了
if (objOri[key]?.toString() === "[object Object]") {
objCopy[key] = {};
deepCopy(objCopy[key], objOri[key]);
} else if (Object.prototype.toString.call(objOri[key]) === "[object Array]") {
objCopy[key] = [];
deepCopy(objCopy[key], objOri[key]);
} else {
objCopy[key] = objOri[key];
}
}
return objCopy;
}
deepCopy(objCopy, objOri);
console.log(objCopy);
// {name: 'James', age: 20, hobby: Array(3), location: {…}}
// age: 20
// hobby: (3) ['篮球', '唱跳', 'Rap']
// location: {posfirst: 'county', posecond: 'home'}
// name: "James"
// [[Prototype]]: Object
console.log(objOri);
// {name: 'James', age: 20, hobby: Array(3), location: {…}}
// age: 20
// hobby: (3) ['篮球', '唱跳', 'Rap']
// location: {posfirst: 'county', posecond: 'home'}
// name: "James"
// [[Prototype]]: Object
objOri.location.posfirst = "hometown";
(objOri.hobby)[0] = "足球";
console.log(objOri.location.posfirst, (objOri.hobby)[0]);
// hometown 足球
console.log(objCopy.location.posfirst, (objCopy.hobby)[0]);
// county 篮球 -> 赋值不受影响,拷贝成功
//深拷贝 -> JSON方法,但对value为undefined的key不能拷贝
objCopy = JSON.parse(JSON.stringify(objOri));