js创建对象方式总结
字面量方式
使用大括号 {}
创建一个新对象,这是最简单直接的方式。适用于创建单个对象,可以直接在大括号内定义属性和方法。
let person = {
name: 'John',
age: 30,
gender: 'male'
};
let preson2 = {
name: 'John',
age: 30,
gender: 'male'
};
console.log(person === preson2) // false
这种创建方式对于创建大量相似对象的时候,会产生大量的重复代码
Object.create()
Object.create(proto[, propertiesObject])
方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
。这个方法允许你选择一个原型对象作为新对象的原型。
//3.Object.create()
let personPrototype = {
introduce: function () {
console.log(`My name is ${this.name} and I'm ${this.age} years old.`);
}
};
let person = Object.create(personPrototype);
person.name = 'John';
person.age = 30;
console.log(person)// {name: 'John', age: 30}
console.log(person.__proto__ === personPrototype) // true
console.log(person.__proto__ === personPrototype.prototype) // false personPrototype.prototype是undefined
console.log(personPrototype.__proto__ === Object.prototype) // true
在 JavaScript 中,只有函数对象(Function对象)才有
prototype
属性。函数对象的prototype
属性是一个对象,用于存储构造函数实例化的对象所共享的属性和方法。当你使用
new
关键字创建一个函数的实例时,实例的__proto__
属性会指向该函数的prototype
属性。这种机制支持了原型继承,让多个实例能够共享同一个原型对象上的方法和属性。
类(ES6+)
在ES6中引入了类的概念,使用 class
关键字可以定义类,然后通过 new
关键字创建类的实例。类语法是一个语法糖,背后仍然使用原型和构造函数。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log("Hello, " + this.name);
}
}
const person = new Person("Dave", 32);
console.log(person.__proto__ === Person.prototype) // true
工厂函数
工厂函数是一个普通函数,用来返回一个新的对象。工厂函数不使用 new
关键字,但可以接受参数并根据参数定制返回的对象。
function createPerson(name, age) {
var o = new Object();
o.name = name;
o.age = age;
o.greet = function () {
console.log("Hi, my name is " + this.name + " and I am " + this.age + " years old.");
};
return o;
}
const person = createPerson("Eve", 27);
console.log(person.__proto__ === createPerson.prototype) // false
console.log(person.__proto__ === Object.prototype) // true
// 无法识别为特定类型
console.log(person instanceof createPerson) // false
console.log(person instanceof Object) // true
工厂模式通过一个函数来封装创建对象的细节,从而实现对象创建代码的复用。但是,使用工厂模式创建的对象,无法识别为特定的类型。
构造函数
使用 new
关键字和构造函数来创建对象。构造函数通常首字母大写,可以接受参数用于设置对象的初始属性。
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.greet = function() {
console.log("Hi, my name is " + this.name + " and I am " + this.age + " years old.");
};
}
let person = new Person('John', 30, 'male');
let preson2 = new Person('John', 30, 'male');
console.log(person === preson2) // false
构造函数模式可以通过
new
关键字调用,创建的对象与构造函数之间建立了联系,可以通过instanceof
来识别对象类型。但每个实例都会创建新的函数实例。构造函数模式相对于工厂模式的优点是,所创建的对象和构造函数建立起了联系,因此可以通过原型来识别对象的类型。但是构造函数存在一个缺点就是,造成了不必要的函数对象的创建,因为在 js 中函数也是一个对象,因此如果对象属性中如果包含函数的话,那么每次都会新建一个函数对象,浪费了不必要的内存空间,因为函数是所有的实例都可以通用的。
原型模式
原型模式通过构造函数的prototype
属性定义共享的属性和方法,解决了构造函数模式中的函数重复创建问题。但所有实例共享属性和方法,对于引用类型的属性可能会导致意外的结果。
function Person() { }
Person.prototype.name = "John";
Person.prototype.age = 30;
Person.prototype.arr = [1,2,3]
Person.prototype.greet = function () {
console.log("Hi, my name is " + this.name + " and I am " + this.age + " years old.");
};
var person1 = new Person();
var person2 = new Person();
console.log(person1 === person2) // false
console.log(person1.__proto__ === Person.prototype) // true
person1.name = "person1"
console.log(person1.name) // "person1"
console.log(person2.name) // "John"
// 存在一个引用类型如 Array 这样的值,那么所有的实例将共享一个对象,一个实例对引用类型值的改变会影响所有的实例。
person1.arr.push(4) //
console.log(person1.arr) // [1, 2, 3, 4]
console.log(person2.arr) // [1, 2, 3, 4]
构造函数和原型模式的组合
这种模式结合了构造函数模式和原型模式的优点,通过构造函数初始化属性,通过原型共享方法。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function () {
console.log("Hi, my name is " + this.name + " and I am " + this.age + " years old.");
};
var person1 = new Person("John", 30);
var person2 = new Person("Jane", 25);
动态原型模式
动态原型模式在构造函数内部动态定义原型方法,只在第一次调用构造函数时执行,结合了构造函数和原型模式的优点,同时提高了封装性。
function Person(name, age) {
this.name = name;
this.age = age;
if (typeof this.greet != "function") {
Person.prototype.greet = function() {
console.log("Hi, my name is " + this.name + " and I am " + this.age + " years old.");
};
}
}
var person1 = new Person("John", 30);
var person2 = new Person("Jane", 25);
寄生构造函数模式
寄生构造函数模式类似于工厂模式,但使用new
关键字调用。它允许在不修改原构造函数的情况下,对创建的对象进行扩展。与工厂模式一样,创建的对象无法识别为特定的类型。
function Person(name, age) {
var o = new Object();
o.name = name;
o.age = age;
o.greet = function() {
console.log("Hi, my name is " + this.name + " and I am " + this.age + " years old.");
};
return o;
}
var person1 = new Person("John", 30);
var person2 = new Person("Jane", 25);