说说函数调用模式

  相信大家都知道,函数的调用模式与进入函数执行上下文的this指针有着密不可分的关系。随着调用模式的不同,this指针的指向便有所不同。随着应用的复杂、代码的累积,对于函数作用域的分析真是个头痛的问题。因此,深入理解函数调用模式对函数作用域(this指针)的影响变得至关重要。

/**
 * 函数调用模式
 * 
 *     1>方法调用模式
 *         (1)当一个函数被保存为对象的一个属性时,称它为一个方法。
 *         (2)当一个调用表达式包含一个属性存取表达式(即一个.表达式或[subscript]下标表达式),
 *             那么它被当做一个方法来调用。
 *         (3)当一个方法被调用时,this被绑定到该对象。可以使用this去访问对象,所以它能从对象中取值或修改对象。
 *             this到对象的绑定发生在调用的时候。
 *     2>函数调用模式
 *         (1)当函数以此模式调用时,this被绑定到全局对象。这是语言设计上的一个错误。倘若语言设计正确,
 *             当内部函数被调用时,this应该仍然绑定到外部函数的this变量,
 *             这个设计错误的后果是方法不能利用内部函数来帮助它工作,因为内部函数的this被绑定了错误的值,
 *             所以不能共享该方法对对象的访问权。
 *         (2)解决方案:如果该方法定义一个变量(如that)并给它赋值为this,那么内部就可以通过那个变量访问到this。
 *     3>构造器调用模式
 *         (1)如果在一个函数前面带上new来调用,那么将创建一个隐藏连接到该函数的prototype成员的新对象,
 *             同时this将会被绑定到那个新对象上。
 *         (2)我们通常以大写格式来命名构造器函数。
 *     4>Apply、Call调用模式
 *         (1)apply(thisObj, argsArray)
 *             第一个是将被绑定给this的值,第二个是参数数组。
 *         (2)call(thisObj, arg1, arg2, ...)
 *             第一个是将被绑定给this的值,之后为参数列表枚举。
 *     
 *     我们需要深入区分前两者调用模式,深入理解汤姆大叔的博客便知其区别了——
 *     深入理解JavaScript系列(13):This? Yes,this!
 */
 1 //分析
 2 (function ($) {
 3     
 4     window.color = 'red';
 5     
 6     /**
 7      * 1>this与上下文中可执行代码的类型有直接关系,this值在进入上下文时确定,并且在上下文运行期间永久不变。
 8      * 2>this值的首要特点(或许是最主要的)是它不是静态的绑定到一个函数。
 9      * 3>this值的确定与引用类型的值相关,其通用规则如下:
10      *     在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。
11      *     如果调用括号()的左边是引用类型的值,this将设为引用类型值的base对象(base object),
12      *     在其他情况下(与引用类型不同的任何其它属性),这个值为null。
13      */
14     var myapp = {
15         color: 'green',
16         paint: function (node) {
17             node.style.color = this.color;
18         }
19     };
20     
21     var findNodes = function (callback) {
22         
23         var nodes = $('div');
24         for (var i = 0, len = nodes.length; i < len; i += 1) {
25             //此时经过中间值计算后,callback的base是global,因此调用callback后的this指向global
26             callback(nodes[i]);
27         }
28     }
29     //findNodes的调用模式为函数调用模式
30     findNodes(myapp.paint);
31     
32     //myapp.paint()的调用模式为方法调用模式
33     myapp.paint($('div').get(0));
34     
35 })(jQuery);
36 
37 //改造
38 (function ($) {
39     
40     var myapp = {
41         color: 'green',
42         paint: function (node) {
43             node.style.color = this.color;
44         }
45     };
46     
47     var findNodes = function (callback_obj, callback) {
48         var nodes = $('div');
49         for (var i = 0, len = nodes.length; i < len; i += 1) {
50             if (typeof callback === 'function') {
51                 //改造的方式无非是改变回调函数的作用域
52                 callback.call(callback_obj, nodes[i]);
53             }
54             if (typeof callback === 'string') {
55                 callback_obj[callback](nodes[i]);
56             }
57         }
58     };
59     //我们指定在myapp对象的作用域下,执行myapp.paint函数
60     //传递一个对象和一个方法
61     findNodes(myapp, myapp.paint);
62     //传递一个对象和方法名称字符串
63     findNodes(myapp, 'paint');
64     
65 })(jQuery);
/**
 * 本篇随笔参考资料:
 * 
 * 《JavaScript语言精粹》
 *     第4章:函数
 * 《JavaScript模式》
 *     第4章:函数
 * 《深入理解JavaScript系列——汤姆大叔的博客》
 *     深入理解JavaScript系列(13):This? Yes,this!
 */

  深入理解JavaScript系列的篇篇文章都是精华,集合了很多JavaScript书籍的核心思想,建议博友细细推敲。

  以下列举本人已经读过、加以深入理解并部分应用于实践的文章——

深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点
深入理解JavaScript系列(2):揭秘命名函数表达式
深入理解JavaScript系列(3):全面解析Module模式
深入理解JavaScript系列(4):立即调用的函数表达式
深入理解JavaScript系列(5):强大的原型和原型链
深入理解JavaScript系列(9):根本没有“JSON对象”这回事!
深入理解JavaScript系列(10):JavaScript核心(晋级高手必读篇)
深入理解JavaScript系列(11):执行上下文(Execution Contexts)
深入理解JavaScript系列(12):变量对象(Variable Object)
深入理解JavaScript系列(13):This? Yes, this!
深入理解JavaScript系列(14):作用域链(Scope Chain)
深入理解JavaScript系列(15):函数(Functions)
深入理解JavaScript系列(16):闭包(Closures)

  很惭愧,看的并不是很多,还有不少东西要学,我一直信奉一个学习理念——

  抓住一个点,深究下去;
  抓住一个点,扩展下去!

  还有很多可以研究的知识,还有很多可以整合的知识。加油吧,给自己打打气!

原文地址:https://www.cnblogs.com/jinguangguo/p/2712475.html