javascript进阶知识13-对象基础

138 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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) // {}

image.png

第一个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);

image.png

同时我们还经常自定义构造函数,使用构造函数创建对象:

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属性。

image.png

prototype是一个对象,他的身上默认携带constructor对象,他指向的是我们刚才创建的函数。(具体等原型链再讲吧)

但是使用构造函数的时候要注意,构造函数不能使用箭头函数!!!!

let Person = (name, age) => {
    this.name = name;
    this.age = age;
    this.sayName = () => {
        console.log(this);
    }
}

let person = new Person('ly', 18);

image.png

[箭头函数表达式]的语法比[函数表达式]更简洁,并且没有自己的[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; 

image.png

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}`);
}

image.png