这个对象就是对function的一些扩充,最重要的当属bind方法,prototype的帮助文档上特意说了一句话:Prototype takes issue with only one aspect of functions: binding.其中wrap方法也很重要,在类继承机制里面就是利用wrap方法来调用父类的同名方法。

argumentNames bind bindAsEventListener curry defer delay methodize wrap

view plaincopy to clipboardprint?

//通过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 } })());

//通过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 这个条件有什么用?我试了试,去了也没什么影响,知道的告诉我一下。下面看一下示例:

view plaincopy to clipboardprint?
  1. var fn = function(foo, bar) { return foo + bar; };
  2. fn.argumentNames(); //-> ['foo', 'bar']
  3. Prototype.emptyFunction.argumentNames(); //-> []

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变量设为当前的函数,通过例子说明更清楚些:

view plaincopy to clipboardprint?
  1. var obj = {
  2. name: 'A nice demo',
  3. fx: function() { alert(this.name); }
  4. };
  5. window.name = 'I am such a beautiful window!';
  6. function runFx(f) { f(); }
  7. //其中__method就相当于obj.fx
  8. var fx2 = obj.fx.bind(obj);
  9. runFx(obj.fx); //I am such a beautiful window!
  10. runFx(fx2); //A nice demo
  11. /*
  12. 这里如果我们不在runFx函数里面调用f(),而是直接在外面调用obj.fx()那么得到的结果将是'A nice demo'。
  13. 其实如果我们这样写:var f=obj.fx;f();那也将得到‘I am such a beautiful window!’。
  14. 通过上面的例子,我们应该能看出上下文的概念:
  15. obj.fx(); //上下文为:obj
  16. f(); //上下文为:window
  17. 可以看出上下文其实就是最后一个'.'之前的那个对象,如果直接调用函数则上下文为window
  18. */

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是不一样的。看一下例子:

view plaincopy to clipboardprint?
  1. var obj = {
  2. name: 'A nice demo',
  3. fx: function() {
  4. alert(this.name + '\n' + $A(arguments).joi(', '));
  5. }
  6. };
  7. //这里的[1,2,3]就是slice.call(arguments, 1);里面的arguments
  8. var fx2 = obj.fx.bind(obj, 1, 2, 3);
  9. //这里的[4,5]就是merge(args, arguments);里面的arguments
  10. fx2(4, 5);
  11. // Alerts the proper name, then "1, 2, 3, 4, 5"

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对象。看一下示例:

view plaincopy to clipboardprint?
  1. var obj = { name: 'A nice demo' };
  2. function handler(e) {
  3. var data = $A(arguments);
  4. data.shift();
  5. alert(this.name + '\nOther args: ' + data.join(', ')); }
  6. handler.bindAsEventListener(obj, 1, 2, 3);
  7. //=======================
  8. "button" value="button" οnclick="handle()" />

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" οnclick="handle()" />

curry方法:

这个方法的个人觉得帮助文档上给的例子不好,下面给出另一个示例,一看就明白了:

view plaincopy to clipboardprint?
  1. var F=function(){alert(Array.prototype.slice.call(arguments,0).join(' '))};
  2. F.curry('I').curry('am').curry('never-online').curry('http://www.never-online.net')();
  3. //I am never-online http://www.never-online.net

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的简单封装,时间单位为秒,看一下示例:

view plaincopy to clipboardprint?
  1. // clearing a timeout
  2. var id = Element.hide.delay(5, 'foo');
  3. window.clearTimeout(id);

// 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);的意思就是把被包装的函数当作第一个参数传入包装函数,看一下示例:

view plaincopy to clipboardprint?
  1. function wrapped(){
  2. alert('wrapped');
  3. }
  4. //可以在wrapper之前调用原函数或者之后调用,是不是有点AOP的意思了
  5. var wrapper=wrapped.wrap(function(oldFunc,param){
  6. //oldFunc()
  7. alert(param);
  8. oldFunc();
  9. });
  10. //wrapper,wrapped
  11. wrapper("wrapper");

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当成第一个参数传到这个原始函数中了。看一下示例就明白了:

view plaincopy to clipboardprint?
  1. // start off with a simple function that does an operation
  2. // on the target object:
  3. var fn = function(target, foo) { target.value = foo; }; var object = {};
  4. // 原始的方法
  5. fn(object, 'bar');
  6. object.value //-> 'bar'
  7. //调用methodize之后,可以看出fn函数第一个参数target变成了object
  8. object.fnMethodized = fn.methodize();
  9. object.fnMethodized('boom!');
  10. object.value //-> 'boom!'

// 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!'

转载于:https://www.cnblogs.com/orez88/articles/1534197.html

Prototype 学习——Function对象相关推荐

  1. 【JavaScript框架封装】使用Prototype给Array,String,Function对象的方法扩充

    版权声明:本文为博主原创文章,未经博主允许不得转载.更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/ ...

  2. javascript学习之对象基础

    2019独角兽企业重金招聘Python工程师标准>>> javascript学习之对象基础 面向对象语言 面向对象语言需要向开发者提供四种基本能力 封装:把相关信息(数据和方法)存储 ...

  3. prototype是原型对象,那__proto__又是什么呢,总不能是别名吧?

    做过前端的都知道,两个必会的知识就是原型和原型链,如果有人问你,原型是什么?你是不是回答对象中都有一个默认的属性叫prototype,指向的就是原型.如果再追问你,那原型链是什么呢?你是不是回答如果在 ...

  4. 关于JavaScript的Prototype及原型对象的理解

    学习JavaScript时,就一定会涉及到两个概念–prototype,原型对象.自己在做项目时可能无意中使用到,但是却没有真正去了解这个东西,在学会使用的基础上,进一步去理解它会帮助自己吸收到更多不 ...

  5. JavaScript学习笔记——对象知识点

    javascript对象的遍历.内存分布和封装特性 一.javascript对象遍历 1.javascript属性访问 对象.属性 对象[属性] //字符串格式 //javascript属性的访问方法 ...

  6. JavaScript之面向对象学习四原型对象的动态性

    1.由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反映出来---即便是先创建了实例后修改原型也是如此.代码如下: function Person(){ } va ...

  7. 深度学习之对象检测_深度学习时代您应该阅读的12篇文章,以了解对象检测

    深度学习之对象检测 前言 (Foreword) As the second article in the "Papers You Should Read" series, we a ...

  8. JS中函数的prototype属性和对象的__proto__属性

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  9. 【JavaScript高级教程】JavaScript prototype(原型对象)

    所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法. function Person(first, last, age, eyecolor) {this.fi ...

最新文章

  1. 主成分分析(PCA)Python代码实现
  2. 赵本山:我的时代还没有结束 | Python告诉你
  3. 这篇文章说出了研究生和导师的相处真谛……
  4. angularjs html编辑器,AngularJS集成wangeditor富文本编辑器
  5. java(i++和++i的理解)
  6. python读取文件最后几行_如何用python获取文件的最后一行,文件可能会比较大
  7. kmap_atomic的细节以及改进
  8. mysql 5.6 主主复制_Percona MySQL 5.6 主主复制环境报错Got fatal error 1236 from master.....
  9. idea报错快捷键_idea快捷键总结
  10. dubbo的工作原理
  11. 这6款APP和游戏,是苹果选出的2019年年度最佳
  12. 无人驾驶虚拟仿真(四)--通过ROS系统控制小车行走
  13. 教你如何使用关键词获取淘宝和天猫的商品信息
  14. 山水之道第五境——精灵的天地大阵
  15. LR之识别图片验证码
  16. 电影文件长长的文件名是这个意思
  17. 在C/C++中调用LUA脚本简介
  18. git 配置origin_在VS CODE中配置使用Git
  19. pytorch环境配置 一键官网配置+离线配置(anaconda+duda+cudnn+pytorch)
  20. vue实现打印功能,并多页打印

热门文章

  1. 找出消费者在使用你的产品的时候,什么时刻觉得“值了”
  2. 教大家一个简单的办法
  3. Synchronized 锁升级机制
  4. SQL Server执行计划面试问题
  5. @sql 单元测试_简单单词中使用tSQLt进行的常规SQL单元测试
  6. SQL Server中的万圣节问题和建议的解决方案
  7. Spring MVC起步(一)
  8. 微信小程序开发——以简单易懂的浏览器页面栈理解小程序的页面路由
  9. 【复习笔记】Cache的映像方法
  10. UVA - 1605 Building for UN (联合国大楼)