JavaScript类的几种经典写法与原理详解
JavaScript早期并未引入"类"这一原生概念,而是通过构造函数和原型对象来模拟面向对象的特性。本文将深入解析几种经典的类定义写法,包括构造函数法、原型方式、组合模式以及基于对象字面量的替代方案,剖析其在内存占用、方法共享及实例化灵活性上的差异。
核心原理:原型是类的基石
在JavaScript中,类的所有实例对象都从同一个原型对象上继承属性,因此原型对象是构建"类"的核心。类是对对象的抽象,不占用内存;而对象是具体的实例,占用存储空间。早期的JS开发多为面向过程或简单函数编写,随着需求复杂化,逐渐引入了模仿其他语言(如Java)的类式编程思想。
方法一:构造函数法
这是最直观的模拟类的方式,通过在构造函数内部使用 this 关键字定义属性和方法。
<script>
// Person类:定义一个人,有name属性和getName方法
function Person(name){
this.name = name;
this.getName = function(){
return this.name;
}
}
// 实例化几个对象
var p1 = new Person("trigkit4");
var p2 = new Person("mike");
console.log(p1 instanceof Person); // true
console.log(p2 instanceof Person); // true
</script>
分析:
- 优点: 支持传入参数构造不同的对象实例,灵活性高。
- 缺点: 每次创建新实例时,都会重新生成一次
getName方法。对于大量实例而言,这会造成不必要的内存浪费,因为每个实例的方法地址都是独立的。
为了解决方法重复创建的问题,可以将方法提取为外部函数,使所有实例共享同一方法引用:
<script>
// 外部公共函数
function getName() {
return this.name;
}
function Person(name){
this.name = name;
this.getName = getName;
}
</script>
方法二:原型方式
这种方式将属性挂在原型对象 prototype 上,利用原型链实现共享。
<script>
function Person(){};
// 类的属性和方法都放在prototype上
Person.prototype.name = "trigkit4";
Person.prototype.getName = function(){
return " I'm " + this.name;
}
var p1 = new Person();
var p2 = new Person();
console.log(p1.name); // trigkit4
console.log(p2.getName()); // I'm trigkit4
</script>
分析:
- 优点: 所有对象实例共享
getName方法和属性,极大地节省了内存。 - 缺点: 无法通过构造函数参数动态初始化属性(例如每个用户有不同的名字),因为属性被固定在了原型上。
方法三:构造函数 + 原型方式(组合模式)
综合上述两种方法的优点:使用构造函数定义实例属性(字段),使用原型定义方法。
<script>
function Person(name){
// 实例属性,每个实例拥有独立副本
this.name = name;
}
// 原型方法,所有实例共享
Person.prototype.getName = function(){
return " I'm " + this.name;
}
</script>
这种写法既允许构造不同属性的对象,又实现了方法的内存共享。为了让代码结构更紧凑,有时会将原型赋值写在构造函数内部:
<script>
function Person(name){
this.name = name;
// 注意:这里的写法虽然能运行,但每次new都会重新定义原型方法,失去共享意义,仅用于演示位置紧凑性
// 实际开发中建议保持分离或使用Object.defineProperty等方式优化
if (!Person.prototype._init) {
Person.prototype.getName = function(){
// 使用闭包捕获局部变量name,或者直接用this.name
return this.name;
};
Person.prototype._init = true;
}
}
var p1 = new Person('trigkit4');
console.log(p1.getName()); // trigkit4
</script>
方法四:Object.create() 映射模式
在ES5中,Object.create() 提供了一种基于原型的对象创建方式。此时,"类"表现为一个普通对象模板。
// 定义对象模板(类)
var Person = {
name : "trigkit4",
age : 21,
run: function(){
alert("I like running");
}
};
// 直接创建实例,无需new
var p1 = Object.create(Person);
alert(p1.age); // 21
p1.run(); // I like running
局限: 这种方法简洁直观,但无法实现私有属性/方法,且实例间若修改原型上的引用类型数据容易产生冲突,对"类"的模拟不如函数方式全面。
方法五:createNew() 工厂模式
通过对象内部定义一个静态方法 createNew 来负责实例化,不涉及 this 和 prototype 的显式操作。
<script>
var Person = {
createNew : function () {
var person = {};
person.name = "trigkit4";
person.run = function(){
alert("I like running");
};
return person;
}
};
</script>
使用时调用:var p1 = Person.createNew();。这种写法类似于对象字面量,适合简单的对象模拟,但缺乏真正的继承链支持。
总结
JavaScript中的"类"本质上是通过函数和原型链实现的。在现代开发中,ES6引入了 class 关键字,其底层依然遵循上述原型继承逻辑,但语法更为清晰。理解构造函数、原型及 Object.create 等早期写法,有助于深入掌握JS的对象系统。
以上就是JavaScript类的几种经典写法与原理详解的详细内容,更多关于JavaScript类和面向对象编程的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













