找回密码
 立即注册
首页 业界区 业界 对《javascript 杂谈之哪种写法你更喜欢?》最后一种“ ...

对《javascript 杂谈之哪种写法你更喜欢?》最后一种“匿名函数法”的解释

简千叶 2025-5-29 16:14:54
前两天看了篇不错的关于javascript写法的文章。在评论里,不少人表示看不懂最后一种方法,作者也没详细说明,于是我顺势解说,算是沾点人气。
1.png

代码如上图,整体结构模仿jQuery,代码不长,知识点较多,信息量很大,我们分两部分,逐行解释。
第一部分

第一部分中,我们把extend相关的方法抽离,剩余代码如下:
  1. (function () {
  2.         var yQuery = (function () {
  3.             var yQuery = function () {
  4.                 return yQuery.fn.init();
  5.             };
  6.             yQuery.fn = yQuery.prototype = {
  7.                 init: function () {
  8.                     return this;
  9.                 }
  10.             };
  11.             return yQuery;
  12.         })();
  13.         window.yQuery = window.$ = yQuery();
  14.     })();
复制代码
知识点1:无引用的匿名函数调用
  1. (function() {
  2.     })();
复制代码
这种写法作用是声明并执行一个方法,等同于:
  1. function Test() {
  2.     }
  3.     Test();
复制代码
知识点2:属性变量无需声明
  1. var obj = new Object();
  2. obj.name = "abc";
复制代码
obj并没有name属性,但无需声明就可以使用,初始值为undefined。上例中yQuery.fn 就没有声明。
知识点3:{}二义性,相当于创建一个对象。
  1. var obj = new Object();
  2. var obj = { };
复制代码
在js中,{}除了可作为复合语句边界以外,还有创建一个空对象的作用,因此上面这两句相同。而在例子中用到的情况如下:
  1.         {
  2.             init: function () {
  3.                 return this;
  4.             }
  5.         };
复制代码
这段代码猛一看像方法,实质是一个包含了init方法的对象,而方法中的this指向这个对象本身。
知识点4:连等表达式
  1. var a = b = 1;
复制代码
这个比较好理解,相当于对他们分别赋同一个值。在上例中,yQuery.fn就用到了这个写法。
知识点5:原型继承prototype
  1. yQuery.fn = yQuery.prototype = {
  2.                 init: function () {
  3.                     return this;
  4.                 }
  5.             };
复制代码
例子中,通过连等分别对yQuery.fn和yQuery.prototype赋值给了同一个对象。而fn的作用只是一个别名,只为书写方便,重点是给prototype赋值,为什么要给它赋值?在本例中无法解释。
在jQuery中,init方法会返回不同对象,而本例中永远返回同一个对象,因此这里prototype没有多大意义。至于jQuery为什么要用prototype,算是题外话了,有兴趣的可点这里。
第一部分代码含义

这段代码第二行yQuery和第三行的yQuery是两个变量,因名字相同,所有很有迷惑性。整段代码意思就是:yQuery.prototype指向了一个包含init方法的对象,prototype有个别名fn,可通过yQuery.fn.init()返回这个对象,最后把这个对象赋值给window.$和window.yQuery属性。
第二部分

看完了第一部分,第二部分就相对简单了,代码如下:
  1. yQuery.extend = yQuery.fn.extend = function () {
  2.                 var options, name, src, copy,
  3.                     target = arguments[0] || {},
  4.                     i = 1,
  5.                     length = arguments.length;
  6.                 if (length === i) {
  7.                     target = this;
  8.                     --i;
  9.                 }
  10.                 for (; i < length; i++) {
  11.                     if ((options = arguments[i]) != null) {
  12.                         for (name in options) {
  13.                             src = target[name];
  14.                             copy = options[name];
  15.                             if (src === copy) {
  16.                                 continue;
  17.                             }
  18.                             if (copy!==undefined) {
  19.                                 target[name] = copy;
  20.                             }
  21.                         }
  22.                     }
  23.                 }
  24.                 return target;
  25.             };
复制代码
知识点1:函数中的arguments变量

函数内部会自带一个arguments变量,该变量记录传入的参数,从左至右分别是arguments[0],arguments[1]等,js奇怪的地方在于,你声明了一个无参函数,在调用的时候依然可以传入参数,比如:
  1. function NoArg() {
  2.         console.log(arguments[0]);
  3.         console.log(arguments[1]);
  4.         console.log(arguments[2]);
  5.     }
  6.     NoArg(1, 2, "a");
复制代码
该例NoArg调用时,会正常显示传入参数。
知识点2:结果类型不确定的逻辑运算

js中,所有类型都可以进行逻辑判断(true或false),js会将值转化为布尔值,但并不改变原值。如:
  1. var str = "a";
  2.     if(str) {
  3.     }
复制代码
此处的str为true,该特性与逻辑运算符”||”和”&&”结合形成了js一大特点,代码如下:
  1. var str = "a";
  2. var num = 1;
  3. var x = str || num; //x="a"
  4. var y = str && num; //y=1;
复制代码
js支持“逻辑短路”,所谓逻辑短路是指:

  • 在”||” 运算中,第一个条件符合就结束判断。
  • 在”&&”运算中,第一个条件不符合就结束判断。
因此,”str || num”的str为true,则结束判断,返回str。”str&&num”的str为true,则继续判断num,num为true,则返回num。在本文案例中,有几个地方用到了这个特性:
  1. target = arguments[0] || {}
复制代码
容易看出,如果arguments[0]有值则返回该值,不然就通过{}返回一个空的对象。还有一处在图片中有,我文中没有打出来的代码:
  1. $.ui = $.ui || { };
复制代码
知识点3:数组方式访问对象属性
  1. var obj = new Object();
  2. obj.name = "a";
  3. obj["name"] = "a";
复制代码
最后两行代码等效。
第二部分代码含义

这部分代码可简单描述为:定义一个方法,将参数1之外的所有参数的属性成员赋值给参数1。我把循环部分修改一下,能更容易看懂,代码如下:
  1. for (; i < length; i++) {
  2.         if ((options = arguments[i]) != null) {
  3.             for (var name in options) {
  4.                 if (options[name] !== undefined) {
  5.                     target[name] = options[name];
  6.                 }
  7.             }
  8.         }
  9.     }
复制代码
结语

js中有不少语法和运算符存在二义性,这导致js代码显的混乱难懂,所以不少人骂js是一个2B的语言,我觉得也不无道理。不过随着js的应用范围越来越广泛,终究避不开它,因此骂归骂,学还是要学的。
我是看了周爱民老师的《JavaScript语言精髓与编程实践(第2版)》后才算对js真正入门,饮水思源,推荐此书。
 


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册