在 JavaScript 中,对象是一种复合数据类型,它将一组无序的键值对组合在一起。
键通常是字符串,而值可以是任何 JavaScript 数据类型,包括数组、函数,甚至是其他对象。
为什么要创建对象
1、封装性
对象可以将数据(属性)和对数据的操作(方法)封装到一起,形成了一个相对独立的个体,这个个体有自己的行为和属性。
这样做的好处是可以隐藏内部实现细节,只暴露必要的接口,使代码结构更加清晰,减少了不必要的外部访问。
2、重用性
如果有一组数据和操作总是一起使用,那么通过创建一个对象来封装它们,就可以在需要的时候重用这个对象,避免重复编写相同的代码。
3、模块化
对象可以用来创建模块和组件,使得你的代码更加模块化,更易于理解和维护。
对象的原理
在 JavaScript 中,对象实际上是一种特殊的数据类型。
当你创建一个对象时,JavaScript 引擎会在内存中为这个对象分配一块空间,然后将你定义的属性和方法存储在这块空间中。
每个属性和方法都有一个与之关联的键,你可以通过这个键来访问或修改属性的值,或者调用方法。
需要注意的是,对象是引用类型,在 JavaScript 中对对象的操作都是对对象引用的操作。
这意味着,如果你将一个对象赋值给另一个变量,那么这两个变量实际上引用的是同一个对象,对一个变量所引用的对象的修改会影响到另一个变量。
创建对象的方式
字面量的创建
let car = {
make: 'Toyota',
model: 'Camry',
display: function() {
console.log(this.make + ' ' + this.model);
}
};
car.display(); // 输出 "Toyota Camry"
new 关键字创建
let car = new Object();
car.make = 'Toyota';
car.model = 'Camry';
car.display = function() {
console.log(this.make + ' ' + this.model);
};
car.display(); // 输出 "Toyota Camry"
使用构造函数
function Car(make, model) {
this.make = make;
this.model = model;
this.display = function() {
console.log(this.make + ' ' + this.model);
};
}
let car = new Car('Toyota', 'Camry');
car.display(); // 输出 "Toyota Camry"
对象的方法
JavaScript中的对象有一系列内置的方法。这些方法大多数都来自于Object.prototype
这意味着它们可以在你创建的任何对象上使用。这里有一些常用的方法:
toString()
let car = {
make: 'Toyota',
model: 'Camry'
};
console.log(car.toString()); // 输出 "[object Object]"
此方法返回一个表示对象的字符串。
默认情况下,toString()方法被每个Object对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中type是对象的类型。
hasOwnProperty(propertyName)
let car = {
make: 'Toyota',
model: 'Camry'
};
console.log(car.hasOwnProperty('make')); // 输出 true
console.log(car.hasOwnProperty('year')); // 输出 false
此方法返回一个布尔值,指示对象自身(不包括原型链)是否具有指定的属性。
valueOf()
let car = {
make: 'Toyota',
model: 'Camry'
};
console.log(car.valueOf() === car); // 输出 true
此方法返回对象的原始值。
默认情况下,valueOf()方法由每个Object对象继承。如果此方法在自定义对象中未被覆盖,valueOf() 返回对象本身。
isPrototypeOf(object)
function Car(make, model) {
this.make = make;
this.model = model;
}
let car = new Car('Toyota', 'Camry');
console.log(Car.prototype.isPrototypeOf(car)); // 输出 true
console.log(Object.prototype.isPrototypeOf(car)); // 输出 true
此方法返回一个布尔值,表示指定的对象是否在当前对象的原型链上。
Object.assign(target, ...sources)
let obj1 = { a: 1, b: 2 };
let obj2 = { b: 3, c: 4 };
let obj3 = Object.assign({}, obj1, obj2);
console.log(obj3); // 输出 { a: 1, b: 3, c: 4 }
此方法用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。
Object.keys(obj)
let car = {
make: 'Toyota',
model: 'Camry'
};
console.log(Object.keys(car)); // 输出 ['make', 'model']
此方法返回一个包含对象自身的所有可枚举属性名称的数组,顺序与使用for...in循环的顺序相同(区别在于一个for-in循环也枚举原型链中的属性)。
Object.values(obj)
let car = {
make: 'Toyota',
model: 'Camry'
};
console.log(Object.values(car)); // 输出 ['Toyota', 'Camry']
此方法返回一个包含对象自身的所有可枚举属性值的数组,顺序与使用for...in循环的顺序相同(区别在于一个for-in循环也枚举原型链中的属性)。
Object.entries(obj)
let car = {
make: 'Toyota',
model: 'Camry'
};
console.log(Object.entries(car)); // 输出 [['make', 'Toyota'], ['model', 'Camry']]
此方法返回一个给定对象自身可枚举属性的键值对数组,其顺序与使用for...in循环的顺序相同(区别在于一个for-in循环也枚举原型链中的属性)。
继承
JavaScript 使用原型链实现继承。当我们创建一个对象,它默认就会继承自 Object.prototype。
function Vehicle(make) {
this.make = make;
}
Vehicle.prototype.displayMake = function() {
console.log(this.make);
};
function Car(make, model) {
Vehicle.call(this, make);
this.model = model;
}
Car.prototype = Object.create(Vehicle.prototype);
Car.prototype.constructor = Car;
let car = new Car('Toyota', 'Camry');
car.displayMake(); // 输出 "Toyota"
原型与原型链
每个 JavaScript 对象都有一个特殊的隐藏属性 Prototype,它要么是另一个对象,要么是 null。
我们通常使用 __proto__ 来访问这个属性(虽然这不是一个好习惯)。Prototype 对象被称为当前对象的“原型”。
当我们尝试访问一个对象的属性时,如果该对象本身没有这个属性,JavaScript 会尝试在该对象的原型(Prototype 或 __proto__)上查找该属性。如果原型对象上也没有这个属性,那么 JavaScript 会继续在原型的原型上查找,一直到原型为 null 为止。这就形成了一条原型链。