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 相关文章推荐
在第一个input框内输入内容.textarea自动得到第一个文件框的值的javascript代码
Apr 20 Javascript
ExtJS 入门
Oct 29 Javascript
jquery快捷动态绑定键盘事件的操作函数代码
Oct 17 Javascript
Js判断CSS文件加载完毕的具体实现
Jan 17 Javascript
一系列Bootstrap导航条使用方法分享
Apr 29 Javascript
javascript阻止事件冒泡和浏览器的默认行为
Jan 21 Javascript
从零学习node.js之mysql数据库的操作(五)
Feb 24 Javascript
详解webpack编译多页面vue项目的配置问题
Dec 11 Javascript
Vue入门之数量加减运算操作示例
Dec 11 Javascript
微信小程序当前时间时段选择器插件使用方法详解
Dec 28 Javascript
Node4-5静态资源服务器实战以及优化压缩文件实例内容
Aug 29 Javascript
javascript函数式编程基础
Sep 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目录导航文件代码
2006/10/09 PHP
提高define性能的php扩展hidef的安装和使用
2011/06/14 PHP
LotusPhp笔记之:Cookie组件的使用详解
2013/05/06 PHP
php上传文件并存储到mysql数据库的方法
2015/03/16 PHP
一个简单安全的PHP验证码类 附调用方法
2016/06/24 PHP
golang与PHP输出excel示例
2016/07/22 PHP
JavaScript 学习历程和心得分享
2010/12/12 Javascript
js实现在字符串中提取数字
2013/11/05 Javascript
JavaScript实现简单获取当前网页网址的方法
2015/11/09 Javascript
Vue数据驱动模拟实现1
2017/01/11 Javascript
基于Bootstrap的网页设计实例
2017/03/01 Javascript
JS排序之选择排序详解
2017/04/08 Javascript
jqgrid实现简单的单行编辑功能
2017/09/30 Javascript
实例分析JS与Node.js中的事件循环
2017/12/12 Javascript
使用classList来实现两个按钮样式的切换方法
2018/01/24 Javascript
webpack4 SplitChunks实现代码分隔详解
2019/05/23 Javascript
简谈创建React Component的几种方式
2019/06/15 Javascript
js实现数字跳动到指定数字
2020/08/25 Javascript
vue-axios同时请求多个接口 等所有接口全部加载完成再处理操作
2020/11/09 Javascript
Python MD5加密实例详解
2017/08/02 Python
python操作MySQL 模拟简单银行转账操作
2017/09/27 Python
Python使用zip合并相邻列表项的方法示例
2018/03/17 Python
Ubuntu16.04/树莓派Python3+opencv配置教程(分享)
2018/04/02 Python
使用python读取txt文件的内容,并删除重复的行数方法
2018/04/18 Python
Python函数式编程指南:对生成器全面讲解
2019/11/19 Python
python 经典数字滤波实例
2019/12/16 Python
Python logging模块handlers用法详解
2020/08/14 Python
CSS3实现div从下往上滑入滑出效果示例
2020/04/28 HTML / CSS
Sephora丝芙兰澳洲官方网站:国际知名化妆品购物
2016/10/27 全球购物
大学生职业生涯规划范文——找准自我,定位人生
2014/01/23 职场文书
政府四风问题整改措施
2014/10/04 职场文书
党员批评与自我批评思想汇报
2014/10/08 职场文书
应届毕业生求职简历自我评价
2015/03/02 职场文书
年度考核登记表个人总结
2015/03/06 职场文书
关于分班的感言
2015/08/04 职场文书
三年级作文之趣事作文
2019/11/04 职场文书