作用域和闭包

假装没事ソ 提交于 2020-02-02 10:45:17

知识点

  • 执行上下文
  • this
  • 作用域
  • 作用域链
  • 闭包

  • 执行上下文

    • 范围:一段<script>或者一个函数
    • 全局:变量定义、函数声明
    • 函数:变量定义、函数声明、this、arguments
12345678910111213141516171819202122
//全局中或某个函数体中,程序会把变量声明提前,并且用undefined占位(即赋值)//也会把函数声明提前console.log(a);//undefinedvar a = 100;  fn('kk');//kk 20function fn(name) {    age = 20;    console.log(name, age);    var age;}//详细运行过程如下// var a;// //函数fn也被提前;// console.log(a);//因为只是声明提前,赋值没有提前,所有undedined// a = 100;// fn('kk');///////////// function fn(name) {//  var age;//同理,声明被提前 name也被赋值//  console.log(name, age)// }
123456789
fn1();//正常执行function () {}//这里fn2声明被提前,还没有赋值,所有报错:undefinedfn2();var fn2 = function() {}
12345678
var a = 10;console.log(this.a);//10function fn(name) {    var a = 1;    console.log(this.a);//this是运行环境的this,而不是定义环境的this    console.log(arguments);//函数参数的集合体}fn('kk');//10;["kk",callee:....]
  • this 要在执行时才能确认值,定义时无法确认(所以程序中的bug在执行时才会报错,定义时无法发现)

    • 作为构造函数执行

      123456
      var Foo = function(name) {    //this = {}    this.name = name;    //return this;}var f = new Foo('kk');
    • 作为对象属性执行

      1234567
      var obj = {    name:'A',    printName: function() {        console.log(this.name);    }}obj.printName();
    • 作为普通函数执行

      1234
      function fn() {    console.log(this);}fn();//window
    • call apply bind

      1234567
      function fn(name) {    this.name = name;    console.log(this.name);}fn.call({age:20},'kk');//kkfn.apply({age:20},['kk']);//kkfn();//undefined
1234
var fn = function() {    console.log(this.name);}.bind({name:'kk'})//bind 必须是函数表达式,函数声明是不可以的fn();//kk
  • 作用域

    • 没有块级作用域

      1234
      if(true) {    var name = "kk";}console.log(name);//kk
    • 只有函数和全局作用域

      1234567
      var a = 'outer';function fn() {    var a = 'inner';    console.log(a);//inner}console.log(a);//outerfn();
  • 作用域链 父级作用域是在定义是决定的,而不是运行时决定

    123大专栏  作用域和闭包n>456
    var g = 'global'function fn() {    //g为'自由变量',即当前作用域没有的变量    console.log(g);//global 从父级中找,当前作用域的父级作用域是全局作用域}fn();
  • 闭包 闭包的使用场景两种

    • 函数作文返回值

      12345678910111213
      function F1() {    var a = 100;    return function() {        console.log(a);        //a是自由变量,所以会从父级寻找值        //又因为函数的父级作用域是定义时决定,而不是运行时决定        //所以父级作用域是F1,a为100    }}var f1 = F1();var a = 200;f1();//100
    • 函数参数传递

      1234567891011121314
      //函数作为参数到另一个函数里执行function F1() {    var a = 100;    return function() {        console.log(a);    }}var f1 = F1();function F2(fn) {    var a = 200;    fn();}F2(f1);//100
总结
  • 说一下对变量提升的理解

    12
    变量定义函数声明(注意和函数表达式的区别)
  • 说明this几种不同的使用场景

    1
    4种看前面
  • 创建10个a标签 点击时候打印出对应的序号

    12345678910111213
    //错误var i,a;for(i=0;i<10;i++) {    a = document.createElement('a');    a.innerHTML = i;    a.addEventListener('click', function(e) {//每个i对应一个click共10个        e.preventDefault();        console.log(i);//无论点击哪个结果都是 10        //因为 i 是自由变量,到父级(全局作用域)寻找i的值,而这时循环结束        //i已经是10    })    document.body.appendChild(a);}
123456789101112131415
//正确var i;for(i=0;i<10;i++) {    (function (i){        var a = document.createElement('a');        a.innerHTML = i;        a.addEventListener('click', function(e) {//每个i对应一个click共10个            e.preventDefault();            console.log(i);            //i是自由变量,从父级(自执行函数)中找值,由于i作为参数传递            //所以从参数中取i的值,分别是0~9        })        document.body.appendChild(a);    })(i);}
  • 如何理解作用域

    123
    自由变量作用域链闭包的两个场景
  • 实际开发中闭包的应用

    12345678910111213141516
    //闭包实际应用中主要用于封装变量,收敛权限function isFirstLoad() {    var _list = [];    return function(id) {        if(_list.indexOf(id)>=0){            return false;        }else{            _list.push(id)            return true;        }    }}var firstLoad = isFirstLoad();console.log(firstLoad(10));//trueconsole.log(firstLoad(10));//false
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!