JavaScript面向对象编程核心机制与实战解析
本文深入解析JavaScript面向对象编程的核心机制,涵盖数据类型、包装类及引用类型与值类型的区别。详细阐述利用new构造对象时的原型链创建流程,并通过代码示例演示封装、继承(原型链与手动拷贝)及多态的实现。同时对比深拷贝与浅拷贝差异,探讨prototype.constructor的作用及在实际B/S架构中的应用,旨在提升代码复用率与开发效率。
JavaScript面向对象编程概述
在JavaScript中充分运用面向对象的设计思想,能够显著提升代码的重用性,降低模块间的耦合度,并实现更清晰的逻辑分层与并行开发。接下来,我将分步骤简要阐述我对这一主题的理解。
一、数据类型与包装类
数据类型与包装类
包装类 …… 类型名 …… 常见值 …… 分类
Number …… number …… 123.123 …… 基本数据类型
Boolean …… Boolean …… true、false …… 基本数据类型
String …… string …… “hello world!” …… 基本数据类型
Object …… object …… {}、[] …… 复合数据类型
Function …… function …… function(){} …… 特殊类型
无 …… undefined …… undefined、未定义 …… 小数据类型
无 …… null …… null …… 小数据类型
内置类型与本文关系不大,不列出。
二、引用类型与值类型
引用类型与值类型
引用类型:object function
值类型:number、boolean、string、null、undefined
三、new function(构造器)与prototype(原型)
构造函数与原型机制
关于prototype的设计模式网上已有大量介绍,此处不再赘述。下面通过一个示例来介绍在JavaScript中使用new关键字构造对象的具体过程。
function classname(){this.id=0;} var v=new classname();
当使用function构造对象时,系统会执行以下流程:
1、 查找classname的prototype,并进行浅拷贝。
2、 绑定this指针到拷贝来的对象。
3、 将this.constructor属性设置为classname。
[注:其实classname.prototype.constructor的值也被设置为classname,第六部分会说明]
4、 执行用户{}中的代码。
5、 返回this指针赋予左值v。
四、实现面向对象的三个基本特征
封装、继承与多态实现
1、 封装
封装概念广为人知,在JavaScript中,重点在于访问权限的控制。在其他原生支持面向对象的语言中,通常支持public、protected、private三个关键字来控制访问权限,但在JavaScript中,我们只能依靠复杂的作用域关系来实现这一控制:
代码如下:
function classname(a){
var uid=a; //uin为模拟private,作用域为{},外部无法使用
this.getuid=function(){return a;} //为uid提供一个外部只读接口 obj.getuid();
this.setuid=function(val){a=val} //为uid提供一个外部可写接口obj.setuid(5);
this.id=uid; //id为模拟public obj.id 使用
}
classname.prototype.func=function(){}; //模拟public方法 obj.func()调用
classname.stafunc=function(){}; //模拟静态方法 classname.stafunc()调用
var obj=new classname(1); [!]非常需要注意的就是,因为function是引用类型, classname.prototype.func是所有对象共享的一个function对象(每个对象仅存着引用),因此对象规模不大。而使用this.getuid和this.setuid为定义一个function,因此每个对象实例都会存一份,如果放肆使用这种方法,会造成对象规模庞大,影响性能。个人认为模拟private变量的意义不大。
[!]如果有需求真的需要大量使用this.xxx=function(){}这种情况,在function(){}中的this指针与最外的this指针是不同的,最好在类定义的首行加上var _this=this;,这样在this.xxx=function(){}中也可以方便使用绑定的指针。
2、 继承
继承的实现主要有两种方法:第一种是利用JavaScript本身的原型模型,通过给prototype赋值并改变其constructor属性来实现继承;第二种方法是不使用prototype,手动实现将父对象的所有属性和方法深拷贝到子对象。例如A需要继承B,第一种写法可以是:A.prototype=new B();A.prototype.constructor=A; 第二种写法可以编写一个递归函数,或者使用jquery中的extend方法。另外,如果要实现多继承,使用prototype会相当麻烦(需要依次继承多个类,还要创建空对象来承接),而第二种方法则相对简单,依次拷贝即可。通常为了便于查找父类,可以在对象中增加一个属性来引用父类。
3、 多态
函数重载不再赘述,通过检查参数即可实现,非常灵活。隐藏属性则是直接赋值为undefined。需要注意的是,如果打算继承B类的prototype,一定要先创建一个空对象来承接,否则直接给类写方法会相当于直接修改了prototype,即使不写方法,最后修改constructor时也会导致继承链错乱。创建一个空对象非常容易:
代码如下:
function temp(){};
temp.prototype=B;
var obj=new temp(); 这样再让需要继承B.prototype的类继承obj即可,即便修改prototype也不会影响到B。而且也不像继承new B()那样浪费很多空间。
五、深拷贝与浅拷贝
深拷贝与浅拷贝
这个和其他语言中没什么区别,浅拷贝就是直接拷贝,遇到引用类型或类类型不再深入。深拷贝则是根据类型判断,进行递归拷贝。
六、prototype.constructor
prototype.constructor的作用
这个值主要是用于维护继承的原型链。一篇文章已经写的非常详细,请参考:http://bbs.51js.com/thread-84148-1-1.html
七、JS的面向对象开发
JS面向对象开发实战经验
由于我不是前台开发人员,见过项目有限,仅谈自己的经验。
我开发过的B/S架构中,常用两种模式:一种是以CGI为主,由后台语言生成HTML,JS仅负责用户交互和ajax通信等;另一种是使用MVC架构,后台语言仅生成JSON,View层完全由JS组件在客户端实现。后者通常大量使用面向对象思想进行编程,将组件封装成类,将JSON传入构造函数,再由控制器或布局组件Add进来。由于组件可以重用,在开发后台管理系统和JS游戏时,效率还是相当可观的。
JavaScript闭包与类(Class)的区别及适用场景对比
2026-11-05 15:48:57
JavaScript入门要学ES6吗?let与箭头函数等新特性解析
2026-11-05 14:49:16
JavaScript 8种数据类型详解:基本类型与引用类型的区别
2026-11-05 14:25:15
怎么在JavaScript中使用async/await优化Ajax异步流程
2026-11-05 13:56:15
JavaScript replace回调函数实现动态正则替换逻辑
2026-11-05 13:52:13
