详解JS面向对象编程:两种经典继承模式解析
本文深入解析JavaScript基于原型的面向对象编程,重点介绍两种经典继承实现方式。第一种通过函数模拟类,利用prototype属性及uber机制实现方法调用;第二种采用拷贝继承,通过_this对象承载公有成员并传递至子类。文章结合具体代码示例,详细阐述变量可见性、构造函数修正及父类方法复写等核心细节,帮助开发者理解JS继承机制的本质。
JavaScript面向对象基础与术语定义
由于JavaScript语言底层基于原型(prototype)机制,传统上并不存在“类”的概念(尽管ES6引入了class语法,此处暂不展开讨论),因此在JS中我们接触到的都是对象实例,这体现了“一切皆对象”的设计哲学。
鉴于“对象”一词在JS中含义较为宽泛,许多初学者容易混淆“类型对象”与“具体对象实例”的区别。为了便于理解,下文在术语使用上将借鉴Java等语言的分类方式,明确区分类型与实例。
基于函数模拟的继承模式
接下来介绍第一种实现方式。
类(函数模拟)
function Person(name,id){
//实例变量可以被继承
this.name = name;
//私有变量无法被继承
var id = id;
//私有函数无法被继承
function speak(){
alert("person1");
}
}
//静态变量,无法被继承
Person.age = 18;
//公有函数可以被继承
Person.prototype.say = function(){
alert("person2");
}
实现继承,并调用父类方法。
function Person(name,id){
//实例变量可以被继承
this.name = name;
//私有变量无法被继承
var id = id;
//私有函数无法被继承
function speak(){
alert("person1");
}
}
//静态变量,无法被继承
Person.age = 18;
//公有静态成员可被继承
Person.prototype.sex = "男";
//公有静态函数可以被继承
Person.prototype.say = function(){
alert("person2");
}
//创建子类
function Student(){
}
//继承person
Student.prototype = new Person("iwen",1);
//修改因继承导致的constructor变化
Student.prototype.constructor = Student;
var s = new Student();
alert(s.name);//iwen
alert(s instanceof Person);//true
s.say();//person2
实现继承,复写父类方法并模拟super()调用。
function Person(name,id){
//实例变量可以被继承
this.name = name;
//私有变量无法被继承
var id = id;
//私有函数无法被继承
function speak(){
alert("person1");
}
}
//静态变量,无法被继承
Person.age = 18;
//公有静态成员可被继承
Person.prototype.sex = "男";
//公有静态函数可以被继承
Person.prototype.say = function(){
alert("person2");
}
//创建子类
function Student(){
}
//继承person
Student.prototype = new Person("iwen",1);
//修改因继承导致的constructor变化
Student.prototype.constructor = Student;
//保存父类的引用
var superPerson = Student.prototype.say;
//复写父类的方法
Student.prototype.say = function(){
//调用父类的方法
superPerson.call(this);
alert("Student");
}
//创建实例测试
var s = new Student();
alert(s instanceof Person);//true
s.say();//person2 student
封装继承相关的辅助函数。
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
其中,uber属性用于指向父对象的prototype属性(“uber”为德语,意为“向上”或“上一层”)。这相当于在子对象上建立了一条直接调用父对象方法的通道。该行代码主要用于保证继承结构的完备性,属于备用性质的设置。
基于拷贝与_this对象的继承模式
接下来介绍第二种实现方式。
这种方式相当于对象拷贝,通过定义一个_this对象来承载需要被继承的内容。通过传递这个_this对象,即可实现继承逻辑,相比前一种方式,其直观性更强,更易于理解。
//创建父类
function Person(name,id){
//创建一个对象来承载父类所有公有东西
//也就是说_this承载的对象才会被传递给子类
var _this = {};
_this.name = name;
//这样的是不会传递下去的
this.id = id;
//承载方法
_this.say = function(){
alert("Person");
}
//返回_this对象
return _this;
}
//子类
function Student(){
//获取person的_this对象,从而模仿继承
var _this = Person("iwne",1);
//保存父类的_this引用
var superPerson = _this.say;
//复写父类的方法
_this.say = function(){
//执行父类的say
superPerson.call(_this);
alert("Student");
}
return _this;
}
var s = new Student();
s.say();
希望以上解析能对各位学习JavaScript程序设计有所帮助。
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
为什么JS中typeof []返回object:数组类型检测误区解析
2026-11-04 19:50:47
