JQuery源码分析:强制js函数调用总是返回其实例化对象
2016-02-05 00:20
525 查看
在jQuery中问题出现以下这样一种模式的代码:
这么做有什么好处呢?
① 强制f以类的构造函数执行(this表示的f的实例化对象),而不是当作函数调用(this表示全局变量window);
② 强制通过Function.apply或Function.call方式执行函数时,要求当前对象参数也f的实例对象。
这种写法保证了函数调用与实例化的一致性:
我写的函数,往往只需要它当作类来使用,但是语法是允许它当作函数来调用。为了防止被函数来使用带来的麻烦,就需要这么处理。 javascript脚本的特点就是太灵活了,有时会给开发带一些不必要的麻烦,特别是写框架性代码时,需要约束一些用法,保证使用者写出更加安全、健壮的代码。
我上述的方法封装成如下扩展方法:
测试代码如下
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
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- JavaScript演示排序算法
- 2015-2016网页设计趋势分析 Web Design of Trends
- javascript实现10进制转为N进制数
- jQuery Ajax 跨域调用
- 移动端的长按事件
- jquery教程靠边站,一分钱不花让你免费学会jquery
- JQuery+Strusts1.x无刷新登录
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 对一个分号引发的错误研究
- 异步流程控制:7 行代码学会 co 模块
- ES6 走马观花(ECMAScript2015 新特性)
- JavaScript拆分字符串时产生空字符的原因