`

Function Invocation Patterns

阅读更多

今天看到微博上大家在讨论一个JavaScript的小问题,问题虽小,还是有思考的价值。我看到不少人对其展开了讨论,有很多答案,也有很多有意思的观点。学JavaScript的人很多,但是学好真不容易,哪怕就是基础的部分。

先看一下下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var value = 500;
var obj = {
    value: 0,
    increment: function() {
        this.value++;
 
        var innerFunction = function() {
            alert(this.value);
        }
 
        innerFunction();
    }
}
obj.increment();

好,在往下阅读以前,想一想,你觉得会打印的结果是多少?

————————————————-思考———————————————————

不少人都觉得是1,因为obj对象的value初始值是0,打印的“this.value”在“this.value++”以后就应该变成1了。

其实答案是500,语句”innerFunction()”,正是使用了Function Invocation Patterns这种方式去调用一个方法,这个方法调用没有显式指定“this”,那么如果你按照一些其它编程语言的思路去思考的话,没有显式指定this,this就应该是当前对象吧……那你就错了。这正是JavaScript设计中一个很糟糕的部分,或者说,是一个坑——在没有显式指定this的时候,这个this其实是一个global对象,在这里就是window。

还有很多人解释说这是“闭包”的一个应用,有人又说不是,我来分析一下:闭包简单说就是“包含自由变量的代码块”——也就是说,一个条件是代码块,这点毫无疑问满足;另一个条件是自由变量,这就有争议了,代码中的那个全局变量value算不算所谓的“自由变量”,如果算,那就符合闭包的要求,如果不算(很多人认为global变量不能算作闭包的自由变量),那就不算闭包。

解决方法呢,其中的一个比较简单的办法就是持有一个当前正确this的引用,在这里保存到一个名为“that”的变量里,再让目标方法来调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var value = 500;
var obj = {
    value: 0,
    increment: function() {
        var that = this;
        that.value++;
 
        var innerFunction = function() {
            alert(that.value);
        }
 
        innerFunction();
    }
}
obj.increment();

这样结果就是1了。

还没完,如果我把程序改成这样(即把原来的“this.value++”改成“value++”):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var value = 500;
var obj = {
    value: 0,
    increment: function() {
        value++;
 
        var innerFunction = function() {
            alert(this.value);
        }
 
        innerFunction();
    }
}
obj.increment();

结果又是多少呢?

————————————————-思考———————————————————

结果应该是501。因为没有使用this.value的时候,“value++”这一行的这个value是全局的value。

那我把全局的value屏蔽掉吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//var value = 500;
var obj = {
    value: 0,
    increment: function() {
        value++;
 
        var innerFunction = function() {
            alert(this.value);
        }
 
        innerFunction();
    }
}
obj.increment();

这样的结果又是多少,这回总该是1了吧?

————————————————-思考———————————————————

不,这回会报错:Uncaught ReferenceError: value is not defined。因为在这样使用的时候,obj对象的value对increment方法内部来说直接不可见。

其实,在JavaScript中,有这样几种函数调用模式:

  1. 方法调用:Fethod Invocation
  2. 函数调用:Function Invocation
  3. 构造器调用:Constructor Invocation
  4. Apply调用:Apply Invocation

这些模式其实你都用过,如果你想知道更多,请阅读这篇文章,上面的例子代码也是从它里面引用来的。

如果你对上面说到的都理解了,那么看看这段代码,结果应该是多少?

1
2
3
4
5
6
7
8
9
var value = 500;
var obj = function(){
    var value = 0;
    return function() {
        value++;
        alert(value);
    }
}
obj()();

————————————————–思考——————————————————–

结果应该是1(其实这道题只是一个简单的闭包使用而已,并没有Function Invocation Patterns,我挖了个坑让你跳,嘿嘿),你对了吗?

最后一题,把典型的闭包和Function Invocation Patterns结合起来,你要毫无压力地挺住啊:

1
2
3
4
5
6
7
8
9
10
11
12
var value = 500;
var obj = function(){
    var value = 0;
    var getValue = function(){
        return this.value;
    };
    return function() {
        value++;
        alert( getValue(value) );
    }
}
obj()();

结果是多少呢?

————————————————–思考——————————————————–

正确结果是500,这次你对了吗?

文章系本人原创,转载请注明作者和出处(http://www.raychase.net

注:本博客已经迁移到个人站点 http://www.raychase.net/ ,欢迎大家访问收藏,本ITEye博客在数日后将不再更新。

1
1
分享到:
评论

相关推荐

    Learning C++ Functional Programming

    Recurring method invocation using recursive algorithm Procrastinating the execution process using Lazy Evaluation Optimizing code with Metaprogramming Running parallel execution using Concurrency ...

    Addison.Wesley.C++.by.Dissection.2002.pdf

    - **Function Invocation:** Describes how to call functions. - **Function Definition:** Discusses the details of defining functions. - **The return Statement:** Explains the `return` statement. - **...

    ObjCRuntimeGuide

    This allows for dynamic invocation of methods, which is useful in scenarios where the exact method to be called is determined at runtime. - **Dynamic Method Resolution:** Objective-C supports ...

    Google C++ Style Guide(Google C++编程规范)高清PDF

    Creating common, required idioms and patterns makes code much easier to understand. In some cases there might be good arguments for changing certain style rules, but we nonetheless keep things as ...

    [JavaScript][PDF][英文版]Oh My JS

    2. Understanding JavaScript Function Invocation and "this"(理解JavaScript函数调用和“this”):这部分内容解释了在JavaScript中函数如何被调用以及如何处理函数中的“this”关键字,这是JavaScript中一个容易...

    Fuzzy and Neuro-Fuzzy Systems in Medicine

    Chapter 3—Brain State Identification and Forecasting of Acute Pathology Using Unsupervised Fuzzy Clustering of EEG Temporal Patterns 1. Introduction 2. Background 2.1 The Electroencephalogram ...

    Java2核心技术卷I+卷2:基础知识(第8版) 代码

    Naming Patterns for Bean Properties and Events 698 Bean Property Types 701 BeanInfo Classes 710 Property Editors 713 Customizers 723 JavaBeans Persistence 732 Chapter 9: Security 755 Class ...

    Using Perl For Web Programming.pdf

    Invocation H Command-Line Arguments H Program Layout H G Data Types Scalars H Arrays H Associative Arrays H File Handles H G Special Variables Environment Variables H Program Arguments H ...

    The way to go

    go程序设计语言 Contents Preface................................................................................................................................. xix PART 1—WHY LEARN GO—GETTING ...

    [Go语言入门(含源码)] The Way to Go (with source code)

    The Way to Go,: A Thorough Introduction to the Go Programming Language 英文书籍,已Cross the wall,从Google获得书中源代码,分享一下。喜欢请购买正版。 目录如下: Contents Preface......................

Global site tag (gtag.js) - Google Analytics