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

作用域链

  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.以对象的方法调用函数。当惰性函数定义在处理以上三种情况的时候,使用新的变量名调用挥着是时以对象的方法来调用函数,那么该函数在执行的时候并不会更新自身,而是执行旧函数体的内容.

<script>
    //01 声明函数foo
    function foo() {
        console.log("foo!");
        foo = function () {
            console.log("foo! foo!");
        }
    }

    //02 为foo函数对象添加属性
    foo.description = "foo函数的描述信息";

    //03 把foo函数赋值给其他的变量
    var func = foo;

    //04 把foo函数赋值给对象中的方法
    var obj = {
        showFoo:foo
    }

    //05 验证并演示输出
    func(); //foo!
    func(); //foo!
    console.log(func.description);  //foo函数的描述信息
    //总结:01 如果把函数赋值给其他的变量,那么在以其他变量的方式调用时不会更新自身,还是执行旧的函数体

    obj.showFoo();  //foo!
    obj.showFoo();  //foo!
    console.log(obj.showFoo.description);   //foo函数的描述信息
    //总结:02 如果把函数赋值给对象的方法,那么在以对象方法形式调用时不会更新自身,还是会执行旧的函数体。

    foo();  //已经更新过foo函数 foo! foo!
    foo();  //已经更新过foo函数 foo! foo!
    console.log(foo.description);   //undefined
</script>

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

组成: 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. 模式优点:
    在执行一次性的初始化任务时保护全局的命名空间。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容