本文系统总结了JavaScript中创建对象的十种方式,涵盖new Object、字面量、工厂模式、构造函数、原型模式、混合模式、动态混合、寄生构造函数、ES6 Class及闭包。深入解析各模式的适用场景、内存特性及优缺点,帮助开发者根据实际需求选择最优方案。
前言
面向对象编程是软件开发中的核心范式之一,而灵活构建对象则是衡量开发者基础能力的重要标准。本文将深入探讨JavaScript中创建对象的十种具体实现路径,并将其归纳为new Object、构造函数与原型对象、以及其他三类主要模式。
new Object
这三种方式在底层机制上均依赖于new Object,其局限性在于无法通过原型链准确识别对象的具体类型,因为它们的原型链最终都指向Object。console.log(obj.__proto__===Object.prototype); // true
new Object
const obj = new Object({name: 'wayne',age: 18})
字面量方式
const obj = {name: 'wayne',age: 18}
工厂函数方式
function createPerson(name, age) {
return {name,age,}
}
const obj = createPerson('wayne', 18)构造函数与原型对象
以下四种方法是对构造函数与原型对象机制的进一步细化与应用。
构造函数方式
若在构造函数内部定义方法,每次实例化都会重新创建该方法,导致内存资源浪费。因此,这种方式仅适合存放属性,而不适合存放方法。
function Person(name, age) {
this.name = name
this.age = age
this.getInfo = function() {
console.log(this.name, this.age)
}
}
const obj = new Person('wayne', 18)原型对象方式
将共享方法统一放置于原型对象中,可以有效避免重复创建相同功能的方法,从而节省内存空间。然而,这种方式并不适合存放属性,主要原因包括以下三点:
- 通过new初始化新属性时操作不便,
- 属性修改过程不够便捷
p1.__proto__.name = 'jack' - 原型对象中的属性会被所有实例共享,这可能导致新创建的实例出现数据冲突或意外覆盖的问题。
function Person() {}
Person.prototype.name = "wayne"
Person.prototype.age = 10
Person.prototype.getInfo = function() {
console.log(this.name, this.age)
}
const p1 = new Person()
// 这里使用的是原型上的属性
p1.getInfo() // wayne 10
// 修改原型上的属性
p1.__proto__.name = 'jack'
p1.__proto__.age = 18
// 这里使用的是原型上的属性
p1.getInfo() // jack 18
const p2 = new Person()
// 修改过的属性
p2.getInfo() // jack 18混合模式
这是目前较为常见的实现方式,即将属性定义在构造函数中,而将方法定义在原型对象上。尽管实用,但这种模式在某种程度上违背了面向对象封装的纯粹思想。
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.getInfo = function() {
console.log(this.name, this.age)
}
const p1 = new Person(name, age)动态混合
这是混合模式的一种改进版本,其缺陷在于语义表达不够清晰。实际上,只有第一个对象被创建时才会触发if判断逻辑。
function Person(name, age) {
this.name = name
this.age = age
if (Person.prototype.getInfo === "undefined") {
Person.prototype.getInfo = function() {
console.log(this.name, this.age)
}
}
}
// 第一次调用时会给 Person.prototype 添加 getInfo 方法
const p1 = new Person("wayne", 18)
const p2 = new Person("jack", 15)寄生构造函数
与动态混合类似,但该模式通过在函数内部调用其他构造函数来实现对象的创建。
function Person(name, age) {
this.name = name
this.age = age
if (Person.prototype.getInfo === "undefined") {
Person.prototype.getInfo = function() {
console.log(this.name, this.age)
}
}
}
function func(name, age) {
const p = new Person(name, age)
return p
}
const p1 = func("wayne", 18)其他
class
利用ES6语法糖class来创建对象,其底层本质仍然是function。
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
getInfo() {
console.log(this.name, this.age)
}
}
const p1 = new Person("wayne", 18)
// class的本质是function
console.log(typeof Person); //function 闭包
借助闭包的特性同样可以实现对象的创建。其优势在于无需使用this和new关键字;然而,其劣势在于容易引发内存泄漏问题。
function Person(name, age) {
return {
getName() {
return name
},
getAge: function() {
return age
}
}
}
const p1 = Person("wayne", 18)
console.log(p1.getName()) // wayne
console.log(p1.getAge()) // 18总结
new Object的三种
new Object:new Object({name: 'wayne',age: 18})- 字面量创建:
{name: 'wayne',age: 18} - 工厂函数方式:
function createPerson(name, age) {return {name,age,}}
构造函数与原型对象四种
- 构造函数方式:适合属性
- 原型对象方式:适合方法
- 混合方式:常见的方式,将属性放在构造函数,方法放在原型上。
- 动态混合:使用if判断是否挂载方法
- 寄生构造函数:通过函数里调用其他构造函数
其他两种
- class,ES6语法糖,本质为function
- 闭包:优点:不用this 和 new;缺点:容易造成内存泄漏。
以上就是JS创建对象的十种方式总结的详细内容,更多关于JS创建对象的资料请关注本站其它相关文章!