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实现简单的页面右下角提示信息框
Jul 31 Javascript
JQuery导航菜单选择特效
Apr 11 Javascript
jQuery判断元素是否显示 是否隐藏的简单实现代码
May 19 Javascript
微信小程序--组件(swiper)详细介绍
Jun 13 Javascript
vue 将页面公用的头部组件化的方法
Dec 18 Javascript
angularjs使用gulp-uglify压缩后执行报错的解决方法
Mar 07 Javascript
vue实现底部菜单功能
Jul 24 Javascript
vue axios数据请求get、post方法及实例详解
Sep 11 Javascript
微信小程序实现手势滑动卡片效果
Aug 26 Javascript
js之切换全屏和退出全屏实现代码实例
Sep 09 Javascript
Typescript的三种运行方式(小结)
Sep 18 Javascript
vue输入节流,避免实时请求接口的实例代码
Oct 30 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下使用SMTP发邮件的代码
2008/01/10 PHP
php ignore_user_abort与register_shutdown_function 使用方法
2009/06/14 PHP
解析php二分法查找数组是否包含某一元素
2013/05/23 PHP
PHP使用array_multisort对多个数组或多维数组进行排序
2014/12/16 PHP
PHP中加速、缓存扩展的区别和作用详解(eAccelerator、memcached、xcache、APC )
2016/07/09 PHP
PHP针对伪静态的注入总结【附asp与Python相关代码】
2017/08/01 PHP
PHP实现微信退款功能
2018/10/02 PHP
Laravel5.1 框架表单验证操作实例详解
2020/01/07 PHP
yii 框架实现按天,月,年,自定义时间段统计数据的方法分析
2020/04/04 PHP
jQuery 顺便学习下CSS选择器 奇偶匹配nth-child(even)
2010/05/24 Javascript
Javascript创建自定义对象 创建Object实例添加属性和方法
2012/06/04 Javascript
javascript删除字符串最后一个字符
2014/01/14 Javascript
jquery通过ajax加载一段文本内容的方法
2015/01/15 Javascript
JavaScript实现页面5秒后自动跳转的方法
2015/04/16 Javascript
jquery实现动画菜单的左右滚动、渐变及图形背景滚动等效果
2015/08/25 Javascript
JavaScript数组实现数据结构中的队列与堆栈
2016/05/26 Javascript
bootstrapValidator bootstrap-select验证不可用的解决办法
2017/01/11 Javascript
Angularjs自定义指令实现三级联动 选择地理位置
2017/02/13 Javascript
详解vue.js 开发环境搭建最简单攻略
2017/06/12 Javascript
详谈表单格式化插件jquery.serializeJSON
2017/06/23 jQuery
基于vue打包后字体和图片资源失效问题的解决方法
2018/03/06 Javascript
JS+CSS实现炫酷光感效果
2020/09/05 Javascript
[36:14]DOTA2上海特级锦标赛D组小组赛#1 EG VS COL第二局
2016/02/28 DOTA
详谈Python基础之内置函数和递归
2017/06/21 Python
更换Django默认的模板引擎为jinja2的实现方法
2018/05/28 Python
Python生成器generator用法示例
2018/08/10 Python
python中正则表达式与模式匹配
2019/05/07 Python
Python+PyQT5的子线程更新UI界面的实例
2019/06/14 Python
安装完Python包然后找不到模块的解决步骤
2020/02/13 Python
纯CSS3实现绘制各种图形实现代码详细整理
2012/12/26 HTML / CSS
AmazeUI 缩略图的实现示例
2020/08/18 HTML / CSS
英国定做窗帘和纺织品面料一站式商店:Dekoria
2018/08/29 全球购物
Otticanet英国:最顶尖的世界名牌眼镜, 能得到打折季的价格
2019/02/10 全球购物
工程力学专业自荐信范文
2014/03/17 职场文书
初中学生操行评语
2014/12/26 职场文书
创业项目大全(适合在家创业的项目)
2019/08/15 职场文书