您的位置:首页 > Web前端 > JavaScript

JS方法代理

2015-06-23 17:15 666 查看
JS作为一门脚本语言,十分容易上手。外加其灵活性,可以轻而易举地扩展功能。今天,我们就聊聊JS的方法代理。方法代理是脚本语言中常见的方法扩展形式。这种灵活的形式优点在于遇到复杂的JS代码需要扩展时,可以相对简单的抽取并修改。但是,其缺点也十分明显,会造成代码的碎片化,因而是一把双刃剑。


基本形式

var _func = obj.func;

obj.func = function() {

return _func();

};

此处,obj的func方法是原始方法。我们使用一个_func变量保存该方法,之后重写func方法,返回调用原始的方法。相当的好理解。


不定长参数

有时候,我们会遇到不定长参数的形式。那么我们可以做以下更改:
var _func = obj.func;

obj.func = function() {

return _func.apply(this, arguments);

};

写到这里,JS方法代理的两种形式已经写完了。这时,你可能会疑惑这种方法代理有什么用?那么,就跟随我看看几个例子吧:



重写静态方法

出于某些原因,我们需要在console打印的同时,将打印数据传输到指定服务器上用户帮助统计数据。而在开发过程中,直接使用了原生态的console.log方法输出。那么,我们就可做如下修改。

首先,构建代理方法:
var _log = console.log;

console.log = function() {

return _log.apply(this, arguments);

};

接着,插入ajax调用逻辑:
console.log = function() {

var _args = Array.prototype.slice.call(arguments);

$.post("srvAddr", {userID: userID, args: _args});

return _log.apply(this, arguments);

};

可以很容易预见效果:




原型代理

有时候,我们需要直接接管一个类的方法。那么相应的,我们就要将其prototype中的方法做代理。现在我们假设要使得Array默认支持数字排序:
var _sort = Array.prototype.sort;

Array.prototype.sort = function() {

_sort.apply(this, arguments);

};

我们首先检测数组中的元素是否是数字,如果是则按照数字排序,否则就按照默认方式排序:
var _sort = Array.prototype.sort;

Array.prototype.sort = function() {

var _isNum = true;

for(var i = 0 ; i < this.length ; i += 1) {

if(typeof this[i] !== "number") {

_isNum = false;

break;

}

}



if(_isNum) {

return _sort.call(this, function(a, b) {

return a - b;

});

} else {

return _sort.apply(this, arguments);

}

};



原始排序方式(将数字转换成字符排序)



代理后排序方式

注意:此处仅作为原型方法代理的例子。在实际开发中,应该尽量避免对原生对象原型方法做代理。



重载

在jQuery中,toggle方法拥有多种重载,其中一个为toggle(display),通过接受boolean参数来决定元素显示还是隐藏。而fadeToggle方法则不接受该参数。让我们进行简单的代理,使其支持boolean参数:
var _fadeToggle = $.fn.fadeToggle;



$.fn.fadeToggle = function(display) {

if(arguments.length === 1 && typeof display === "boolean") {

if(display) {

return this.fadeIn();

} else {

return this.fadeOut();

}

}

return _fadeToggle.apply(this, arguments);

};

通过参数长度和接收参数类型类型判断是否调用fadeIn或fadeOut方法。如果不匹配则调用原来的fadeToggle方法。以此类推,slideToggle也可以同样适用。



*继承

继承中,我们有时候会需要调用父类方法来实现。这和java中的super有些类似。一个简单的例子。我们定义了一个Person,可以laugh。同时定义一个Robot继承,是其沿用Person的laugh但是稍作修改:
var Person = function() {

this.name = "";

this.laugh = function() {

return "Ha ha!";

};

return this;

};



var Robot = function() {

Person.apply(this);

var _laugh = this.laugh;

this.laugh = function() {

return encodeURIComponent(_laugh());

};

return this;

};


劫持

说到劫持,则和安全性开始挂钩了。如今大多数网站都习惯于使用开源的js库来开发,但是如果碰巧被插入了恶意代码,那么安全也就变得不安全了(例如chrome中大量未经验证的游览器插件)。以下,我们将举几个劫持的例子。



Ajax劫持

不少人以为,通过闭包的方式将重要用户参数存储在作用域内(例如动态生成的secureID),那么即便是被插入了恶意代码也无法获取到,从而无法伪造ajax请求来获取重要信息似乎就足够了。但是如果整个ajax请求被拦截了呢?
var _ajax = $.ajax;



$.ajax = function() {

var $p = _ajax.apply($, arguments);

$p.done(function(data) {

// Do something...

});

return $p;

};

jQuery中所有ajax请求(get,post,getJSON)最终都会调用$.ajax来实现。而通过方法代理直接劫持$.ajax方法并返回一个正常promise对象,会使得页面脚本运行毫无影响。但是实际上数据已经被劫持走了。



Array劫持

Array拥有不少原型方法,例如push,pop,shift,unshift等等。我们只需要简单的代理数组操作方法,便可以截获数据。
var _push = Array.prototype.push;

Array.prototype.push = function() {

// Do something...

return _push.apply(this, arguments);

};

好了,以上就是这次的方法代理介绍。由于方法代理会混乱代码逻辑使得代码结构变得不易理解。在日常开发过程中,我们应该尽量避免使用它。只有在代理重载,或者更改难以理解的遗留代码的部分逻辑时使用它。从而避免将双刃剑误伤了自己。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: