解析 this.initialize.apply(this, arguments)

本文深入探讨JavaScript的面向对象特性,通过实例讲解构造函数、原型链、initialize方法的作用及apply函数的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    一、 起因 

那天用到prototype.js于是打开看看,才看几行就满头雾水,原因是对js的面向对象不是很熟悉,于是百度+google了一把,最后终于算小有收获,写此纪念一下^_^。 
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的面向对象 
initialize是什么? 
只不过是个变量,代表一个方法,用途是类的构造函数。 
其具体功能靠js的面向对象支持,那么js的面向对象是什么样子的那?和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会后一个属性和两个方法。可以通过这样来调用他们:

代码如下:
objectName1.setValue(''hello''); 
alert(objectName1.getValue());//对话框hello 
alert(objectName1.value) ;//对话框hello

那么

复制代码 代码如下:
var objectName2 = ClassName(“b”);//得到一个对象

这样objectName2得到的是什么呢?显然是方法的返回值,这里ClassName只作为了一个普通的函数(虽然首字母大写了)。但是在之前写的ClassName中并没有返回值,所以objectName2会是undifinded那么“b”赋给谁了呢?在这并没有产生一个对象,而只是单纯的执行这个方法,所以这个“b”赋值给了调用这个方法的对象window,证据如下: 
var objectName2 = ClassName(“b”);//得到一个对象 
alert(window.value);//对话框b 
所以JS中的所有function都是一样的,但是用途可能是不同的(用作构造对象抑或是执行一个过程)。 
下面该回到主题了initialize是干什么的?

代码如下:
var Class = { 
    create: function() { 
        return function() { 
            this.initialize.apply(this , arguments); 
        } 
    } 

var A = Class.create();

这段代码是构造个一个function复制给A,这个function是

复制代码 代码如下:
function() { 
    this.initialize.apply(this , arguments); 
}

并且后面这个方法是用来做构造函数的。当使用这个构造函数来构造对象的时候,会让构造出来的这个对象的initialize变量执行apply()方法,apply()的用途后面在说,继续说initialize。这样在初始化对象的时候会联系到initialize(怎么联系就要看apply的了)。 
那么

代码如下:
A.prototype={ 
    initialize:function(v){ 
        this .value=v; 
    } 
    showValue:function(){ 
        alert(this.value); 
    } 
}

是什么意思呢? 
Prototype是“原型”的意思。A是一个function(),那么A. prototype,就是function中的一个变量,其实是个对象。这个对象拥有什么方法,那么function产生的对象就拥有什么方法,故 
var a = new A(‘helloWord!'); 
a. showValue();//弹出对话框helloWord!
所以a对象也会有initialize方法,不只如此,每一个有A构造出来的对象都会有一个initialize方法,而在前面说过,构造的时候会调用构造函数,构造函数里面会让initialize去调用apply方法,于是在new A(‘helloWord!')的时候initialize回去调用apply方法。这也就是调用了一个初始化的方法。

三、 call()和apply() 
下面开始研究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对象 
这段代码能说明一切了:

代码如下:
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。

Strophe.Builder = function (name, attrs) { // Holds the tree being built. this.nodeTree = this._makeNode(name, attrs); // Points to the current operation node. this.node = this.nodeTree; }; Strophe.Builder.prototype = { /** Function: tree * Return the DOM tree. * * This function returns the current DOM tree as an element object. This * is suitable for passing to functions like Strophe.Connection.send(). * * Returns: * The DOM tree as a element object. */ tree: function () { return this.nodeTree; }, /** Function: toString * Serialize the DOM tree to a String. * * This function returns a string serialization of the current DOM * tree. It is often used internally to pass data to a * Strophe.Request object. * * Returns: * The serialized DOM tree in a String. */ toString: function () { return Strophe.serialize(this.nodeTree); }, /** Function: up * Make the current parent element the new current element. * * This function is often used after c() to traverse back up the tree. * For example, to add two children to the same element * > builder.c('child1', {}).up().c('child2', {}); * * Returns: * The Stophe.Builder object. */ up: function () { this.node = this.node.parentNode; return this; }, /** Function: attrs * Add or modify attributes of the current element. * * The attributes should be passed in object notation. This function * does not move the current element pointer. * * Parameters: * (Object) moreattrs - The attributes to add/modify in object notation. * * Returns: * The Strophe.Builder object. */ attrs: function (moreattrs) { for (var k in moreattrs) this.node.setAttribute(k, moreattrs[k]); return this; }, /** Function: c * Add a child to the current element and make it the new current * element. * * This function moves the current element pointer to the child. If you * need to add another child, it is necessary to use up() to go back * to the parent in the tree. * * Parameters: * (String) name - The name of the child. * (Object) attrs - The attributes of the child in object notation. * * Returns: * The Strophe.Builder object. */ c: function (name, attrs) { var child = this._makeNode(name, attrs); this.node.appendChild(child); this.node = child; return this; }, /** Function: cnode * Add a child to the current element and make it the new current * element. * * This function is the same as c() except that instead of using a * name and an attributes object to create the child it uses an * existing DOM element object. * * Parameters: * (XMLElement) elem - A DOM element. * * Returns: * The Strophe.Builder object. */ cnode: function (elem) { this.node.appendChild(elem); this.node = elem; return this; }, /** Function: t * Add a child text element. * * This *does not* make the child the new current element since there * are no children of text elements. * * Parameters: * (String) text - The text data to append to the current element. * * Returns: * The Strophe.Builder object. */ t: function (text) { var child = Strophe.xmlTextNode(text); this.node.appendChild(child); return this; }, /** PrivateFunction: _makeNode * _Private_ helper function to create a DOM element. * * Parameters: * (String) name - The name of the new element. * (Object) attrs - The attributes for the new element in object * notation. * * Returns: * A new DOM element. */ _makeNode: function (name, attrs) { var node = Strophe.xmlElement(name); for (var k in attrs) node.setAttribute(k, attrs[k]); return node; } }; /** PrivateClass: Strophe.Handler * _Private_ helper class for managing stanza handlers. * * A Strophe.Handler encapsulates a user provided callback function to be * executed when matching stanzas are received by the connection. * Handlers can be either one-off or persistant depending on their * return value. Returning true will cause a Handler to remain active, and * returning false will remove the Handler. * * Users will not use Strophe.Handler objects directly, but instead they * will use Strophe.Connection.addHandler() and * Strophe.Connection.deleteHandler(). */ /** PrivateConstructor: Strophe.Handler * Create and initialize a new Strophe.Handler. * * Parameters: * (Function) handler - A function to be executed when the handler is run. * (String) ns - The namespace to match. * (String) name - The element name to match. * (String) type - The element type to match. * (String) id - The element id attribute to match. * (String) from - The element from attribute to match. * * Returns: * A new Strophe.Handler object. */ Strophe.Handler = function (handler, ns, name, type, id, from) { this.handler = handler; this.ns = ns; this.name = name; this.type = type; this.id = id; this.from = from; // whether the handler is a user handler or a system handler this.user = true; }; Strophe.Handler.prototype = { /** PrivateFunction: isMatch * Tests if a stanza matches the Strophe.Handler. * * Parameters: * (XMLElement) elem - The XML element to test. * * Returns: * true if the stanza matches and false otherwise. */ isMatch: function (elem) { var nsMatch, i; nsMatch = false; if (!this.ns) { nsMatch = true; } else { var self = this; Strophe.forEachChild(elem, null, function (elem) { if (elem.getAttribute("xmlns") == self.ns) nsMatch = true; }); nsMatch = nsMatch || elem.getAttribute("xmlns") == this.ns; } if (nsMatch && (!this.name || Strophe.isTagEqual(elem, this.name)) && (!this.type || elem.getAttribute("type") == this.type) && (!this.id || elem.getAttribute("id") == this.id) && (!this.from || elem.getAttribute("from") == this.from)) { return true; } return false; }, /** PrivateFunction: run * Run the callback on a matching stanza. * * Parameters: * (XMLElement) elem - The DOM element that triggered the * Strophe.Handler. * * Returns: * A boolean indicating if the handler should remain active. */ run: function (elem) { var result = null; try { result = this.handler(elem); } catch (e) { if (e.sourceURL) { Strophe.fatal("error: " + this.handler + " " + e.sourceURL + ":" + e.line + " - " + e.name + ": " + e.message); } else if (e.fileName) { if (typeof(console) != "undefined") { console.trace(); console.error(this.handler, " - error - ", e, e.message); } Strophe.fatal("error: " + this.handler + " " + e.fileName + ":" + e.lineNumber + " - " + e.name + ": " + e.message); } else { Strophe.fatal("error: " + this.handler); } throw e; } return result; }, /** PrivateFunction: toString * Get a String representation of the Strophe.Handler object. * * Returns: * A String. */ toString: function () { return "{Handler: " + this.handler + "(" + this.name + "," + this.id + "," + this.ns + ")}"; } }; /** PrivateClass: Strophe.TimedHandler * _Private_ helper class for managing timed handlers. * * A Strophe.TimedHandler encapsulates a user provided callback that * should be called after a certain period of time or at regular * intervals. The return value of the callback determines whether the * Strophe.TimedHandler will continue to fire. * * Users will not use Strophe.TimedHandler objects directly, but instead * they will use Strophe.Connection.addTimedHandler() and * Strophe.Connection.deleteTimedHandler(). */ /** PrivateConstructor: Strophe.TimedHandler * Create and initialize a new Strophe.TimedHandler object. * * Parameters: * (Integer) period - The number of milliseconds to wait before the * handler is called. * (Function) handler - The callback to run when the handler fires. This * function should take no arguments. * * Returns: * A new Strophe.TimedHandler object. */ Strophe.TimedHandler = function (period, handler) { this.period = period; this.handler = handler; this.lastCalled = new Date().getTime(); this.user = true; }; Strophe.TimedHandler.prototype = { /** PrivateFunction: run * Run the callback for the Strophe.TimedHandler. * * Returns: * true if the Strophe.TimedHandler should be called again, and false * otherwise. */ run: function () { this.lastCalled = new Date().getTime(); return this.handler(); }, /** PrivateFunction: reset * Reset the last called time for the Strophe.TimedHandler. */ reset: function () { this.lastCalled = new Date().getTime(); }, /** PrivateFunction: toString * Get a string representation of the Strophe.TimedHandler object. * * Returns: * The string representation. */ toString: function () { return "{TimedHandler: " + this.handler + "(" + this.period +")}"; } }; /** PrivateClass: Strophe.Request * _Private_ helper class that provides a cross implementation abstraction * for a BOSH related XMLHttpRequest. * * The Strophe.Request class is used internally to encapsulate BOSH request * information. It is not meant to be used from user's code. */ /** PrivateConstructor: Strophe.Request * Create and initialize a new Strophe.Request object. * * Parameters: * (String) data - The data to be sent in the request. * (Function) func - The function that will be called when the * XMLHttpRequest readyState changes. * (Integer) rid - The BOSH rid attribute associated with this request. * (Integer) sends - The number of times this same request has been * sent. */ Strophe.Request = function (data, func, rid, sends) { this.id = ++Strophe._requestId; this.data = data; // save original function in case we need to make a new request // from this one. this.origFunc = func; this.func = func; this.rid = rid; this.date = NaN; this.sends = sends || 0; this.abort = false; this.dead = null; this.age = function () { if (!this.date) return 0; var now = new Date(); return (now - this.date) / 1000; }; this.timeDead = function () { if (!this.dead) return 0; var now = new Date(); return (now - this.dead) / 1000; }; this.xhr = this._newXHR(); }; Strophe.Request.prototype = { /** PrivateFunction: getResponse * Get a response from the underlying XMLHttpRequest. * * This function attempts to get a response from the request and checks * for errors. * * Throws: * "parsererror" - A parser error occured. * * Returns: * The DOM element tree of the response. */ getResponse: function () { var node = null; if (this.xhr.responseXML && this.xhr.responseXML.documentElement) { node = this.xhr.responseXML.documentElement; if (node.tagName == "parsererror") { Strophe.error("invalid response received"); Strophe.error("responseText: " + this.xhr.responseText); Strophe.error("responseXML: " + Strophe.serialize(this.xhr.responseXML)); throw "parsererror"; } } else if (this.xhr.responseText) { Strophe.error("invalid response received"); Strophe.error("responseText: " + this.xhr.responseText); Strophe.error("responseXML: " + Strophe.serialize(this.xhr.responseXML)); } return node; }, /** PrivateFunction: _newXHR * _Private_ helper function to create XMLHttpRequests. * * This function creates XMLHttpRequests across all implementations. * * Returns: * A new XMLHttpRequest. */ _newXHR: function () { var xhr = null; if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); if (xhr.overrideMimeType) { xhr.overrideMimeType("text/xml"); } } else if (window.ActiveXObject) { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } xhr.onreadystatechange = this.func.prependArg(this); return xhr; } };
最新发布
08-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值