首先看下面的代码:  

  var x = 1       
  var f1 = function( f ) {
  var x = 2 ;
  f( ' console.log( x ) ' )
  }
  var f2 =  function( ) {
  var x = 2 ;
  eval( ' console.log( x ) ' )
  }
  f1( eval )  // 1
  f2( )  // 2
  
  eval 是一个 global 对象的内置函数,即便在 window 对象内,它也可以作为全局函数使用。
  如果你对结果有疑问,那为了搞懂原因,需要了解 JavaScript 一个重要的知识点: 作用域 ,上下文环境
  
  很多书籍和大牛都会引用 上下文环境 这一概念,在我看来,上下文环境只是一种更加繁琐的理解方式,甚至可以说是完全多余,如果去函数内寻找对应的属性,只会发现一个包含scope关键字的属性与作用域对应,在我看来,上下文环境只是一个被人为创造的词汇,是为了便于他人理解而创建出来的抽象概念。
 
  如果你接受了我上面的观点,那作用域就同时囊括了上下文环境的特性,以下两个观点是理解作用域的关键:
 
  第一,只有在函数执行的时候作用域才会生成,函数体内代码未被执行的情况作用域是不会生效的;
  第二,函数体所在处才是代码执行的地方,依据第一个观点,也即作用域生成的地方,是以此寻找上级作用域的起点。
 
  和其他强类型语言不同,JavaScript 能创造独立作用域的方式还不够丰富,函数声明就是其中之一,在不考虑闭包等其他操作联通作用域的情况下,同级作用域之间是绝对屏蔽的,即便是嵌套的作用域,也只允许子作用域向上查询,父级作用域无法向下进入子作用域。
 
  需要注意的是,不是子作用域的所有变量都可以向上去查询,比如 this ,作为一门极其灵活而又混沌的语言,js不会允许这种情况发生,于是ES6这一标准提出了箭头函数的概念,其作用是为 this 开辟一条通向上级作用域的特快通道,将 this 发射出去,这在本质上使得 JavaScript 的逻辑变得更加灵活了,不像其他语言具有较强的模式化属性。
 
  有点脱离主题了,说回为什么两者的输出结果不一致,引用函数其实也是一个包装过的概念,比如本例中的 f ,它的本质只是栈内存的索引地址,更重要的是这一地址指向的并不是存储在堆内存里的函数对象,而是指向另一个栈内存内的地址 eval ,eval 才是真正指向函数的指针,也可以直接将其理解为 eval 函数在栈内存内的唯一代言,毫无疑问,函数体内部才存在作用域,作用域的本质不过是附着了很多变量属性的对象,需要注意的是,此例中并不是指 f1 和 f2 这两个函数对象,而是指其引向的函数体 { } 这个对象。
 
  如果你真正理解了上面我这段话,那么也就不难理解结果不同的原因,f( 'console.log( x ) ' )在执行的时候实际上还是去寻找 eval 所指向的作用域,而 eval 的上级作用域是全局作用域,其作用域内 x 的值是为 1 。
 
  
 

JavaScript中函数引用调用和函数直接调用的区别的更多相关文章

  1. 一篇文章把你带入到JavaScript中的闭包与高级函数

    在JavaScript中,函数是一等公民.JavaScript是一门面向对象的编程语言,但是同时也有很多函数式编程的特性,如Lambda表达式,闭包,高阶函数等,函数式编程时一种编程范式. funct ...

  2. JavaScript中常见的数组操作函数及用法

    JavaScript中常见的数组操作函数及用法 昨天写了个帖子,汇总了下常见的JavaScript中的字符串操作函数及用法.今天正好有时间,也去把JavaScript中常见的数组操作函数及用法总结一下 ...

  3. JavaScript中常见的字符串操作函数及用法

    JavaScript中常见的字符串操作函数及用法 最近几次参加前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等.如果你经常参加笔试或者也是一个过来人,相信 ...

  4. JavaScript中变量声明有var和没var的区别

    JavaScript中变量声明有var和没var的区别 JavaScript中有var和没var的区别 Js中的变量声明的作用域是以函数为单位,所以我们经常见到避免全局变量污染的方法是 (functi ...

  5. 【转载】在Javascript中 声明时用"var"与不用"var"的区别

    原文链接:http://www.2cto.com/kf/201204/128406.html[侵删]   Javascript声明变量的时候,虽然用var关键字声明和不用关键字声明,很多时候运行并没有 ...

  6. 在Javascript中 声明时用"var"与不用"var"的区别,== 和 ===的区别

    今天,被问到两个JS问题,当时没回答到重点,问题虽然看起来简单,但是细节却马虎不得,在此做下记录: 1. 在Javascript中 声明时用"var"与不用"var&qu ...

  7. JavaScript中的闭包和匿名函数

    JavaScript中的匿名函数及函数的闭包   1.匿名函数 2.闭包 3.举例 4.注意 1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没 ...

  8. JavaScript中的闭包与匿名函数

    知识内容: 1.预备知识 - 函数表达式 2.匿名函数 3.闭包 一.函数表达式 1.定义函数的两种方式 函数声明: 1 function func(arg0, arg1, arg2){ 2 // 函 ...

  9. 谈谈javascript中的变量提升还有函数提升

    在很多面试题中,经常会看到关于变量提升,还有函数提升的题目,所以我就写一篇自己理解之后的随笔,方便之后的查阅和复习. 首先举个例子 foo();//undefined function foo(){ ...

  10. javascript中的两个定时函数setTimeOut()和setInterVal()的区别

    js中经常性要用到间隔几秒或暂停几秒执行某个函数, 简单介绍我从网上收集到setTimeOut()和setInterVal()的区别1.setInterVal()介绍 1)定义 setInterval ...

随机推荐

  1. js操作BOM对象

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  2. Unity中用Mono插件解析xml文件

    1.解压压缩包,把文件夹拖到脚本文件夹下 Mono是第三方基金会开发的开源的东西,通过Mono基础上开发的程序可以在各个系统下运行.开发语言是C#. 用插件解析比较高效,平台运行稳定.使用简单. Un ...

  3. 四、Linux的常用命令

    linux常用命令可以参考这位前辈的:https://www.cnblogs.com/gaojun/p/3359355.html 这篇博文介绍的比较详细!

  4. TLS通信过程

    TLS通信过程 握手与密钥协商过程 基于RSA握手和密钥交换的客户端验证服务器为示例详解TLS/SSL握手过程 sequenceDiagram client->>server: clien ...

  5. getString与optString的区别

    JSONObject.getString("key"):当对象中没有key属性的时候,会抛出No value for "key"的异常: public Stri ...

  6. java——形参与实参

    看了很多的文章,稍微有一些的总结:对最基本的形参与实参有了一定的理解,虽然还是不够深入. 1.基本概念 形参:全称为"形式参数"是在定义函数名和函数体的时候使用的参数,目的是用来接 ...

  7. SQL优化清单

    SQL优化清单 1.from 语句中包含多个表的情况下,把记录数少的表放在前面 2.where 语句中包含多个条件时,将刷选多的条件放前面 3.避免使用select * ,因为这样会去查询所有列的数据 ...

  8. Python入门学习例子——从Hao123获取图片

    import urllib.requestimport re #获取html页面内容def getHtml(url): data=urllib.request.urlopen(url) pageCon ...

  9. Scientific Toolworks Understand 软件教程

    系统:Ubuntu16.04 x64 安装 安装包 下载地址: part1:http://download.csdn.net/detail/p942005405/9711128 part2:http: ...

  10. Mac上配置maven+eclipse+spark开发环境

    1.安装jdk 2.下载scala-ide.官网:http://scala-ide.org 3.安装maven 4.在eclipse中,配置maven的安装了路径.偏好设置--->maven-- ...