Prototype Function对象 学习


Posted in Javascript onJuly 12, 2009

这个对象就是对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!'
Javascript 相关文章推荐
Jquery 插件开发笔记整理
Jan 17 Javascript
js导航菜单(自写)简单大方
Mar 28 Javascript
input输入框鼠标焦点提示信息
Mar 17 Javascript
一看就懂:jsonp详解
Jun 01 Javascript
基于JavaScript如何实现私有成员的语法特征及私有成员的实现方式
Oct 28 Javascript
Bootstrap每天必学之折叠(Collapse)插件
Apr 25 Javascript
微信小程序 教程之注册程序
Oct 17 Javascript
微信小程序 功能函数小结(手机号验证*、密码验证*、获取验证码*)
Dec 08 Javascript
vue组件的写法汇总
Apr 12 Javascript
JavaScript使用indexOf()实现数组去重的方法分析
Sep 04 Javascript
JavaScript 预解析的4种实现方法解析
Sep 03 Javascript
js面向对象之实现淘宝放大镜
Jan 15 Javascript
Prototype Object对象 学习
Jul 12 #Javascript
Prototype 学习 工具函数学习($w,$F方法)
Jul 12 #Javascript
Prototype 学习 工具函数学习($A方法)
Jul 12 #Javascript
Prototype 学习 工具函数学习($方法)
Jul 12 #Javascript
Prototype 学习 Prototype对象
Jul 12 #Javascript
javascript 动态加载 css 方法总结
Jul 11 #Javascript
checkbox 复选框不能为空
Jul 11 #Javascript
You might like
php面向对象全攻略 (十一)__toString()用法 克隆对象 __call处理调用错误
2009/09/30 PHP
关于ob_get_contents(),ob_end_clean(),ob_start(),的具体用法详解
2013/06/24 PHP
PHP实现JS中escape与unescape的方法
2016/07/11 PHP
Laravel如何创建服务器提供者实例代码
2019/04/15 PHP
php实现QQ小程序发送模板消息功能
2019/09/18 PHP
php ActiveMQ的安装与使用方法图文教程
2020/02/23 PHP
根据出生日期自动取得星座的js代码
2010/07/20 Javascript
javascript中将Object转换为String函数代码 (json str)
2012/04/29 Javascript
JS实现5秒钟自动封锁div层的方法
2015/02/20 Javascript
分析了一下JQuery中的extend方法实现原理
2015/02/27 Javascript
JS原型与原型链的深入理解
2017/02/15 Javascript
详解angularJs指令的3种绑定策略
2017/04/13 Javascript
vue2.0 自定义日期时间过滤器
2017/06/07 Javascript
JS查找数组中重复元素的方法详解
2017/06/14 Javascript
Node.js + express基本用法教程
2019/03/14 Javascript
简单说说如何使用vue-router插件的方法
2019/04/08 Javascript
Vue列表如何实现滚动到指定位置样式改变效果
2020/05/09 Javascript
[03:41]2018完美盛典-《Fight With Us》
2018/12/16 DOTA
详解在Python中处理异常的教程
2015/05/24 Python
django框架如何集成celery进行开发
2017/05/24 Python
Python实现比较扑克牌大小程序代码示例
2017/12/06 Python
python使用PIL实现多张图片垂直合并
2019/01/15 Python
python实现dijkstra最短路由算法
2019/01/17 Python
python实现比对美团接口返回数据和本地mongo数据是否一致示例
2019/08/09 Python
Python 中由 yield 实现异步操作
2020/05/04 Python
Python爬虫之Spider类用法简单介绍
2020/08/04 Python
有关HTML5 Video对象的ontimeupdate事件(Chrome上无效)的问题
2013/07/19 HTML / CSS
巴西美妆购物网站:Kutiz Beauté
2019/03/13 全球购物
师范毕业生自荐信
2013/10/17 职场文书
教师申诉制度
2014/01/29 职场文书
2015年个人审计工作总结
2015/04/07 职场文书
乡镇党建工作总结2015
2015/05/19 职场文书
喋血孤城观后感
2015/06/08 职场文书
三八节祝酒词
2015/08/11 职场文书
2015年六年级班主任工作总结
2015/10/15 职场文书
标准版个人借条怎么写?以及什么是借条?
2019/08/28 职场文书