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

在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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值