JS方法代理

页面导航:首页 > 网络编程 > JavaScript > JS方法代理

JS方法代理

来源: 作者: 时间:2016-02-02 09:58 【

作者:Jiang, JilinJS作为一门脚本语言,十分容易上手。外加其灵活性,可以轻而易举地扩展功能。今天,我们就聊聊JS的方法代理。方法代理是脚本语言中常见的方法扩展形式。这种灵活

 

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);

};

 

好了,以上就是这次的方法代理介绍。由于方法代理会混乱代码逻辑使得代码结构变得不易理解。在日常开发过程中,我们应该尽量避免使用它。只有在代理重载,或者更改难以理解的遗留代码的部分逻辑时使用它。从而避免将双刃剑误伤了自己。


Tags:

文章评论

最 近 更 新
热 点 排 行
Js与CSS工具
代码转换工具

<