持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
1、理解对象
js里万物皆对象,任何数据类型都可以转为对象。
创建对象
创建自定义对象目前使用最常见的方法就是使用对象字面量:
let person = {
name:'ly',
age:18,
sayName() {
console.log(this.name)
}
}
同时也可以使用Object构造函数的方式创建:
let person = new Object()
person.name = 'ly';
person.age = 18;
person.sayName = function() {
console.log(this.name)
}
还可以使用Object.create()函数创建一个新对象,但是该方法通常用来实现继承:
let person = Object.create(null);
console.log(person) // {}
let obj = Object.create(Object.prototype);
console.log(obj) // {}
第一个person意思是创建一个原型为null的空对象;第二个obj的意思是创建一个原型为Object原型的对象(等于使用字面量创建的对象)。关于原型后面再说。
除此之外,还有工厂函数可以创建对象:
function createPerson(name,age) {
let o = new Object();
o.name = name;
o.age = age;
o.sayName = function() {
console.log(this.name)
}
return o;
}
let person1 = createPerson('ly',18);
let person2 = createPerson('lyyy',20);
同时我们还经常自定义构造函数,使用构造函数创建对象:
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
}
}
let person1 = new Person('ly', 18);
let person2 = new Person('lyyy', 20);
person1.sayName(); // ly
person2.sayName(); // lyyy
在使用new的时候,构造函数会执行以下操作:
1.在内存中创建一个新对象。
2.在这个新对象内部的__proto__特性被赋值为构造函数的prototype属性。
3.构造函数内部的this被赋值为这个新对象(即this指向新对象)
4.执行构造函数内部的代码(给新对象添加属性)。
5.如果一个构造函数返回非空对象,则返回该对象;否则,返回在内存中新创建的对象。
类似于:
{// new的执行过程
var this = {} //定义一个空的this变量
this.__proto__ = Person.prototype //将实例对象的_proto_属性指向构造函数的原型
Person('ly',18).call(this) //将实参带入构造函数,并将构造函数this的指向改为创建的this对象。
this.name='ly'
this.age=18 //给新对象添加属性
return this //返回这个刚创建的this对象,并赋值给fun变量。
}
// 一般情况下,构造函数内不写返回值,返回这个this对象,
// 但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤
注:关于函数的prototype好像忘写了,prototype属性每一个函数都拥有,他的意思是原型。我们只要记住,我们创建函数后,js会自动给我们创建的函数添加prototype属性。
prototype是一个对象,他的身上默认携带constructor对象,他指向的是我们刚才创建的函数。(具体等原型链再讲吧)
但是使用构造函数的时候要注意,构造函数不能使用箭头函数!!!!
let Person = (name, age) => {
this.name = name;
this.age = age;
this.sayName = () => {
console.log(this);
}
}
let person = new Person('ly', 18);
[箭头函数表达式]的语法比[函数表达式]更简洁,并且没有自己的[this],[arguments],[super]或[new.target]。
箭头函数没有单独的this、不绑定arguments、箭头函数不能用作构造器,和new一起用会抛出错误、箭头函数没有prototype属性。
所以在之前的this.__proto__ = Person.prototype这一环节也就失败了!
2、对象属性的增删查改
let user = {
name: "ly",
age: 18,
18: 18
};
// 读
console.log(user.name); //ly
// or
console.log(user["name"]); //ly
// 中括号的读取
console.log(user[18]); // 18
// 增
user.sex = '男';
user.getname = function() {
return this.name;
};
console.log(user.getname()); //ly
// 删
delete user.name;
3、对象的引用传值
对象是引用类型,所以在传递参数的时候,传递的是对象的地址值。
let user = {
name: "ly",
};
function editUser(obj) {
obj.age = "8";
}
editUser(user);
// 打印的是被方法处理后的对象数据
console.log(user); // {age: "8",name: "ly"}
所以在函数中操作对象的内存地址会改变原来的对象数据,但是如果在函数中改变了地址值,那么对原对象就没有影响了。
let user = {
name: "ly",
};
function editUser(obj) {
obj = {
age: 8
}
}
editUser(user);
console.log(user); // { name: 'ly' }
这是因为,对象是按值传递的,editUser(user)中的user传递的是user对象的内存地址,而在函数中的形参就是声明一个变量为obj,然后将user对象内存地址复赋值给obj,这就使得obj和usre共用一个内存地址了,那么对这个内存里的修改就是一致的。但是例2中obj={age:8}是重新开辟了一个新的内存地址,obj和user不共用一个内存地址了,所以修改就不一致了。
4、合并对象
有时候我们需要将几个对象合并起来,形成一个新对象。
使用展开语法
let user = {
name: "ly",
age: "18",
};
// 展开语法合并两个对象
let newuser = {...user, height: 170, weight: 60 };
console.log(newuser); // { name: 'ly', age: '18', height: 170, weight: 60 }
对象中同名参数后面的会覆盖前面的
let user = {
name: "ly",
age: "18",
};
let newuser = {...user, name: 'lyyy', weight: 60 };
console.log(newuser); // { name: 'lyyy', age: '18', weight: 60 }
展开语法合并两个对象
let user = {
name: "ly",
age: "18",
};
let hobby = {
hobby1: '玩',
hobb2: '睡觉'
}
// 展开语法合并两个对象
let newuser = {...user, ...hobby };
console.log(newuser); // { name: 'ly', age: '18', hobby1: '玩', hobb2: '睡觉' }
使用assign()方法
Object.assing(obj1,obj2)可以合并对象 obj1 和对象 obj2
let user = {
name: "ly",
age: "18",
};
let hobby = {
hobby1: '玩',
hobb2: '睡觉'
}
let newuser = Object.assign(user, hobby)
console.log(newuser); // { name: 'ly', age: '18', hobby1: '玩', hobb2: '睡觉' }
5、对象的解构赋值
将对象中的属性解构赋值给普通变量
let user = {
name: "李四",
age: 18,
};
// 对象解构,可以分解获取对象的部分数据
let { name: a, age: g } = user;
console.log(a); // 李四
console.log(g); // 18
let info = {
title: "实践是检验真理的唯一标准",
count: 99,
};
// 如果声明的变量名称和对象里面的名称同名可以简写
let { title, count } = info;
console.log(title); // 实践是检验真理的唯一标准
console.log(count); // 99
let { random, floor } = Math;
console.log(floor(random() * 10)); // 2
将普通变量添加到对象中:
// 将变量转为对象,可以简写
let height = 170;
let weight = 55;
let obj = { height, weight };
console.log(obj);
多层对象解构操作:
let obj = {
name: "ly",
info: {
height: "170",
weight: "55",
},
};
// 多层解构方法,相当于把info对象里面的height解构赋值给height变量。例子如下
// let {height} = {height:"188"}
let { name, info: { height } } = obj;
console.log(height); // 170
6、对象的遍历
Object.keys(object)遍历对象的所有键名,返回一个数组Object.values(object)遍历对象的所有键值,返回一个数组Object.entries(object)遍历对象的键名和键值,返回一个二维数组
let user = {
name: "ly",
age: 18,
sex: "男",
height: 170,
};
// Object.keys() 获取对象中的所有键名
console.log(Object.keys(user)); // ["name", "age", "sex", "height"]
// Object.values() 获取对象中所有的值
console.log(Object.values(user)); // ["ly", "18", "男", "170"]
// Object.entries() 获取队形的键名和值
console.log(Object.entries(user));
// [["name","ly"],["age",18],["sex","男"],["height",170]]
还有for..in..与for..of..遍历:
let user = {
name: "ly",
age: 18,
sex: "男",
height: 170,
};
// for in 获取对象的值
for (const key in user) {
console.log('key:', key, 'value:', user[key]);
}
// for of 获取键和值
for (const [key, value] of Object.entries(user)) {
console.log(`${key}:${value}`);
}