这段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之appendChild、insertBefore和insertAfter使用说明
Dec 30 Javascript
Javascript面向对象编程(二) 构造函数的继承
Aug 28 Javascript
给Flash加一个超链接(推荐使用透明层)兼容主流浏览器
Jun 09 Javascript
js(jQuery)获取时间的方法及常用时间类搜集
Oct 23 Javascript
jQuery中的pushStack实现原理和应用实例
Feb 03 Javascript
浅析jQuery 遍历函数,javascript中的each遍历
May 25 Javascript
基于MVC5和Bootstrap的jQuery TreeView树形控件(二)之数据支持json字符串、list集合
Aug 11 Javascript
关于JavaScript数组你所不知道的3件事
Aug 24 Javascript
微信小程序实现顶部下拉菜单栏
Nov 04 Javascript
vue 验证码界面实现点击后标灰并设置div按钮不可点击状态
Oct 28 Javascript
JQuery实现折叠式菜单的详细代码
Jun 03 jQuery
JavaScript中EventBus实现对象之间通信
Oct 18 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
[原创]解决wincache不支持64位PHP5.5/5.6的问题(提供64位wincache下载)
2016/06/22 PHP
PHP基于redis计数器类定义与用法示例
2018/02/08 PHP
PHP实现的只保留字符串首尾字符功能示例【隐藏部分字符串】
2019/03/11 PHP
HTML代码中标签的全部属性 中文注释说明
2009/03/26 Javascript
一个原生的用户等级的进度条
2010/07/03 Javascript
JS延迟加载(setTimeout) JS最后加载
2010/07/15 Javascript
JQuery拖拽元素改变大小尺寸实现代码
2012/12/10 Javascript
window.showModalDialog()返回值的学习心得总结
2014/01/07 Javascript
深入分析原生JavaScript事件
2014/12/29 Javascript
JavaScript中的eval()函数使用介绍
2014/12/31 Javascript
javascript判断移动端访问设备并解析对应CSS的方法
2015/02/05 Javascript
JS实现三级折叠菜单特效,其它级可自动收缩
2015/08/06 Javascript
Angular Js文件上传之form-data
2015/08/28 Javascript
jQuery基于扩展实现的倒计时效果
2016/05/14 Javascript
JS使用单链表统计英语单词出现次数
2016/06/16 Javascript
用瀑布流的方式在网页上插入图片的简单实现方法
2016/09/23 Javascript
JS给按钮添加跳转功能类似a标签
2017/05/30 Javascript
微信小程序中吸底按钮适配iPhone X方案
2017/11/29 Javascript
React Native 使用Fetch发送网络请求的示例代码
2017/12/02 Javascript
Vue仿今日头条实例详解
2018/02/06 Javascript
使用webpack-dev-server处理跨域请求的方法
2018/04/18 Javascript
使用vue根据状态添加列表数据和删除列表数据的实例
2018/09/29 Javascript
electron制作仿制qq聊天界面的示例代码
2018/11/26 Javascript
Vue.js实现可排序的表格组件功能示例
2019/02/19 Javascript
layui表格 返回的数据状态异常的解决方法
2019/09/10 Javascript
javascript开发实现贪吃蛇游戏
2020/07/31 Javascript
Python装饰器使用示例及实际应用例子
2015/03/06 Python
Python实现批量读取图片并存入mongodb数据库的方法示例
2018/04/02 Python
Python3.6.0+opencv3.3.0人脸检测示例
2018/05/25 Python
Python列表原理与用法详解【创建、元素增加、删除、访问、计数、切片、遍历等】
2019/10/30 Python
Python栈的实现方法示例【列表、单链表】
2020/02/22 Python
深入浅析css3 中display box使用方法
2015/11/25 HTML / CSS
优秀德育工作者事迹材料
2014/05/07 职场文书
个人先进事迹材料范文
2014/12/29 职场文书
2015年学生管理工作总结
2015/05/26 职场文书
在python中读取和写入CSV文件详情
2022/06/28 Python