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 相关文章推荐
XMLHttpRequest Level 2 使用指南
Aug 26 Javascript
jQuery利用sort对DOM元素进行排序操作
Nov 07 Javascript
深入理解JS继承和原型链的问题
Dec 17 Javascript
微信小程序中做用户登录与登录态维护的实现详解
May 17 Javascript
详解vuex 中的 state 在组件中如何监听
May 23 Javascript
详解用webpack把我们的业务模块分开打包的方法
Jul 20 Javascript
利用JavaScript的%做隔行换色的实例
Nov 25 Javascript
elementui的默认样式修改方法
Feb 23 Javascript
微信小程序公用参数与公用方法用法示例
Jan 09 Javascript
发布订阅模式在vue中的实际运用实例详解
Jun 09 Javascript
策略模式实现 Vue 动态表单验证的方法
Sep 16 Javascript
基于layui框架响应式布局的一些使用详解
Sep 16 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
smarty模板嵌套之include与fetch性能测试
2010/12/05 PHP
基于wordpress主题制作的具体实现步骤
2013/05/10 PHP
PHP框架Laravel中实现supervisor执行异步进程的方法
2017/06/07 PHP
php 中的closure用法详解
2017/06/12 PHP
Smarty模板配置实例简析
2019/07/20 PHP
javascript document.execCommand() 常用解析
2009/12/14 Javascript
锋利的jQuery 要点归纳(一) jQuery选择器
2010/03/21 Javascript
qTip 基于JQuery的Tooltip插件[兼容性好]
2010/09/01 Javascript
javascript基础知识大集锦(二) 推荐收藏
2011/01/13 Javascript
通过jquery还原含有rowspan、colspan的table的实现方法
2012/02/10 Javascript
javascript间隔刷新的简单实例
2013/11/14 Javascript
JavaScript中判断页面关闭、页面刷新的实现代码
2014/08/27 Javascript
JavaScript日期类型的一些用法介绍
2015/03/02 Javascript
Underscore之Array_动力节点Java学院整理
2017/07/10 Javascript
开发一个Parcel-vue脚手架工具(详细步骤)
2018/09/22 Javascript
解决vue组件没显示,没起作用,没报错,但该显示的组件没显示问题
2020/09/02 Javascript
antd-DatePicker组件获取时间值,及相关设置方式
2020/10/27 Javascript
[06:59]DOTA2-DPC中国联赛3月7日Recap集锦
2021/03/11 DOTA
python使用arcpy.mapping模块批量出图
2017/03/06 Python
Python简单网络编程示例【客户端与服务端】
2017/05/26 Python
python爬取拉勾网职位数据的方法
2018/01/24 Python
解决Python pandas df 写入excel 出现的问题
2018/07/04 Python
如何用python处理excel表格
2020/06/09 Python
浅谈keras 的抽象后端(from keras import backend as K)
2020/06/16 Python
keras的load_model实现加载含有参数的自定义模型
2020/06/22 Python
Python利用Faiss库实现ANN近邻搜索的方法详解
2020/08/03 Python
python rsa-oaep加密的示例代码
2020/09/23 Python
世界上最好的精品店:Shoptiques
2018/02/05 全球购物
网站设计师的岗位职责
2013/11/21 职场文书
讲座主持词
2014/03/20 职场文书
ktv周年庆活动方案
2014/08/18 职场文书
社区六一儿童节活动总结
2015/02/11 职场文书
明确岗位职责
2015/02/14 职场文书
建筑质检员岗位职责
2015/04/08 职场文书
督导岗位职责范本
2015/04/10 职场文书
孔子观后感
2015/06/08 职场文书