zoukankan      html  css  js  c++  java
  • 一段奇葩Javascript代码引发的思考

         今天与一挚友加同事调试一段奇葩的javascript代码,在分析出结果后,让我萌生了写此篇文章的想法,如有不对之处望指正,也欢迎大家一起讨论。缩减后的js代码如下,你是否能准确说明他的输出值呢?

    function DemoFunction(){
        this.init = function(){
            var func = (function(va){
            this.va = va;
            return function(){
                va += this.va;
                return va;
            }
            })(function(va1, va2){
                var va3 = va1 + va2; //干扰代码
                return va1;
            }(1,2));
            
            console.log(func(20));
    
            this.func = func;
            console.log(this.func(100));
        }
    }
    var a = new DemoFunction();
    a.init();

    如果要解释这段代码,首先我们得有如下几个概念:

    • 执行上下文:每次当控制器转到ECMAScript可执行代码时,即会进入一个可执行上下文,参考文献
    • this:this的创建是在 “进入执行上下文” 时创建的,在代码执行过程中是不可变的,参考文献
    • 自执行函数:准确来说应该叫:立即调用函数表达式。因为他声明后即执行,参考文献

    详细解释此段代码

    一、首先看DemoFunction的构造函数

    这是代码的重点,第一层代码可以缩减为如下:

    function DemoFunction(){
        this.init = function(){
            //省略代码....
        }
    }

    表示为DemoFunction的实例提供init方法(声明:此处有误导成份,方法应尽可能放在原型链接上,也就是prototype上。),对外公开的接口。

    二、在init方法中,再次省略代码如下:

    var func = (function(va){
        this.va = va;
        return function(){
            va += this.va;
            return va;
        }
    })(8/*省略代码...*/);
    
    //省略代码....

    代码虽短,但信息量巨大,但这样省略部分代码后,你是否可以清晰的看出他的层次结构。

    • 首先定义了一个立即执行函数,并把此函数的执行结果赋值给func。
    • 需要注意立即执行函数中this.va=va这行代码,由于立即执行函数没有调用者,所以在进入可执行上下文时,this会被赋值为Global(浏览器中为window对象)。
    • 更需要注意立即执行函数,返回的是一个闭包,在这里一定要注意一个问题:this是在进入可执行上下文时创建的。
    • 也就是说此段代码执行完成后,func的值应该是这样的:
    func = function(){
        va += this.va;
        return va;
    }

    只不过此时他的父级作用域是立即执行函数而已。

    三、在init方法中,注意如下代码:

    var func = (function(va){
        this.va = va;
        return function(){
            va += this.va;
            return va;
        }
    })(function(va1, va2){
        var va3 = va1 + va2;
        return va1;
    }(1,2));
    //省略代码....

        va又为一个立即执行函数,这个立即执行函数接受了两个参数va1,va2,但只返回了va1。以此为据,那么可以确定va的值也就为1。接着就执行this.va=va这句代码,由于当前this为window,所以参数va的值被赋值到了window的一个叫va的属性上。

    四、在init方法中,加上输出语句:

    var func = (function(va){
        this.va = va;
        return function(){
            va += this.va;
            return va;
        }
        })(function(va1, va2){
            var va3 = va1 + va2;
            return va1;
        }(1,2));
        
        console.log(func(20));
    
        this.func = func;
        console.log(this.func(100));
    }

    主要分析两个console.log,也是产出结果的时候到了。

    • 第一个console.log输出的是func(20),这里一定要注意调用者是没有具体指定的,此时默认的就是Global(也就是widnow对象),因此输出为:2
    • 第二个console.log输出的是this.func(100),可以看到this.func与func是指向同一个函数的引用,但此时的调用者则指定为this,也就是当前对象的实例,因此输出为:NaN。

           原因:this(当前对象的实例)作为调用者,在func的函数中va += this.va这句代码中的this是指向当前对象的实例,但当前对象的实例上是没有va属性的。如果你调试跟踪会发现va是有值的,他的值为:1,这是为什么呢?这就是作用域链,va虽然在当前作用域没有,但在父级(也就是window的作用域下)是存一个叫va的属性的。

    总结

         通过此段示例代码的分析,我们可以体会到要深入理解Javascript代码,必须要明白且深度掌握他的:闭包、this、原型链(作用域链)、立即调用函数表达式、函数等概念和机理。此类概念每时每该都充斥任务一个库或者框架的代码中,有了他们做为基石,理解和看懂别人的Js代码就so easy了。

  • 相关阅读:
    Python第二弹--------类和对象
    Python第一弹--------初步了解Python
    Java标记接口
    CentOS7下的YUM源服务器搭建详解,过程写的很详细(转)
    CentOS7.0安装Nginx 1.10.0
    QT中C++与Html端通信例子
    QT基础:QMainWindow学习小结
    QT基础:QT 定时器学习
    QT3D场景快速绘制入门学习
    QT编译错误:cannot find file: *.pro
  • 原文地址:https://www.cnblogs.com/cqhaibin/p/6540907.html
Copyright © 2011-2022 走看看