作用域链&闭包&函数相关

作用域链

  1. 在JS中函数可以创建作用域;
  2. 函数中又可以创建函数(可以开辟新的作用域);
  3. 函数内部的作用域可以访问外部的作用域;
  4. 如果有多个函数嵌套,那么久会构成一个链式的访问结构,也就是作用域链;
  5. 注意:函数内部作用域可以访问外部的作用域,但是外部的作用域却无法访问内部的作用域。

作用域注意点

  1. 在获取值和设置值的时候都是访问变量;
  2. 并非在函数内部写了变量,这个变量就属于当前函数,而是必须使用var 关键字声明的变量才属于当前函数;
  3. 函数在声明的时候,里面的代码并不会执行,只有在函数调用时才会执行;
  4. 声明函数时候的函数名,其实也是一个变量名,可以通过这个变量名来进行设置和赋值;
  5. 注意:在变量内部使用var 关键字声明一个变量并不会把同名的全局变量覆盖掉。

变量搜索原则

  1. 在使用变量的时候,首先在当前作用域中查找,如果找到就直接使用;
  2. 如果没有找到就去上一级作用域中查找,如果找到就直接使用,如果没有找到就重复上面的过程;
  3. 直到0级作用域。
    注意点:在当前作用域中使用var 关键字声明变量并不会覆盖掉上一级作用域中的同名变量。

闭包

闭包:通过某种方式实现的一个封闭的,包裹的对外不公开的结构或空间。
原理:变量的访问原则(即上一级的作用域无法访问下一级的作用域),其实函数本身就是闭包。

实现思路

  1. 我们需要能够在函数外部访问函数内部的变量,正常情况无法访问;
  2. 在函数内部如果新创建函数,那么按照作用域链的原则,这个新创建的内部函数能够访问到函数中的这些变量;
  3. 我们如果能够操作函数中新创建的函数,那么就能够操作函数中的变量(如访问和设置等);
  4. 如果要能够操作函数中新创建的函数,那么需要在函数中把新创建的函数返回。
  5. 调用函数,接收并得到其返回值(是一个函数);
  6. 调用返回值(函数),通过函数传参的方式来设置函数中的变量;
  7. 调用返回值(函数),通过在函数内部再次return的方式来访问函数中的变量。

基本模式
在函数内部创建函数(内部函数),在这个内部函数中,可以操作外部函数中的变量;

  1. 在函数(外部)中创建函数(内部函数),在该函数(内部函数)中操作外部函数中的变量;
  2. 在外部函数中,把内部函数作为返回值返回;
  3. 调用外部函数,并接受其返回值(是一个函数);
  4. 调用接受到的返回值(内部函数),来间接的操作外部函数的变量。

作用
最基本的作用:闭包中的变量更安全,只能通过特定的接口来访问。
说明:1. 获取函数内部的数据操作只能通过指定的接口;
2. 对变量的设置操作会更安全,我们可以在设置数据之前进行校验;
3. 延长变量的生命周期。

进程和线程
进程是指系统中正在运行的一个应用程序。
线程:一个进程中可以有一个或者多个线程,线程是CPU调度中最小的单位,是真正执行任务的。
多线程:一个进程中可能有多条线程,多条线程之间并发执行多个不同的任务。
单线程:一个进程中只有一条线程,即同一时间只能执行一个操作,只能干一件事情。
串行执行:按照顺序一个一个的执行任务;
并发执行:多条线程同时执行任务
javascript是单线程的
JS执行任务:
1.渲染任务;
2.代码的主要任务;
3.事件性任务(定时器任务..)。

  1. setTimeOut 和闭包执行:
    方法一:for循环的同时执行即时函数
for (var i = 0; i < 10; i++) {
    (function (j) {
        setTimeout(function () {
            console.log(j);
        },0);
    })(i);
}

方法二:for循环的同时计时器的执行保存在队列中,由于传参被保留,for循环完成后,打印值为0~9.

for (var i = 0; i < 10; i++) {
        setTimeout((function (j) {
            return function () {
                console.log(j);
            }
        })(i),0);

}
  1. div 事件和闭包
    方法一:
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
    (function (j) {
        divs[j].onclick = function () {
            alert('我是第' +(j+1)  + '个div')
        }
    })(i);
}

方法二:

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
        divs[i].onclick = (function (j) {
            return function () {
                alert("我是第"+ (j+1) + "div");
            }
        })(i);
    }

函数的特殊性:本身是对象,且能够提供作用域。

  1. 函数可以在运行时动态创建,还可以在程序执行过程中创建;
  2. 函数可以赋值给变量,可以被扩展,甚至是删除;
  3. 函数可以作为其他函数的参数和返回值;
  4. 函数可以拥有自己的方法和属性。

函数回调:回调函数(回调),当我们把某个函数作为参数传递给另一个函数的时候,这个函数就称为回调函数

  1. 函数作为其他函数的参数:
function foo(callBack) {
     callBack();
}
function demo() {
    console.log('demo');
}
foo(demo);//demo
  1. 对象的方法作为其他函数的参数
  var person = {
        name : "zs",
        showName :function () {
            console.log(this.name);
        }
    }
    function  foo(callBack) {
        callBack();
    }
foo(person.showName)
  1. 函数作为函数的返回值
 function sum() {
        var a = 0;
        return function () {
            a ++;
            return a;
        }
    }

    var func = sum();
    console.log(func());
    console.log(func());
    console.log(func());
    console.log(func());

惰性函数
某个函数直到第一次使用的时候才被正确的定义,并且其具有向后惰性,执行更少的工作。
应用场景:函数有一些初始化的准备工作要做,且只需要执行一次的情况。
特点:能够更新自己(函数)的实现。
缺点:1.当重新定义自身的时候,已经添加到原始函数的任何属性都会丢失。2.如果函数被赋值给了其他的变量或者是对象方法,那么在使用变量或者是对象方法调用时仍然会执行旧的函数体。

 function foo() {
        console.log("foo!");
        foo = function () {
            console.log("new foo!");
        }
    }

    //函数的调用
    //foo();  //foo!
    //foo();  //new foo!

问题:1. 添加属性;2.把函数赋值给新的变量;3.以对象的方法调用函数。当惰性函数定义在处理以上三种情况的时候,使用新的变量名调用挥着是时以对象的方法来调用函数,那么该函数在执行的时候并不会更新自身,而是执行旧函数体的内容.


即时函数
定义:在函数定义之后立即执行该函数。

组成: 1. 使用函数表达式来定义函数(匿名函数,注意不能使用函数声明方式) ;2. 在函数表达式末尾添加一组(),表示立即执行当前函数;3.将整个函数包装在()中,有两种方式。

作用:1. 用来将所有的代码包装到当前的作用域中,并且不会将任何的变量泄露到全局作用域中;2. js中没有代码块作用域,而函数是js中唯一可以创建作用域的;3. 即时函数就是利用了函数创建作用域这一点,来实现对一些需要封装且不允许外部访问的操作。

优点:1. 不会产生全局变量,在即时函数内部定义的所有变量都仅仅只是该函数的局部变量,不会造成全局变量污染问题;2. 具有更好的封装性,外部无法访问到该函数内部的数据。

   //第一种写法
    (function () {
       console.log("即时函数的第一种写法");
    }());

    //第二种写法
    (function () {
        console.log("即时函数的第二种写法");
    })();

即时对象初始化:

  1. 结构特征:
    1. 提供一个对象,在该对象内部提供一个init初始化方法;
    2. 使用()把对象包装起来(让字面量变成表达式);
    3. 然后随即调用init方法,完成初始化操作。
  2. 基本结构:
    ({}).init();
  3. 模式优点:
    在执行一次性的初始化任务时保护全局的命名空间。

你可能感兴趣的:(作用域链&闭包&函数相关)