这段js代码得节约你多少时间


Posted in Javascript onDecember 20, 2011

1.应用案例:

var Mouse = function () { 
// Look! no that = this! 
this.position = [0, 0]; 
if (document.addEventListener) { 
document.addEventListener('mousemove', ?); //this.move? 
} else if (document.attachEvent) { 
document.attachEvent("onmousemove", ?); //this.move?怎么放进去 
} 
}; 
Mouse.prototype.move = function (arg1,arg2,event) { 
event = window.event || event; 
var x = event.pageX || event.offsetX, 
y = event.pageY || event.offsetY; 
this.position = position = [x, y]; 
this.log(arg1,arg2); 
}; 
Mouse.prototype.log = function (arg1, arg2) { 
console.log(arg1+","+arg2); 
console.log(this.position); 
}; 
new Mouse();

上面你知道'?'号那里要干嘛了吗?我想给document的mousemove绑定我的move方法,但是遇到难题了,这样的话,Mouse.prototype.move
里的this就不会指向Mouse的对象,相信大家经常碰到这种问题.也许你早知道了怎么解决,但是有更快更简单的方法吗?答案是:
Function.prototype.bind()这个神奇的玩意,但是ie6 7 8都不支持,一般现代浏览器都支持了,我们接下来要做的就是模仿他,
这么好的方法当然要模仿它,怎么模仿见下面nothing的原创方法
(function () { 
var proxy = function (fn, target) { 
var proxy = function () { 
if (2 < arguments.length) { //存在被代理的函数有参数的时候 
var privateArgs = Array.prototype.slice.call(arguments, 2); 
//从第二个开始取出来,[this,绑定的对象,参数列表] 
return function () { 
var args = Array.prototype.slice.call(arguments); 
-->这里的arguments与外面的不是同一个,这个是被代理的函数内部的arguments对象, 
比如这里的move函数的 arguments[0]=[object Event]就是这个事件内部的e参数 
Array.prototype.unshift.apply(args, privateArgs); 
-->这里在加上传进来的参数,就实现了,和原生bind一样的参数形式 
//->而且这里是把私有的参数放到前面的比如a=new Mouse();a.move(1,2); 
//如果这个move方法没有参数,意思就是prototype.move=fn(){arguments} , 
//而我传进来了参数,参数的arguments.length=3, 
//arguments[0]=1,arguments[1]=2,arguments[2]=[object event]. 
return fn.apply(target, args); 
} 
//这里之所以搞复杂了,是因为,在被代理的函数可以直接访问arguments,比如我不给被代理的函数传参数,而直接使用 
//这样这个arguments就会包含与原生Function.prototype.bind的arguments一样的对象, 
//这里代码深奥,是因为你没理解这里原生的bind里面的arguments是什么,知道了,就知道为什么绑定我自己的arguments 
//做这么多,主要目的就是使你被代理的函数内部的arguments与function.prototype.bind里的arguments对象包含的东西一致 
} 
return function () { 
return fn.apply(target, arguments); 
} 
} 
return proxy.apply(null, arguments); 
}; 
/*支持原生的使用原生的*/ 
Function.prototype.bind = Function.prototype.bind || 
function (target) { //这里的this指代要被代理的函数 
if (1 < arguments.length) { 
var args = Array.prototype.slice.call(arguments, 1); //取出参数列表 
args.unshift(this, target); //这个args最终变成了[this,绑定的对象,参数列表] 
return proxy.apply(null, args); 
--如果直接proxy(args),麻烦来了,args成了proxy函数的一个参数,就会报错, 
其实这里主要是分开任务处理,proxy只关心代理和参数是怎么传给proxy,如果被代理的没参数,直接; 
return proxy(this, target)--> return fn.apply(target, arguments); 就是17楼的那个答案 
-->估计大家会跟17楼犯一样的错误,这里之所以这么复杂的操作arguments对象,只是为了能保证传进proxy函数中,保证arguments对象不失效 
} 
return proxy(this, target); 
}; 
})();

以上代码为什么我要一直return回来代理,因为这样你才能这样调用this.move.bind(this,1,2)()然后这里会立即执行函数!
有了以上代码,我们就可以轻松的实现了"?"号这里要写什么代码了,^_^,简单吧
if (document.addEventListener) { 
document.addEventListener('mousemove', this.move.bind(this,1,2)); 
} else if (document.attachEvent) { 
document.attachEvent("onmousemove", this.move.bind(this,1,2)); 
}

是不是以后凡是碰到要添加事件,然后调用的方法的this又想指向其他对象,这样是不是很简单呢..
看到大家对以上代码有点难理解,来个简单点得
var a = function () { 
console.log(arguments[0]); //1 
console.log(arguments[1]); //2 
console.log(this.key1); 
//这样绑定参数的话,我的参数列出来才能和原生的bind一样,就这么简单, 
}; 
var b = { 
key1: "value1" 
}; 
a.bind(b, 1, 2)();

反驳17楼同学的代码错误,我想这是很多人会犯的错误,代码如下
Function.prototype.bind = function (target) { 
var self = this; 
return function () { 
return self.apply(target, arguments); //这里的arguments根本传不进来 
} 
} 
var a = function () { 
console.log(arguments.length); //这样bind的话,arguments参数失效 
//arguments.length=0. 
console.log(this.key1); 
}; 
var b = { 
key1: "value1" 
}; 
a.bind(b, [1, 2], 3)(); //从这里可以看出,期望的arguments.length=2 
//这也是我为什么苦口婆心的操作arguments参数 
//我知道这里大部分人都会觉得对的,但是你错了,17楼的同学你还得在思考下

不带注释的源码,
(function () { 
var proxy = function (fn, target) { 
var proxy = function () { 
if (2 < arguments.length) { 
var privateArgs = Array.prototype.slice.call(arguments, 2); 
return function () { 
var args = Array.prototype.slice.call(arguments); 
Array.prototype.unshift.apply(args,privateArgs); 
return fn.apply(target, args); 
} 
} 
return function () { 
return fn.apply(target, arguments); 
} 
} 
return proxy.apply(null, arguments); 
}; 
/*支持原生的使用原生的*/ 
Function.prototype.bind = Function.prototype.bind || 
function (target) { 
if (1 < arguments.length) { 
var args = Array.prototype.slice.call(arguments, 1); 
args.unshift(this, target); 
return proxy.apply(null, args); 
} 
return proxy(this, target); 
}; 
})();

这篇文章是接着上篇文章讲得,我这个讲个详细的列子,如果没看就点
先看列子,本博客没时间去搞华丽的布局,只求朴实的代码,只为js代码爱好者使用

var Mouse = function () { 
if (document.addEventListener) { 
document.addEventListener('mousemove', this.move.bind(this,1,2,[3,4])); 
} else if (document.attachEvent) { 
document.attachEvent("onmousemove", this.move.bind(this,1,2,[3,4])); 
} 
}; 
Mouse.prototype.move = function () { 
console.log(arguments[arguments.length-1].clientX); 
};

这里的arguments的输出结果很好的解释了上文代码,不懂得请结合新给出得列子配合理解.
var privateArgs = Array.prototype.slice.call(arguments, 2); 
//私有的参数,表示代理者的参数,这里代表1,2,[3,4] 
return function () { 
var args = Array.prototype.slice.call(arguments); 
//这里的参数,代表被代理者的参数,这里如事件函数内部的e 
Array.prototype.unshift.apply(args, privateArgs); 
//这里是将两者的参数合并在一起,然后私有参数在前,目的也是为了和原生的参数顺序一致 
return fn.apply(target, args); 
//将合并后的参数这里包括1,2,[3,4] e传进去,并apply 
}

好,到了这里,你会发现一个不错的js技巧,就是不用兼容处理e=window.event||e,直接使用arguments[arguments.length-1]就能兼容代表
所有浏览器的事件e对象,节省了不少的代码与思考的时间,
之所以写出这段代码,是希望大家对js代码有个真正的理解,知道js的真正魅力在哪里,如果了真看懂了此文,至少你知道了arguments到底是
怎么回事了,本博客破烂无比,只有朴实的代码,适合js代码爱好者学习.
其实真正的js魅力何止这点.有了以上的实例加上说明,相信你也应该了解得差不多了,不懂得多demo几下就知道了.
一个js爱好者,会时不时贴出一些较为新鲜的代码供大家学习,本博客的目的就是为了共同学习js代码的精髓.
Javascript 相关文章推荐
IE6-IE9不支持table.innerHTML的解决方法分享
Sep 14 Javascript
JavaScript数组深拷贝和浅拷贝的两种方法
Apr 16 Javascript
JavaScript动态提示输入框输入字数的方法
Jul 27 Javascript
使用JavaScript和CSS实现文本隔行换色的方法
Nov 04 Javascript
jQuery获取单击节点对象的方法
Jun 02 Javascript
jQuery悬停文字提示框插件jquery.tooltipster.js用法示例【附demo源码下载】
Jul 19 Javascript
ES6所改良的javascript“缺陷”问题
Aug 23 Javascript
JavaScript使用Range调色及透明度实例
Sep 25 Javascript
Extjs gridpanel 中的checkbox(复选框)根据某行的条件不能选中的解决方法
Feb 17 Javascript
浅谈react-router HashRouter和BrowserRouter的使用
Dec 29 Javascript
vue element-ui table表格滚动加载方法
Mar 02 Javascript
详解vuex之store拆分即多模块状态管理(modules)篇
Nov 13 Javascript
js实现的仿新浪微博完美的时间组件升级版
Dec 20 #Javascript
非主流的textarea自增长实现js代码
Dec 20 #Javascript
javascript之querySelector和querySelectorAll使用介绍
Dec 20 #Javascript
js有关元素内容操作小结
Dec 20 #Javascript
js汉字排序问题 支持中英文混排,兼容各浏览器,包括CHROME
Dec 20 #Javascript
suggestion开发小结以及对键盘事件的总结(针对中文输入法状态)
Dec 20 #Javascript
js change,propertychange,input事件小议
Dec 20 #Javascript
You might like
yii2学习教程之5种内置行为类详解
2017/08/03 PHP
PHP如何实现订单的延时处理详解
2017/12/30 PHP
PHP实现基于3DES算法加密解密字符串示例
2018/08/24 PHP
js异或加解密效果代码
2008/06/25 Javascript
判断目标是否是window,document,和拥有tagName的Element的代码
2010/05/31 Javascript
jquery中获取select选中值的代码
2011/06/27 Javascript
IE中jquery.form中ajax提交没反应解决方法分享
2012/09/11 Javascript
JavaScript 用cloneNode方法克隆节点的代码
2012/10/15 Javascript
JavaScript 实现类的多种方法实例
2013/05/01 Javascript
jscript读写二进制文件的方法
2015/04/22 Javascript
JS禁用页面上所有控件的实现方法(附demo源码下载)
2015/12/17 Javascript
使用jQuery制作基础的Web图片轮播效果
2016/04/22 Javascript
EasyUI的DataGrid每行数据添加操作按钮的实现代码
2017/08/22 Javascript
vue父组件异步获取数据传给子组件的方法
2018/07/26 Javascript
利用layer实现表单完美验证的方法
2019/09/26 Javascript
layer页面跳转,获取html子节点元素的值方法
2019/09/27 Javascript
angular组件间通讯的实现方法示例
2020/05/07 Javascript
Jquery高级应用Deferred对象原理及使用实例
2020/05/28 jQuery
js实现列表按字母排序
2020/08/11 Javascript
彻底搞懂并解决vue-cli4中图片显示的问题实现
2020/08/31 Javascript
js实现纯前端压缩图片
2020/11/16 Javascript
Python中字符串的修改及传参详解
2016/11/30 Python
Python字符串的全排列算法实例详解
2019/01/07 Python
对Python3之方法的覆盖与super函数详解
2019/06/26 Python
基于python的selenium两种文件上传操作实现详解
2019/09/19 Python
django实现支付宝支付实例讲解
2019/10/17 Python
django中media媒体路径设置的步骤
2019/11/15 Python
Python可变对象与不可变对象原理解析
2020/02/25 Python
使用css3做0.5px的细线的示例代码
2018/01/18 HTML / CSS
Omio中国:全欧洲低价大巴、火车和航班搜索和比价
2018/08/09 全球购物
意大利男装网店:Vrients
2019/05/02 全球购物
彪马法国官网:PUMA法国
2019/12/15 全球购物
11月红领巾广播稿
2014/01/17 职场文书
安全生产先进个人材料
2014/02/06 职场文书
酒店节能降耗方案
2014/05/08 职场文书
科技工作者先进事迹
2014/08/16 职场文书