深入解析JavaScript面向对象、prototype原型链与apply/call机制
本文深入解析JavaScript面向对象编程的核心机制,重点剖析prototype原型链的工作原理。通过代码示例详细讲解apply和call方法的区别及其在构造函数初始化中的应用,并阐释arguments对象如何传递参数,帮助开发者理解JS函数与类的本质差异及对象创建流程。
研究背景与问题提出
一、 起因
在研究prototype.js源码时,发现其中涉及大量JavaScript面向对象编程的知识。由于对JS的面向对象机制不够熟悉,阅读过程中遇到诸多困惑。经过查阅相关资料并进行整理,最终理清了思路,特此记录以作纪念。
prototype.js代码片段
代码如下:
var Class = {
create: function() {
return function() {
this.initialize.apply(this , arguments);
}
}
}
// Class使用方法如下
var A = Class.create();
A. prototype={
initialize:function(v){
this .value=v;
}
showValue:function(){
alert(this.value);
}
}
var a = new A(‘helloWord!');
a. showValue();//弹出对话框helloWord!l initialize是什么?
l apply方法是干什么的?
l arguments变量呢?
l 为什么new A后就会执行initialize方法?
寻找答案:
二、 Js的面向对象
JavaScript面向对象基础
initialize是什么?
initialize本质上是一个变量,指向一个函数,其作用相当于类的构造函数。
其具体功能依赖于JavaScript的面向对象机制。那么,JavaScript中的面向对象呈现何种形态?它与Java等强类型语言的面向对象有何异同?
看代码:
代码如下:
var ClassName = function(v){
this.value=v;
this.getValue=function(){
return this.value;
}
this.setValue=function(v){
this.value=v;
}
} 那么JS中的函数和类有什么不同呢?
其实,ClassName就是一个普通的函数。当它出现在new关键字后面时,它便作为构造函数来创建对象。
如
代码如下:
var objectName1 = new ClassName(“a”);//得到一个对象此时,objectName1是执行ClassName构造函数后返回的对象。在ClassName函数内部,this关键字指向的就是new操作符创建出来的新对象。因此,objectName1将拥有value属性以及getValue和setValue两个方法。可以通过以下方式调用它们:
代码如下:
objectName1.setValue(''hello'');
alert(objectName1.getValue());//对话框hello
alert(objectName1.value) ;//对话框hello那么
代码如下:
var objectName2 = ClassName(“b”);//得到一个对象这样objectName2得到的是什么?显然,它是函数的返回值。在这里,ClassName仅被视为一个普通函数(尽管首字母大写)。由于之前定义的ClassName没有显式返回值,因此objectName2的值将是undefined。那么参数“b”赋给了谁?由于这里并没有创建新对象,而是单纯执行了该函数,所以“b”被赋值给了全局调用者,即window对象。证据如下:
var objectName2 = ClassName(“b”);//得到一个对象
alert(window.value);//对话框b
由此可见,JavaScript中的所有function本质相同,只是用途不同:有的用于构造对象,有的用于执行具体过程。
原型链与构造函数机制
下面该回到主题了initialize是干什么的?
代码如下:
var Class = {
create: function() {
return function() {
this.initialize.apply(this , arguments);
}
}
}
var A = Class.create();这段代码构造了一个函数并将其赋值给A。这个被返回的function是:
代码如下:
function() {
this.initialize.apply(this , arguments);
} 并且这个函数被用作构造函数。当使用这个构造函数创建对象时,它会使得新对象的initialize变量执行apply()方法。apply()的具体用途稍后说明,这里先继续讨论initialize。这样,在初始化对象时,就会通过apply方法关联到initialize。
那么
代码如下:
A.prototype={
initialize:function(v){
this .value=v;
}
showValue:function(){
alert(this.value);
}
} 是什么意思呢?
Prototype意为“原型”。A是一个函数,那么A.prototype就是该函数的一个属性,实际上是一个对象。这个对象拥有什么方法,由A构造出来的对象就拥有什么方法。因此:
var a = new A(‘helloWord!');
a. showValue();//弹出对话框helloWord!
所以,对象a也会拥有initialize方法。不仅如此,每一个由A构造出来的对象都会拥有一个initialize方法。在前文提到,构造对象时会调用构造函数,而构造函数内部会让initialize去调用apply方法。因此,在new A(‘helloWord!')时,initialize会去调用apply方法。这也就是所谓的“初始化”过程。
三、 call()和apply()
apply与call方法解析
下面开始研究apply(),在网上找了几个资料,并结合自己的研究,了解了call()和apply()的功能。功能基本一样,function().call(object,{},{}……)或者function().apply (object,[……])的功能就是对象object调用这里的funciton(),不同之处是call参数从第二个开始都是传递给funciton的,可以依次罗列用“,”隔开。而apply只有两个参数,第二个是一个数组,其中存储了所有传递给function的参数。
this.initialize.apply(this , arguments);
是什么意思?
这里的第一个this,是指用new调用构造函数之后生成的对象,也就是前面的a,那么第二个this也当然应该是指同一个对象。那这句话就是this(也就是a)调用initialize方法,参数是arguments对象(参数的数组对象),所以在构造函数执行的时候,对象a就会去执行initialize方法来初始化,这样就和单词“initialize”的意思对上了。
那么执行initialize方法的参数怎么传递进去的呢?
四、 Arguments对象
Arguments对象详解
这段代码能说明一切了:
代码如下:
function test(){
alert(typeof arguments);
for(var i=0; i<arguments.length; i++){
alert(arguments[i]);
}
}
test("1","2","3");
test("a","b");执行后alert(typeof arguments);会显示object,说明arguments是对象。然后会依次打出1、2、3。说明arguments就是调用函数的实参数组。
代码如下:
var Class = {
create: function() {
return function() {
this.initialize.apply(this , arguments);
}
}
} arguments 就是create返回的构造函数的实参数组,那么在
var a = new A(‘helloWord!');
的时候‘helloWord!'就是实参数组(虽然只有一个字符串),传递给方法apply,然后在调用initialize 的时候作为参数传递给初始化函数initialize。
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
