这段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 相关文章推荐
javascript的函数、创建对象、封装、属性和方法、继承
Mar 10 Javascript
html文本框提示效果的示例代码
Jun 28 Javascript
zepto中使用swipe.js制作轮播图附swipeUp,swipeDown不起效果问题
Aug 27 Javascript
谈谈javascript中使用连等赋值操作带来的问题
Nov 26 Javascript
论JavaScript模块化编程
Mar 07 Javascript
JavaScript入门系列之知识点总结
Mar 24 Javascript
jQuery实现简单倒计时功能的方法
Jul 04 Javascript
JavaScript禁止用户多次提交的两种方法
Jul 24 Javascript
使用jQuery实现一个类似GridView的编辑,更新,取消和删除的功能
Mar 15 Javascript
JavaScript利用fetch实现异步请求的方法实例
Jul 26 Javascript
javascript观察者模式实现自动刷新效果
Sep 05 Javascript
微信小程序实现日历功能
Nov 27 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
PHP 设置MySQL连接字符集的方法
2011/01/02 PHP
php数组函数序列 之shuffle()和array_rand() 随机函数使用介绍
2011/10/29 PHP
php抽象类用法实例分析
2015/07/07 PHP
PHP CURL post数据报错 failed creating formpost data
2016/10/16 PHP
js 对象是否存在判断
2009/07/15 Javascript
查询绑定数据岛的表格中的文本并修改显示方式的js代码
2009/12/15 Javascript
JavaScript在IE和Firefox(火狐)的不兼容问题解决方法小结
2010/04/13 Javascript
Javascript弹出窗口的各种方法总结
2013/11/11 Javascript
IE下通过a实现location.href 获取referer的值
2014/09/04 Javascript
详解jquery中$.ajax方法提交表单
2014/11/03 Javascript
jQuery获得子元素个数的方法
2015/04/14 Javascript
JQuery 获取多个select标签option的text内容(实例)
2017/09/07 jQuery
Vue组件库发布到npm详解
2018/02/17 Javascript
JS实现导出Excel的五种方法详解【附源码下载】
2018/03/15 Javascript
vue form 表单提交后刷新页面的方法
2018/09/04 Javascript
详解webpack模块加载器兼打包工具
2018/09/11 Javascript
微信小程序云开发之模拟后台增删改查
2019/05/16 Javascript
[05:05]给小松五分钟系列 第二期介绍为什么打DOTA2
2014/07/02 DOTA
python使用any判断一个对象是否为空的方法
2014/11/19 Python
用Python给文本创立向量空间模型的教程
2015/04/23 Python
spyder常用快捷键(分享)
2017/07/19 Python
python编程测试电脑开启最大线程数实例代码
2018/02/09 Python
python3利用Dlib19.7实现人脸68个特征点标定
2018/02/26 Python
Python实现正弦信号的时域波形和频谱图示例【基于matplotlib】
2018/05/04 Python
Python操作配置文件ini的三种方法讲解
2019/02/22 Python
Python3.5 win10环境下导入kera/tensorflow报错的解决方法
2019/12/19 Python
appium+python adb常用命令分享
2020/03/06 Python
基于Python词云分析政府工作报告关键词
2020/06/02 Python
浅谈pandas dataframe对除数是零的处理
2020/07/20 Python
python批量生成条形码的示例
2020/10/10 Python
菲律宾购物网站:Lazada菲律宾
2018/04/05 全球购物
双立人美国官方商店:ZWILLING集团餐具和炊具
2020/05/07 全球购物
机械专业应届生求职信
2013/09/21 职场文书
2014年园林绿化工作总结
2014/12/11 职场文书
《钢铁是怎样炼成的》高中读后感
2019/08/07 职场文书
创业计划书之农家乐
2019/10/09 职场文书