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 相关文章推荐
JavaScript词法作用域与调用对象深入理解
Nov 29 Javascript
Extjs中ComboBoxTree实现的下拉框树效果(自写)
May 28 Javascript
javascript确认框的三种使用方法
Dec 17 Javascript
使用js操作css实现js改变背景图片示例
Mar 10 Javascript
封装了一个支持匿名函数的Javascript事件监听器
Jun 05 Javascript
js实现按一下删除键删除整个单词附demo
Sep 05 Javascript
js限制文本框的输入内容代码分享(3类)
Aug 20 Javascript
深入分析Javascript事件代理
Jan 30 Javascript
使用postMesssage()实现跨域iframe页面间的信息传递方法
Mar 29 Javascript
JavaScript操作表单实例讲解(上)
Jun 20 Javascript
自定义vue全局组件use使用、vuex的使用详解
Jun 14 Javascript
Vue学习笔记之表单输入控件绑定
Sep 05 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自动获取目录下的模板的代码
2010/08/08 PHP
2014年最新推荐的10款 PHP 开发框架
2014/08/01 PHP
php+mysql查询优化简单实例
2015/01/13 PHP
教大家制作简单的php日历
2015/11/17 PHP
我整理的PHP 7.0主要新特性
2016/01/07 PHP
详解php协程知识点
2018/09/21 PHP
JavaScript Archive Network 集合
2007/05/12 Javascript
更正确的asp冒泡排序
2007/05/24 Javascript
eval与window.eval的差别分析
2011/03/17 Javascript
解决js数据包含加号+通过ajax传到后台时出现连接错误
2013/08/01 Javascript
javascript中$(function() {});写与不写有哪些区别
2015/08/10 Javascript
JavaScript常用基础知识强化学习
2015/12/09 Javascript
jQuery动态增减行的实例代码解析(推荐)
2016/12/05 Javascript
Javascript中JSON数据分组优化实践及JS操作JSON总结
2017/12/22 Javascript
基于Angularjs-router动态改变Title值的问题
2018/08/30 Javascript
微信小程序map组件结合高德地图API实现wx.chooseLocation功能示例
2019/01/23 Javascript
koa大型web项目中使用路由装饰器的方法示例
2019/04/02 Javascript
优雅地使用loading(推荐)
2019/04/20 Javascript
layui 数据表格+分页+搜索+checkbox+缓存选中项数据的方法
2019/09/21 Javascript
解决qrcode.js生成二维码时必须定义一个空div的问题
2020/07/09 Javascript
[32:07]完美世界DOTA2联赛PWL S3 LBZS vs Rebirth 第一场 12.16
2020/12/17 DOTA
python基础教程之类class定义使用方法
2014/02/20 Python
实例说明Python中比较运算符的使用
2015/05/13 Python
python 使用get_argument获取url query参数
2017/04/28 Python
基于python3 的百度图片下载器的实现代码
2019/11/05 Python
python通过链接抓取网站详解
2019/11/20 Python
Windows+Anaconda3+PyTorch+PyCharm的安装教程图文详解
2020/04/03 Python
快速解决Django关闭Debug模式无法加载media图片与static静态文件
2020/04/07 Python
xadmin使用formfield_for_dbfield函数过滤下拉表单实例
2020/04/07 Python
python中列表的含义及用法
2020/05/26 Python
Stubhub英国:购买体育、演唱会和剧院门票
2018/06/10 全球购物
Linux面试题LINUX系统类
2015/11/25 面试题
工作期间打牌检讨书范文
2014/11/20 职场文书
2015国庆节66周年标语
2015/07/30 职场文书
django 认证类配置实现
2021/11/11 Python
Spring Bean是如何初始化的详解
2022/03/22 Java/Android