这段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 相关文章推荐
js 方法实现返回多个数据的代码
Apr 30 Javascript
JQuery文本框高亮显示插件代码
Apr 02 Javascript
当前流行的JavaScript代码风格指南
Sep 10 Javascript
浅谈JavaScript中的作用域和闭包问题
Jul 07 Javascript
jQuery中Datatables增加跳转到指定页功能
Feb 08 Javascript
vue使用Axios做ajax请求详解
Jun 07 Javascript
JavaScript 日期时间选择器一些小结
Apr 02 Javascript
推荐一个基于Node.js的表单验证库
Feb 15 Javascript
详解如何在Vue项目中发送jsonp请求
Oct 25 Javascript
webpack+express实现文件精确缓存的示例代码
Jun 11 Javascript
ES6字符串的扩展实例
Dec 21 Javascript
Vue组件化(ref,props, mixin,.插件)详解
May 15 Vue.js
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
中国第一家无线电行
2021/03/01 无线电
php实现搜索类封装示例
2016/03/31 PHP
PHP实现的折半查找算法示例
2017/12/19 PHP
PHP hex2bin()函数用法讲解
2019/02/25 PHP
extJs 常用到的增,删,改,查操作代码
2009/12/28 Javascript
javascript 浏览器检测代码精简版
2010/03/04 Javascript
DLL+ ActiveX控件+WEB页面调用例子
2010/08/07 Javascript
setTimeout和setInterval的区别你真的了解吗?
2011/03/31 Javascript
JS获取url链接字符串 location.href
2013/12/23 Javascript
javascript定义变量时有var和没有var的区别探讨
2014/07/21 Javascript
js简单实现点击左右运动的方法
2015/04/10 Javascript
js获取数组的最后一个元素
2015/04/14 Javascript
js实现密码强度检测【附示例】
2016/03/30 Javascript
深入理解jQuery中的事件冒泡
2016/05/24 Javascript
想学习javascript JS和jQuery哪个重要 先学哪个
2016/12/11 Javascript
jQuery实现选中行变色效果(实例讲解)
2017/07/06 jQuery
关于jQuery里prev()的简单操作代码
2017/10/27 jQuery
微信小程序商品详情页规格属性选择示例代码
2017/10/30 Javascript
微信小程序使用video组件播放视频功能示例【附源码下载】
2017/12/08 Javascript
vue vue-Router默认hash模式修改为history需要做的修改详解
2018/09/13 Javascript
微信小程序学习笔记之跳转页面、传递参数获得数据操作图文详解
2019/03/28 Javascript
vue-cli3跨域配置的简单方法
2019/09/06 Javascript
python中的实例方法、静态方法、类方法、类变量和实例变量浅析
2014/04/26 Python
python映射列表实例分析
2015/01/26 Python
Python中Django框架利用url来控制登录的方法
2015/07/25 Python
Flask的图形化管理界面搭建框架Flask-Admin的使用教程
2016/06/13 Python
浅谈python数据类型及类型转换
2017/12/18 Python
DRF跨域后端解决之django-cors-headers的使用
2019/01/27 Python
python爬虫爬取微博评论案例详解
2019/03/27 Python
使用OpenCV实现仿射变换—旋转功能
2019/08/29 Python
Python lxml模块的基本使用方法分析
2019/12/21 Python
django rest framework 自定义返回方式
2020/07/12 Python
团队拓展活动方案
2014/08/28 职场文书
2014年小学安全工作总结
2014/12/04 职场文书
实操Python爬取觅知网素材图片示例
2021/11/27 Python
python区块链实现简版工作量证明
2022/05/25 Python