探索JS的函数表达式(你不知道的js)

函数是js中既强大又容易令人困惑的特性,首先定义函数的方法有两种:函数声明和函数表达式


定义函数的两种方法

许多浏览器给函数定义了一个非标准的name属性,console.log(functionName.name) =》 “functionName”,匿名函数的name属性则是一个空的字符串

函数声明的重要特征就是函数声明提升,可以在声明函数之前调用

在函数内部使用函数声明定义函数,只能创建局部函数


递归

递归函数是一个函数通过名字调用自身的情况下构成的


递归

arguments.callee是一个指向正在执行的函数的指针,在这里等同于factorial(num-1)


闭包

闭包就是指有权访问另一个函数内部变量的函数,通常是一个函数包含一个函数的形式,这句话大多数前端er都知道,但如何去理解闭包呢

首先要理解作用域和作用域链的问题,当某个函数被调用时,会创建一个执行环境以及相应的作用域链,然后,使用arguments和其他命名参数来初始化函数的活动对象,在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三位,以此类推,直至全局对象,也就是作用域链的终点:全局执行环境,举个🌰


创建闭包函数

后台的每个执行环境都有一个表示变量的对象——变量对象,全局环境的变量始终存在(window),而像createComparisonFunction()函数这样的局部环境的变量对象,只在函数执行时存在,在创建createComparisonFunction()函数时,会预先创建一个包含全局变量对象的作用域链,被保存在内部的[[Scope]]属性中,这个对象对应的是一个对象的列表,列表中的对象仅能javascript内部访问,没法通过语法访问。

当调用createComparisonFunction()函数时,会为函数创建一个执行环境,然后通过复制函数的[[Scope]]属性中的对象,构建起执行环境的作用域链。作用域链的本质是一个指向变量对象的指针列表,只引用但不实际包含的变量对象。


调用compareNames()函数的过程中产生的作用域链之间的关系

通常函数执行完成,就是销毁局部活动对象,但上面的🌰中的匿名函数的作用域链包含了外部函数的活动对象,所以即使外部函数执行完毕,其局部活动对象也不会销毁,直到匿名函数被销毁。

闭包与变量

由于作用域链的配置机制是一个引用,所以闭包只能获取包含函数中任何变量的最终值。🌰

闭包函数的引用值

由于这里没有参数传递,这里的i是作用域链中引用的对象,即使它的值是基本类型,所以这里输出10个10。

想要获得0-9这样的结果,可以将i作为实参传递给匿名函数的形参,中间是有一个复制的操作,或者使用ES6的let,详情参考这里

this对象

this对象是在运行时基于函数的执行环境进行绑定的,全局环境中指向window,当函数被作为某个对象调用时,指向调用的对象。this始终指向直接调用它的对象。

每个函数在被调用时,会自动取得两个特殊的变量this和arguments,内部函数搜索这两个变量时,只会在活动对象里搜索,并不会向上查找。可以通过变量赋值的方法实现访问。

内存泄漏

众所周知,js在函数执行完毕后会通过垃圾回收机制将函数内部的活动对象销毁,而闭包函数由于作用域链一直引用对象,所以不能销毁,这样就很容易造成内存泄漏问题,所以使用的时候也要记得手动销毁。


模仿块级作用域

js是没有块级作用域的概念的,所以在块语句中定义的变量,实际是包含在函数中的变量,而非语句中的变量。

私有变量

任何函数中定义的变量,都可以认为是私有变量,因为不能从外部访问到。

有权访问私有变量和私有函数的公有方法叫特权方法

利用私有和特权成员,可以隐藏那些不想被直接修改的数据。🌰

在构造函数中定义特权方法

静态私有变量

通过在私有作用域中定义私有变量和函数,创建特权方法。🌰

创建特权方法

这个🌰中的Person构造函数和setName()和getName()方法一样,都有权访问私有变量name,这种模式下,变量name就变成一个静态的,由所有实例共享的属性。

模块模式

模块模式是为单例(只有一个实例)创建私有变量和特权方法。🌰


模块模式创建特权方法

这里的单例就是application,私有对象components数组,返回对象的getComponentCount()和registerComponent()方法都是有权访问components对象的特权方法。

增强的模块模式

在返回对象之前加入对其增强的代码,这种模式适合那些单例必须是某种类型的实例,同时还必须添加某些属性和方法对其增强情况。🌰


增强的模块模式

小结

本文仅是个人的看法,如有错误和补充,欢迎指正和交流。

参考红皮书的一些学习所得

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  •   函数表达式是 JavaScript 中的一个既强大有容易令人困惑的特性。定义函数的的方式有两种: 函数声明; ...
    霜天晓阅读 835评论 0 1
  • 定义函数的方式有两种:函数声明和函数表达式。 函数声明的一个重要特征就是函数声明提升,意思是在执行代码前会先读取函...
    oWSQo阅读 687评论 0 0
  • 定义函数的方式有两种:一种是函数声明,另一种就是函数表达式。函数声明的语法: 关于函数声明的一个重要特征就是函数声...
    LemonnYan阅读 90评论 0 0
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,145评论 1 32
  • 第3章 基本概念 3.1 语法 3.2 关键字和保留字 3.3 变量 3.4 数据类型 5种简单数据类型:Unde...
    RickCole阅读 5,163评论 0 21