Prototype Function对象 学习_prototype

这个对象就是对function的一些扩充,最重要的当属bind方法,prototype的帮助文档上特意说了一句话:Prototype takes issue with only one aspect of functions: binding.其中wrap方法也很重要,在类继承机制里面就是利用wrap方法来调用父类的同名方法。
argumentNames
bind
bindAsEventListener
curry
defer
delay
methodize
wrap

复制代码 代码如下:

//通过Object对象的extend方法对Function的prototype进行扩展
Object.extend(Function.prototype, (function() {
var slice = Array.prototype.slice;
//把args添加到array后面,并返回array,内部方法
function update(array, args) {
var arrayLength = array.length, length = args.length;
while (length--) array[arrayLength + length] = args[length];
return array;
}
//基本和update方法一样,但是不改变传入参数array,返回一个新的array
function merge(array, args) {
array = slice.call(array, 0);
return update(array, args);
}
//把函数的参数格式化成数组,并返回
function argumentNames() {
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
.replace(/\s+/g, '').split(',');

return names.length == 1 && !names[0] ? [] : names;
}
//把执行函数的上下文绑定到context
function bind(context) {
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
var __method = this, args = slice.call(arguments, 1);
return function() {
var a = merge(args, arguments);
return __method.apply(context, a);
}
}
//基本和bind差不多,就是保证传入的第一个参数一定是event对象
function bindAsEventListener(context) {
var __method = this, args = slice.call(arguments, 1);
return function(event) {
var a = update([event || window.event], args);
return __method.apply(context, a);
}
}
//curry是一个数学家的名字,这个方法的作用就是可以连续的传入参数,看下面的具体例子就知道了
function curry() {
if (!arguments.length) return this;
var __method = this, args = slice.call(arguments, 0);
return function() {
var a = merge(args, arguments);
return __method.apply(this, a);
}
}
//window.setTimeout函数的简单封装
function delay(timeout) {
var __method = this, args = slice.call(arguments, 1);
timeout = timeout * 1000
return window.setTimeout(function() {
return __method.apply(__method, args);
}, timeout);
}
//相当于delay(0.01)
function defer() {
var args = update([0.01], arguments);
return this.delay.apply(this, args);
}
//用wrapper包装将要调用的函数,实现了简单的AOP功能
function wrap(wrapper) {
var __method = this;
return function() {
var a = update([__method.bind(this)], arguments);
return wrapper.apply(this, a);
}
}
//把当前上下文作为第一个参数显示的传入调用的方法
function methodize() {
if (this._methodized) return this._methodized;
var __method = this;
return this._methodized = function() {
var a = update([this], arguments);
return __method.apply(null, a);
};
}
//返回外部可调用的函数
return {
argumentNames: argumentNames,
bind: bind,
bindAsEventListener: bindAsEventListener,
curry: curry,
delay: delay,
defer: defer,
wrap: wrap,
methodize: methodize
}
})());

update,merge方法:由于是内部方法,就不详细说了,看源代码基本上能看懂
argumentNames方法:
基本就是利用正则表达式提出方法里面的参数列表,并且删除空格和一些特殊字符,然后用','进行分割,最后返回参数数组,我不明白最后返回 names.length == 1 这个条件有什么用?我试了试,去了也没什么影响,知道的告诉我一下。下面看一下示例:

复制代码 代码如下:

var fn = function(foo, bar) { return foo + bar; };
fn.argumentNames(); //-> ['foo', 'bar']
Prototype.emptyFunction.argumentNames(); //-> []

bind方法:
首先判断传进来的参数个数,至少要传进来一个context参数,如果直接调用bind()方法,那么将返回原来的函数对象。就相当于没调用一样。
bind方法的原型是这样的:bind(thisObj[, arg...]) -> Function,第一个参数后面可以跟可选的参数,在bind方法里面用args变量存储了除了第一个参数之外的所有其它参数:args = slice.call(arguments, 1);
var __method = this,这句话的意思是把__method变量设为当前的函数,通过例子说明更清楚些:

复制代码 代码如下:

var obj = {
name: 'A nice demo',
fx: function() { alert(this.name); }
};
window.name = 'I am such a beautiful window!';
function runFx(f) { f(); }
//其中__method就相当于obj.fx
var fx2 = obj.fx.bind(obj);
runFx(obj.fx); //I am such a beautiful window!
runFx(fx2); //A nice demo
/*
这里如果我们不在runFx函数里面调用f(),而是直接在外面调用obj.fx()那么得到的结果将是'A nice demo'。
其实如果我们这样写:var f=obj.fx;f();那也将得到‘I am such a beautiful window!'。
通过上面的例子,我们应该能看出上下文的概念:
obj.fx(); //上下文为:obj
f(); //上下文为:window
可以看出上下文其实就是最后一个'.'之前的那个对象,如果直接调用函数则上下文为window
*/

最后返回一个应用于context上下文的匿名函数。
注意:var a = merge(args, arguments);这句话里面的arguments和args = slice.call(arguments, 1);里面的arguments是不一样的。看一下例子:

复制代码 代码如下:

var obj = {
name: 'A nice demo',
fx: function() {
alert(this.name + '\n' + $A(arguments).joi(', '));
}
};
//这里的[1,2,3]就是slice.call(arguments, 1);里面的arguments
var fx2 = obj.fx.bind(obj, 1, 2, 3);
//这里的[4,5]就是merge(args, arguments);里面的arguments
fx2(4, 5);
// Alerts the proper name, then "1, 2, 3, 4, 5"

bindAsEventListener方法:
这个方法和bind差不多,最主要差别在这句:var a = update([event || window.event], args);总是保证绑定的函数第一个参数为event对象。看一下示例:

复制代码 代码如下:

var obj = { name: 'A nice demo' };
function handler(e) {
var data = $A(arguments);
data.shift();
alert(this.name + '\nOther args: ' + data.join(', ')); }
handler.bindAsEventListener(obj, 1, 2, 3);
//=======================
<input type="button" value="button" onclick="handle()" />

curry方法:
这个方法的个人觉得帮助文档上给的例子不好,下面给出另一个示例,一看就明白了:

复制代码 代码如下:

var F=function(){alert(Array.prototype.slice.call(arguments,0).join(' '))};
F.curry('I').curry('am').curry('never-online').curry('http://www.never-online.net')();
//I am never-online http://www.never-online.net

delay和defer方法:
基本就是window.setTimeout的简单封装,时间单位为秒,看一下示例:

复制代码 代码如下:

// clearing a timeout
var id = Element.hide.delay(5, 'foo');
window.clearTimeout(id);

wrap方法:
Returns a function “wrapped” around the original function.
Function#wrap distills the essence of aspect-oriented programming into a single method, letting you easily build on existing functions by specifying before and after behavior, transforming the return value, or even preventing the original function from being called.
这句话:var a = update([__method.bind(this)], arguments);的意思就是把被包装的函数当作第一个参数传入包装函数,看一下示例:

复制代码 代码如下:

function wrapped(){
alert('wrapped');
}
//可以在wrapper之前调用原函数或者之后调用,是不是有点AOP的意思了
var wrapper=wrapped.wrap(function(oldFunc,param){
    //oldFunc()
    alert(param);
    oldFunc();
});

//wrapper,wrapped
wrapper("wrapper");

methodize方法:
Takes a function and wraps it in another function that, at call time,
pushes this to the original function as the first argument.
这个方法先检查将要被methodize的方法是否已经methodize过了,通过内部的变量this._methodized做检查,
最后methodize函数返回的其实就是this._methodized。
这句话:var a = update([this], arguments);是关键,可以看出把this当成第一个参数传到这个原始函数中了。看一下示例就明白了:

复制代码 代码如下:

// start off with a simple function that does an operation
// on the target object:
var fn = function(target, foo) { target.value = foo; }; var object = {};
// 原始的方法
fn(object, 'bar');
object.value //-> 'bar'
//调用methodize之后,可以看出fn函数第一个参数target变成了object
object.fnMethodized = fn.methodize();
object.fnMethodized('boom!');
object.value //-> 'boom!'

时间: 2024-09-14 19:16:01

Prototype Function对象 学习_prototype的相关文章

Prototype Class对象学习_prototype

复制代码 代码如下: /* Based on Alex Arnell's inheritance implementation. */ var Class = (function() { //临时存储parent的prototype function subclass() {}; //创建类的方法 function create() { var parent = null, properties = $A(arguments);     //检查新建一个类时,是否指定了一个父对象     //如

Prototype Number对象 学习_prototype

复制代码 代码如下: Object.extend(Number.prototype, (function() { //返回十六进制颜色之     function toColorPart() { return this.toPaddedString(2, 16); } //返回连续的下一个数值 function succ() { return this + 1; } //连续执行某个操作 function times(iterator, context) { $R(0, this, true).

Prototype Selector对象学习_prototype

复制代码 代码如下: function $$() { return Selector.findChildElements(document, $A(arguments)); } 这个类可以分成三个部分:第一个部分就是根据不同的浏览器,判断使用什么DOM操作方法.其中操作IE就是用普通的getElementBy* 系列方法:FF是document.evaluate:Opera和Safari是selectorsAPI.第二部分是对外提供的基本函数,像findElements,match等,Eleme

Prototype Object对象 学习_prototype

Object is used by Prototype as a namespace; that is, it just keeps a few new methods together, which are intended for namespaced access (i.e. starting with "Object."). 上面说的namespace个人理解就相当于C#中的静态类,提供工具函数的意思,和C#中的namespace应该不是一个概念.因为C#中的命名空间后面不会直

Prototype ObjectRange对象学习_prototype

Ranges represent an interval of values. The value type just needs to be "compatible," that is, to implement a succ method letting us step from one value to the next (its successor). Prototype provides such a method for Number and String, but you

Prototype Array对象 学习_prototype

复制代码 代码如下: Array.from = $A; (function() { //Array原型的引用     var arrayProto = Array.prototype, slice = arrayProto.slice,      //JS 1.6里面会有原生的forEach方法 _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available function each(it

Prototype Template对象 学习_prototype

复制代码 代码如下: var Template = Class.create({ //初始化方法 initialize: function(template, pattern) { this.template = template.toString(); this.pattern = pattern || Template.Pattern; }, //格式化方法,如果从java的角度来说,其实叫format更好 :) evaluate: function(object) {     //检查是否

Prototype Hash对象 学习_prototype

复制代码 代码如下: //Hash对象的工具函数 function $H(object) { return new Hash(object); }; var Hash = Class.create(Enumerable, (function() { //初始化,创建一个新的Hash对象 function initialize(object) { this._object = Object.isHash(object) ? object.toObject() : Object.clone(obje

Prototype Date对象 学习_prototype

看一下源码: 复制代码 代码如下: Date.prototype.toJSON = function() { return '"' + this.getUTCFullYear() + '-' + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + this.getUTCDate().toPaddedString(2) + 'T' + this.getUTCHours().toPaddedString(2) + ':' + this.getUTCM