• JS学习笔记3_函数表达式


    1.函数表达式与函数声明的区别

    函数声明有“提升”(hoisting)的特性,而函数表达式没有。也就是说,函数声明会在加载代码时被预先加载到context中,而函数表达式只有在执行表达式语句时才会被加载

    2.闭包

    有权访问另一个函数作用域中的变量的函数。闭包可以访问另一个作用域中的变量,因此闭包得到的变量值是最终值,而不是该变量在某一时刻的值,有一个很经典的例子:

    function createFuns(){
      var result = new Array();
      for(var i = 0;i < 10;i++){
        result[i] = function(){
          return i;
        };
    
        /*
        result[i] = function(arg){
          return function(){
            return arg;
          }
        }(i);//此处匿名函数立即执行的()可以省略,因为function在等号右边出现,不存在歧义(一般形式是(function(){})())
        */
      }
    
      return result;
    }

    createFuns函数返回一组函数,这些函数执行结果都是10(闭包得到的变量值是最终值),但注释中的方式返回函数的执行结果就是i的当前值,因为是值传递

    3.函数表达式中的this

    内部函数无法直接访问外部函数中的this和arguments对象,因为内部函数在搜索这两个变量时,只会搜索到其活动对象为止

    P.S.活动对象是作用域链的实体,作用域链是抽象概念,而活动对象就是这个概念的具体实现。其实作用域链映射到代码里就是变量对象链条,又扯出了变量对象,不用怕,一点都不复杂:

    执行环境(context)中定义的所有变量和函数都保存在变量对象中,如果执行环境是一个函数,那就把函数的活动对象当作变量对象,并作为变量对象链的一环,也就是作用域链的一环。

    一开始函数的活动对象只有一个属性——arguments对象,每在函数内部声明一个自定义属性,就给该函数的活动对象添加一个属性。。。

    嗯,扯了这么多,其实就一句话:this就是活动对象/变量对象的引用

    如果还不大明白,请参考前辈的博文,顺便推荐这位前辈的其它博文,关于js的都很不错

    4.重复声明变量

    不会引起语法错误,会自动忽略多余的声明,但声明同时的初始化操作被执行,例如:

    var x = 1;
    var x = 2;//var声明被忽略,所以不报错,但赋值会被执行
    alert(x);//2

    5.实现块级作用域的思路

    声明一个匿名函数并立即调用,那么匿名函数内部就是块级作用域。具体实现:

    (function(){/*块级作用域*/})();

    注意:需要用圆括号来消除函数表达式与函数声明的歧义(从解释器的角度看就是这样),因为函数声明后面不能直接跟圆括号,而函数表达式可以。

    P.S.示例中的代码只是一种实现IIFE的方式,还有几种,具体请参考[javascript]IIFE立即执行的函数表达式,这篇博文给出了详细的对比

    6.私有变量

    函数内部用var或者function声明的变量是私有变量。(实例无法直接访问,可以通过定义公有函数来提供访问接口)

    而用this.attr = value;方式声明的变量是公有变量。(实例可以直接访问)

    7.闭包、匿名函数、内部函数、内部匿名函数的区别

    • 闭包:有权访问另一个函数作用域中的变量的函数

    • 匿名函数:没有名字的函数表达式

    • 内部函数:在函数内部声明的函数,也就是闭包

    • 内部匿名函数:在函数内部声明的匿名函数,当然,也是闭包

    P.S.滥用闭包可能会占用大量内存,闭包之所以能够访问外层函数作用域中的变量,是因为闭包的活动对象持有外层函数活动对象的引用

    只有在闭包被销毁后,外层函数中的变量才能被销毁,不能及时销毁,所以可能占用大量内存

    8.执行函数的整个过程

    1. 创建执行环境context,context有内部属性[[Scope]]

    2. 更新作用域链ScopeChain

    3. 创建活动对象

    4. 初始化活动对象的this, arguments, 形参等各个属性

    5. 执行函数体

    6. 销毁活动对象(存在闭包时无法销毁)

    7. 更新作用域链

    9.js单例模式与模块模式

    • 单例模式:创建只有一个实例的对象的一种模式,说白了,模式就是方法,设计模式就是前辈总结出来的好方法。js中实现单例模式尤其简单:

      var singleton = {attr1: value1, attr2: value2};

      没错,就是对象字面量,其实就是创建了匿名对象,不知道构造函数的名字,当然无法创建第2个实例了

    • 模块模式:道格拉斯提出的用来增强单例的方法,可以给单例添加私有属性和公有属性(有时候也叫特权属性,表示有权修改私有属性的属性),例如:

      var singleton = function(){
        //私有属性
        var privateStr = 'secret';
        function addPrefix(){
          privateStr = 'this is my ' + privateStr;
        }
      
        //公有属性(特权属性)
        return{//返回一个匿名对象
          getStr : function(){
            addPrefix();
            return privateStr;
          }
        };
      }();//又是匿名函数立即执行
      
      alert(singleton.getStr());

    P.S.如果不需要单例,只要保护私有属性的话,可以这样做:

    function Cat(){
      //私有属性
      var privateStr = 'secret';
      function addPrefix(){
        privateStr = 'this is my ' + privateStr;
      }
    
      //公有属性(特权属性)
      this.getStr = function(){
        addPrefix();
        return privateStr;
      }
    }
    var obj = new Cat();
    alert(obj.getStr());

    参考资料

  • 相关阅读:
    经典假设检验理论记录一二
    阿里云centos7.3安装tomcat8
    PowerDesigner中Name与Code同步的问题
    PowerDesigner中NAME和COMMENT的互相转换
    树形结构的数据库表设计
    Spring mybatis Access denied for user 'root'@'localhost' (using password:YES)
    IOS上架审核问题
    maven自动部署war包到tomcat 问题
    SpringMVC +Hibernate JPA+Spring-data-jpa
    Hibernate4.3.x Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
  • 原文地址:https://www.cnblogs.com/ayqy/p/4403086.html
Copyright © 2020-2023  润新知