在 JavaScript 编程中,对象 是核心概念之一。理解如何创建对象以及如何实现对象之间的继承关系,对于掌握 JavaScript 面向对象编程至关重要。
本文将从两个部分来讲解:
- JavaScript 中对象的创建方式
- JavaScript 中对象的继承方式
我们会结合代码示例和生活中的类比,帮助你更好地理解这些看似晦涩的概念。
一、JavaScript 中对象的创建方式
1. 字面量方式(Object Literal)
这是最常见、最简单的方式。
js
const person = {
name: "张三",
age: 25,
sayHello: function() {
console.log("你好,我是" + this.name);
}
};
person.sayHello(); // 输出:你好,我是张三
2. 构造函数方式(Constructor Function)
通过定义一个构造函数,使用 new
关键字来创建多个相似对象。
js
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHello = function() {
console.log("你好,我是" + this.name);
};
}
const p1 = new Person("李四", 30);
p1.sayHello(); // 输出:你好,我是李四
生活类比:
这就像工厂流水线生产产品。构造函数就是生产线模板,每次调用 new
就像是启动一次生产,产出一个具有相同结构的产品(对象)。
3. 工厂函数方式(Factory Function)
不使用 new
,而是返回一个新对象的函数。
js
function createPerson(name, age) {
return {
name: name,
age: age,
sayHello: function() {
console.log("你好,我是" + this.name);
}
};
}
const p2 = createPerson("王五", 28);
p2.sayHello(); // 输出:你好,我是王五
4. 使用 Object.create()
方法
这个方法允许你基于一个现有对象创建新对象。
js
const personPrototype = {
sayHello: function() {
console.log("你好,我是" + this.name);
}
};
const p3 = Object.create(personPrototype);
p3.name = "赵六";
p3.sayHello(); // 输出:你好,我是赵六
生活类比:
这就像你模仿某个成功人士的行为模式(原型),然后你自己也具备了类似的能力,但你也可以有自己的个性(属性)。
5. ES6 类语法(Class)
ES6 引入了类语法,让面向对象编程更接近传统语言如 Java/C++。
js
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log("你好,我是" + this.name);
}
}
const p4 = new Person("小明", 20);
p4.sayHello(); // 输出:你好,我是小明
二、JavaScript 中对象的继承方式
JavaScript 的继承机制不同于传统的类继承语言(如 Java),它是一种基于原型(prototype-based)的语言。下面介绍几种常见的继承方式。
1. 原型链继承(Prototype Chaining)
通过将子类的原型指向父类的一个实例,从而实现继承。
js
function Animal() {
this.eat = function() {
console.log("动物会吃东西");
};
}
function Dog() {
this.bark = function() {
console.log("汪汪叫");
};
}
Dog.prototype = new Animal(); // 继承Animal
const dog = new Dog();
dog.eat(); // 输出:动物会吃东西
dog.bark(); // 输出:汪汪叫
生活类比:
这就像孩子继承了父母的某些特征。比如你爸爸会游泳,你也可能会游泳;但你还有自己的技能,比如打篮球。
2. 构造函数继承(Classic Inheritance / Constructor Borrowing)
通过在子类构造函数中调用父类构造函数,实现对父类属性的继承。
js
function Animal(name) {
this.name = name;
}
function Dog(name, breed) {
Animal.call(this, name); // 调用父类构造函数
this.breed = breed;
}
const myDog = new Dog("旺财", "金毛");
console.log(myDog.name); // 输出:旺财
console.log(myDog.breed); // 输出:金毛
生活类比:
这就像你在注册公司的时候,先借用了一个已有的营业执照(父类构造函数),然后再添加自己的特色业务(子类属性)。
3. 组合继承(Hybrid Inheritance)
结合原型链继承和构造函数继承的优点。
js
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(this.name + " 在吃东西");
};
function Dog(name, breed) {
Animal.call(this, name); // 构造函数继承
this.breed = breed;
}
Dog.prototype = new Animal(); // 原型链继承
Dog.prototype.constructor = Dog;// 将被覆盖掉的constructor重新声明为Dog
Dog.prototype.bark = function() {
console.log("汪汪!");
};
const d = new Dog("小白", "哈士奇");
d.eat(); // 输出:小白 在吃东西
d.bark(); // 输出:汪汪!
生活类比:
这就像你既继承了家族的传统手艺(原型链),又拥有自己的独特能力(构造函数),成为一个全能型选手。
4. 寄生组合式继承(Parasitic Combination Inheritance)
优化版的组合继承,避免了多次调用父类构造函数的问题。
js
function inherit(subType, superType) {
const prototype = Object.create(superType.prototype); // 创建对象
prototype.constructor = subType; // 增强对象
subType.prototype = prototype; // 指定对象
}
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(this.name + " 在吃东西");
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
inherit(Dog, Animal);
Dog.prototype.bark = function() {
console.log("汪汪!");
};
const d = new Dog("大黄", "土狗");
d.eat(); // 输出:大黄 在吃东西
d.bark(); // 输出:汪汪!
生活类比:
这就像是你找了一个中介(inherit
函数),帮你高效地继承家产(父类功能),而不是自己盲目操作,浪费资源。
5. ES6 类继承(Class Inheritance)
ES6 提供了 extends
和 super
来简化继承。
js
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} 在吃东西`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}
bark() {
console.log("汪汪!");
}
}
const d = new Dog("豆豆", "柯基");
d.eat(); // 输出:豆豆 在吃东西
d.bark(); // 输出:汪汪!
总结对比表
创建方式 | 特点 | 适用场景 |
---|---|---|
对象字面量 | 简洁直观 | 单个对象快速创建 |
构造函数 | 可复用,适合批量创建对象 | 多个相似对象 |
工厂函数 | 不依赖 new ,封装性好 |
简单封装创建逻辑 |
Object.create() |
明确指定原型 | 实现继承或共享行为 |
Class 类 | 语法清晰,符合传统OOP习惯 | 结构复杂项目 |
继承方式 | 特点 | 优缺点 |
---|---|---|
原型链继承 | 简单易懂 | 共享引用类型数据风险 |
构造函数继承 | 属性独立 | 方法不能复用 |
组合继承 | 兼具两者优点 | 会执行两次父类构造函数 |
寄生组合继承 | 最优方案 | 稍复杂,需手动实现 |
Class 继承 | 语法简洁 | ES6+ 支持,兼容旧环境可能受限 |
结语
JavaScript 的对象模型虽然不同于传统的类语言,但其灵活的原型机制赋予了强大的扩展能力。无论是创建对象还是实现继承,关键在于理解每种方式的原理和适用场景。
正如生活中我们学习他人经验、改进自己的做法一样,JavaScript 的对象也是通过继承不断丰富自身的能力。希望这篇文章能让你对 JavaScript 的对象有更清晰、深入的理解!
如果你喜欢这类内容,欢迎点赞收藏,后续我将持续更新更多前端进阶知识。