作用域链和函数内部this指向问题以及bind、call、apply方法

作用域链

  • 作用域是相对于变量而言的, 其意义就在与查找变量(确定变量的来处, 变量是否可以访问到, 确定变量在当前位置是否可以取到值)

    • JS分函数作用域和全局作用域
    • JS变量又遵循就近使用的原则
      1. 首先在使用该变量的当前作用域查找 , 如果当前作用域声明了这个变量,就可以确定结果;如果没有查找到,进入步骤2
      2. 查找当前作用域的上级作用域,也就是当前函数的上级函数,看看上级函数中有没有声明
      3. 再查找上级函数的上级函数,直到全局作用域为止
      4. 如果全局作用域中也没有,我们就认为这个变量未声明 xxx变量 is not defined
  • 如何确定函数作用域的上一级作用域

    • 函数的上一次作用域取决于函数声明时的位置,而不是函数调用时的位置。

    • 函数就声明在全局作用域内

      <script>
      function fn(callback){
      var age=18;
      callback()
      } fn(function(){
      console.log(age); //age is not defined
      //分析:age变量:
      //1、查找当前作用域:并没有
      //2、查找上一级作用域:全局作用域 (此时函数就声明在全局作用域内)
      //3、此时age变量就获取不到fn函数内部的age变量
      //看上一级作用域,不是看函数在哪里调用,而是看函数在哪里编写,函数声明在全局,它的上一级作用域就是全局作用域。
      //-->因为这种特别,我们通常会把作用域说成是:词法作用域
      })
      </script>
    • 函数声明在其它的函数内 (闭包就是个典型案例)

      <script>
      function fn(){
      var a=5;
      return function(){
      a++;
      console.log(a); //a变量肯定是可以访问的
      }
      }
      var f1=fn(); //f1指向匿名函数
      f1(); //6
      f1(); //7
      f1(); //8
      //分析:a变量:
      //1、查找当前作用域:并没有
      //2、查找上一级作用域:fn函数作用域 (此时函数就声明在fn函数内) //-->一般认为函数执行完毕,变量就会释放,但是此时由于js引擎发现匿名函数要使用a变量,所以a变量并不能得到释放,而是把a变量放在匿名函数可以访问到的地方去了
      //-->a变量存在于f1函数可以访问到的地方,当然此时a变量只能被f1函数访问
      </script>

函数内部的this指向问题(箭头函数不适用)

  • 函数的4种调用方式

    1. 普通函数调用的方式

      <script>
      var age = 18; //该age声明在全局作用域下,其就会被挂载到window对象上,即window.age=18
      var p = {
      age: 15,
      say: function () {
      console.log(this.age); //this指向window
      }
      }
      var s1 = p.say //s1 = function () {console.log(this.age);}
      s1(); //函数调用, 结果为 18
      </script>
    2. 方法的调用

      <script>
      var age = 18; //该age声明在全局作用域下,其就会被挂载到window对象上,即window.age=18
      var p = {
      age: 15,
      say: function () {
      console.log(this.age); //this指向p对象
      }
      }
      p.say() //结果为15 //p.say获取的就是p对象内部的say方法,然后方法后+()就是方法的调用。
      </script>
    3. new调用(构造函数)

      <script>
      var age = 18;
      var p = {
      age: 15,
      say: function () {
      console.log(this.age);
      //此时this指向构造函数new出来的实例,而实例中并没有初始化age属性
      }
      }
      new p.say() //构造函数调用, 结果为undefined
      </script>
      <script>
      var age = 18;
      var p = {
      age: 15,
      say: function (age) {
      this.age = age
      console.log(this.age);
      }
      }
      new p.say(22) //构造函数调用, 结果为22
      </script>
    4. 上下文方式(call、apply、bind)

      <script>
      var length = 21; //window.length = 21
      function f1() {
      console.log(this.length);
      }
      f1.call([1, 3, 5]) //结果为3,此时this指向[1,3,5]数组
      f1.apply(this) //结果为21,此时this指向window
      f1.call(5) //undefinde , 此时this指向 Number,其没有length属性
      f1.bind(this)() //结果为21
      //bind方法只改变函数f1内部this指向,而不会让函数执行,想让其执行,需要在后面手动调用+()
      </script>

bind、call、apply共同点和区别

  • 三个方法都可以改变函数内部this指向
  • bind和call、apply的区别是,bind方法不会让函数执行,而call、apply的调用会让函数也跟着执行
  • call和apply的区别就在与给函数传参的方式不同
    • call(this指向对象, 参数1,参数2,参数3) 参数以逗号分隔,依次排下去
    • apply(this指向对象, [参数1,参数2,参数3]) 参数包裹在一个数组中

作用域链和函数内部this指向问题以及bind、call、apply方法的更多相关文章

  1. this的指向问题、bind/call/apply改变this指向

    this的指向问题 全局作用域下的this指向 无论是否是严格模式,全局作用域下的this始终指向window 函数内部的this 严格模式下: function test() { 'use stri ...

  2. [译]JavaScript:函数的作用域链

    原文:http://blogs.msdn.com/b/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx 在JavaScr ...

  3. python中函数的嵌套和作用域链

    1.三元运算if条件成立的结果 if 条件 else 条件不成立的结果例如: a=20 b=10 c=a if a>b else b print(c) 2.命名空间 全局命名空间:创建的存储“变 ...

  4. JS中的函数声明和函数表达式的区别,即function(){}和var function(){},以及变量提升、作用域和作用域链

    一.前言 Uncaught TypeError: ... is not a function function max(){}表示函数声明,可以放在代码的任何位置,也可以在任何地方成功调用: var ...

  5. 从函数作用域和块级作用域看javascript的作用域链

    在ES6之前,javascript只有全局作用域和函数作用域.所谓作用域就是一个变量定义并能够被访问到的范围.也就是说如果一个变量定义在全局(window)上,那么在任何地方都能访问到这个变量,如果这 ...

  6. 函数的作用域、作用域链以及return关键字

    1.作用域 全局作用域:在函数外部使用var关键字定义的变量 局部作用域:在函数内部使用var关键字定义的变量 特点   (1)局部变量无法直接影响全局变量    (2)在局部作用域中可以使用全局作用 ...

  7. javascript篇-----函数作用域,函数作用域链和声明提前

    在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的(也就是我们不能在代码段外直接访问代码段内声明的变量),我们称之为块级作用域,然而,不同于 ...

  8. js修改函数内部的this指向(bind,call,apply)

    js修改函数内部的this指向 在调用函数的时候偶尔在函数内部会使用到this,在使用this的时候发现并不是我们想要指向的对象.可以通过bind,call,apply来修改函数内部的this指向. ...

  9. 改变JavaScript中函数的内部this指向!

    改变JavaScript中函数的内部this指向! 第一种方法 call call 可以 调用函数 + 改变函数内的this指向! var obj = { name: 'lvhang' } funct ...

随机推荐

  1. Java基础 -- 字符串(格式化输出、正则表达式)

    一 字符串 1.不可变String String对象是不可变的,查看JDK文档你就会发现,String类中每一个看起来会修改String值的方法,实际上都是创建一个全新的String对象,以包含修改后 ...

  2. P4180 严格次小生成树[BJWC2010] Kruskal,倍增

    题目链接\(Click\) \(Here\). 题意就是要求一个图的严格次小生成树.以前被题面吓到了没敢做,写了一下发现并不难. 既然要考虑次小我们就先考虑最小.可以感性理解到一定有一种次小生成树,可 ...

  3. POJ1179Polygon(区间dp)

    啊~~ 被dp摁在地上摩擦的人 今天做了一道区间dp的题(POJ1179Polygon) 题目: Polygon Time Limit: 1000MS   Memory Limit: 10000K T ...

  4. linux的sed命令(一)

    转自:https://www.cnblogs.com/ginvip/p/6376049.html Sed 简介 sed 是一种新型的,非交互式的编辑器.它能执行与编辑器 vi 和 ex 相同的编辑任务 ...

  5. 深入理解Java自带的线程池和缓冲队列

    前言 线程池是什么 线程池的概念是初始化线程池时在池中创建空闲的线程,一但有工作任务,可直接使用线程池中的线程进行执行工作任务,任务执行完成后又返回线程池中成为空闲线程.使用线程池可以减少线程的创建和 ...

  6. <HTML>页面与互联网

    托管 1.数据传输:托管公司允许你在一定时间内向访问者发送的页面和数据量. 2.备份:公司是否对你的页面定期备份,从而在服务器出现硬件故障时能够恢复. 域名 www.starbuzzcoffee.co ...

  7. Oracle ORA-08104报错处理方法及注意事项

    [环境介绍] 系统环境:IBM P740 8205-E6C (AIX) + 11.2.0.3.0 Oracle RAC [背景介绍] 故障描述:数据库表空间超过90%,无法进行扩容表空间,需要业务侧清 ...

  8. Turtle库的学习积累

    1.什么是turtle库 Python的Turtle库是一个直观有趣的图形绘制函数库,Turtle英文翻译过来是乌龟的意思,在绘图时可以想象成一只乌龟在移动. 2.绘图坐标体系 海龟的移动方向 3.绘 ...

  9. Excel——使用INDEX和SMALL实现条件筛选

    如下图所示,如何实现Excel自带的筛选功能呢?(对的,就是软件自带的功能) 如何实现: B13的公式:=IFERROR(INDEX(B:B,SMALL(IF(A$1:A$10=B$12,ROW($1 ...

  10. chrome浏览器开发常用快捷键之基础篇-遁地龙卷风

    1.标签页和窗口快捷键 打开新的标签页,并跳转到该标签页 Ctrl + t 重新打开最后关闭的标签页,并跳转到该标签页 Ctrl + Shift + t 跳转到下一个打开的标签页 Ctrl + PgD ...