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

JQuery源码分析:强制js函数调用总是返回其实例化对象

2016-02-05 00:20 525 查看
在jQuery中问题出现以下这样一种模式的代码:

function f(){
if(!(this instanceof f)){
return new f();
}
//...
// 不允许使用return语句,或者 "return this;"
}


这么做有什么好处呢?

① 强制f以类的构造函数执行(this表示的f的实例化对象),而不是当作函数调用(this表示全局变量window);

② 强制通过Function.apply或Function.call方式执行函数时,要求当前对象参数也f的实例对象。

这种写法保证了函数调用与实例化的一致性:
f()
等价于
new fn()
。 在写f函数时,就不用担心函数被当作方法调用时,向当前this对象成员变量时,变成了全局变量。

我写的函数,往往只需要它当作类来使用,但是语法是允许它当作函数来调用。为了防止被函数来使用带来的麻烦,就需要这么处理。 javascript脚本的特点就是太灵活了,有时会给开发带一些不必要的麻烦,特别是写框架性代码时,需要约束一些用法,保证使用者写出更加安全、健壮的代码。

我上述的方法封装成如下扩展方法:

// 转换成Class:保证函数当前函数fn的调用就是实例化 fn() <==> new fn(),避免函数调用与实例化的二义性导致this意义的不一致性
// @mergeRtv 是否合并返回值,默认false,表示忽略return的返回值;否则将return返回对象合并到当前对象中。
Function.prototype.toClass = function (mergeRtv) {
var fn = this, _mark = "extionMark_" + Math.random();
var merge = mergeRtv === true;
var slice = Array.prototype.slice;
var nfn = function (mark, args) {
if (!(this instanceof nfn)) {
var args = slice.call(arguments);
return new nfn(_mark, args);// 参数怎么解决?
}
args = mark === _mark ? args : slice.call(arguments);
var val = fn.apply(this, args);
if (merge && val && (typeof val == "object" || typeof val == "function")) {
for (var key in val) {
if (val.hasOwnProperty(key)) {
this[key] = val[key];
}
}
}
return this;
}
// 静态成员复制
for (var key in fn) {
if (fn.hasOwnProperty(key)) {
nfn[key] = fn[key];
//console.log("OwnProperty:", key);
}
//console.log("info:", key);
}
return nfn;
}
var fn = function(){
//...
}
// fn函数转化成类的构造函数,fn中的return语句无效,返回值始终是当前类对象
fn = fn.toClass();
// fn() <==> new fn()


测试代码如下

var fn = function (id, name) {
this.Id = id;
this.Name = name;
return {
nid: id,
nName: name
};
}
fn.ClassName = "fn";
var ofn = fn;
var fnObj = new fn(12345, "aaaaa");
console.log("----------- 测试toClass: orgin -----------");
console.log("Id: ", fnObj.Id);
console.log("Name: ", fnObj.Name);
console.log("ClassName: ", fn.ClassName);
console.log("----------- 测试1: 基本 -----------");
fn = ofn.toClass();
var fnObj = fn(12345, "aaaaa");
console.log("Id: ", fnObj.Id);
console.log("Name: ", fnObj.Name);
console.log("nId: ", fnObj.nid);
console.log("nName: ", fnObj.nName);
console.log("ClassName: ", fn.ClassName);
console.log("ClassName: ", fnObj.constructor.ClassName);
console.log("Old Function: ", ofn === fn);
console.log("----------- 测试2:有返回值 -----------");
fn = ofn.toClass(true);
var fnObj = fn(12345, "aaaaa");
console.log("Id: ", fnObj.Id);
console.log("Name: ", fnObj.Name);
console.log("nId: ", fnObj.nid);
console.log("nName: ", fnObj.nName);
console.log("ClassName: ", fnObj.constructor.ClassName);
console.log("Old Function: ", ofn === fn);
console.log("-------------------------------------");
// #endregion
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jquery javascript