JS 进阶必备 —— 闭包、this、箭头函数的实践笔记

闭包、this 和箭头函数是三个常见面试题,也是 js 进阶之路上的拦路虎。这次还用实践熟悉这三个问题。

this 实践

demo

写了一段代码来验证 this 的指向。

    console.log('全局环境的this', this)
    
    function test (){
        console.log('方法中的 this', this)

        function child(){
            console.log('方法中的方法的 this', this)
        }
        child()
    }
    test()

    var obj =  {
        name: "object",
        doSth: function() {
            var oName = "obj function name"
            console.log('对象中的 this', this)
        },
        childObj: {
            name: "childObj",
            doSth: function() {
                var arrow = () => {
                    console.log("对象中箭头函数的this", this)
                }
                arrow()
                console.log('对象的对象中的 this', this)
            }
        },
        doBibao: function() {
            var count = 500
            console.log('闭包构造方法的 this', this)
            return function() {
                console.log('闭包返回结果的 this', this)
            }
        }
    }
    obj.doSth()
    obj.childObj.doSth()
    var mbb = obj.doBibao()
    mbb()

    setTimeout(obj.doSth, 1800)
    setTimeout(obj.doSth.bind(obj), 2000)

    var fun = function() {
        console.log('匿名函数中的 this', this)
    }
    fun()

    class Vue {
        constructor(options){
            this.name = "vue"
            this.type = "object"
            this.options = options
            console.log('构造函数的 this', this)

            options.log()
        }
    }

    var vm = new Vue({
        log: function () {
            console.log('构造函数找那个传递方法的 this', this)
        }
    })

    function bibao (){
        var count = 101
        console.log('闭包外的 this', this)
        return function() {
            count++
            console.log('闭包中的 this', this)
            return count;
        }
    }
    var bi = bibao()
    console.log(bi())

    var mArrow = () => {
        console.log('箭头函数中的 this', this)
    }
    mArrow()
    console.log('以下内容为异步执行')

    setTimeout(() => {
        console.log('延时箭头函数中的 this', this)
    }, 1000)

最后结果如图:


console.log

从中可以得到一些结论(以下都是非严格模式下的测试结果):

  • 全局变量的 this 指向 Window。
  • 全局变量中的具名函数、匿名函数、闭包函数、箭头函数都指向 Window。
  • 在对象中同步调用,this 指向当前对象。
  • 在对象中异步调用,this 已重新指向 Window,如果需要指向对象需要使用 bind() 方法改变 this 指向。

个人理解:this 作为上下文始终会有一个唯一指向对象。这个对象要么指向 Window 要么指向当前对象。当调用对象中方法时,方法中的 this 即指向方法。之后 this 会重新指向 Window。

call & apply & bind

说到 this 不得不说下函数的间接调用方法 apply 和 call 了。他们作用相同,唯一不同点在于 apply 方法的第二个参数接收一个参数数组。而 call 方法接收若干个参数。这两个方法的第一个参数传递的都是 this 指向。

    function sayHello(p1, p2) {
        console.log(`hello ${p1} and ${p2}`)
    }

    sayHello('jack', 'rose')
    sayHello.call(this, 'jack', 'rose')
    sayHello.apply(this, [ 'jack', 'rose' ])

如上代码,其实输出结果是一样的。第一种写法是一种语法糖,第二种和第三种才是真正的方法执行。可以看到它们的第一个参数为 this。所以,call 方法和 apply 方法是可以改变函数的 this 指向的。
而我们之前提到的 bind 函数用于重新指定函数的 this 并且创建出一个新的函数的。引用 MDN 上的说法就是:

bind() 方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

箭头函数和一般函数的区别

箭头函数使用更加简洁的表达方式替代匿名函数而深受喜爱。然而箭头函数与一般匿名函数的不同点在于:箭头函数拥有静态的上下文环境,不会因为不同的调用而改变。
以下是我理解的静态函数与一般函数的不同点:

  • 在箭头函数中,this 是静态的不可变的,所以bind、call和apply方法修改this不起作用:
    var mor = {
        name: "mor"
    }

    var ar = () => {
        console.log("箭头函数的this变化", this)
    }

    ar() // Window
    ar.call(mor, 123) // Window 如果是匿名函数则返回 mor 对象结果
    var newAr = ar.bind(mor)
    newAr() // Window 如果是匿名函数则返回 mor 对象结果
  • 箭头函数拥有静态的上下文环境,不会因为不同的调用而改变。如下例子中箭头函数的 this 指向了 Window 对象。
    var person = {
        sex: "male",
        age: 28
    }

    person.log = function(){
        console.log("01:" + this.sex + "-" + this.age) // 指向 person 对象
    }

    person.log02 = () => {
        console.log("02:" + this.sex + "-" + this.age) // 指向 Window
    }

    person.log() // 01:male-28
    person.log02() // 02:undefined-undefined

闭包函数的原理和用途

这里来简单实现一个闭包:

    function add() {
        var a = 100
        var b = 50
        return function(){
            console.log(a + b)
        }
    }

    var count = add()
    count() // 150

我对闭包的理解就是:在函数中返回函数表达式的写法。

闭包的主要用途有:

  • 避免被垃圾回收机制回收方法结果和变量,使变量始终保存在内存中,实现缓存的功能。如需清空缓存需要将值变为 null。
  • 通过闭包获取方法中的局部变量。

最后

注意,以上都是本人对于这些知识点的理解,可能会有描述不太准确的地方。如有错误还请评论指出,万分感谢。
这里简单记录了一下我对于 this、闭包和箭头函数的理解~更多内容可以看下我提供的参考资料。

参考资料

打个广告

链家上海研发中心招聘前端、后端、测试。
机会不多,需要内推机会的请将简历发送至 dingxiaojie001@ke.com

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

推荐阅读更多精彩内容