• 几道关于this的经典练习题的理解与分析


    1.

    var num = 1;
    var myObject = {
        num: 2,
        add: function() {
            this.num = 3;
            (function() {
                console.log(this.num);
                this.num = 4;
            })();
            console.log(this.num);
        },
        sub: function() {
            console.log(this.num)
        }
    }
    myObject.add();
    console.log(myObject.num);
    console.log(num);
    var sub = myObject.sub;
    sub();

    答案是:(严格模式下会报错!非严格模式下输出如下答案)

    1  3

    3

    4

    4

    分析:

    1. 首先调用myObject.add(),函数内的this是指向myObject的,所以这里的this.num = 3实际是覆盖了myObject的num,此时add外层同级的num变成了3;接下来是自执行函数,自执行函数没有任何对象调用它则是指向全局,所以第一个console输出的是1,然后将全局的num改成了4;最后执行的this.num是输出3这个没什么难理解的了~
    2. myobject.num现在已经被修改成了3,因此第二个输出的是3
    3. 全局的num已经改成了4,因此第三个输出的是4
    4. sub = myObject.sub这句将myObject.sub函数赋值给sub,而实际上造成了this的丢失,这里sub()执行时this是指向全局,输出的是全局的num,即4

    2.

            var name = 'window'        
            var person1 = {
                name: 'person1',
                show1: function () {
                    console.log(this.name)
                },
                show2: () => console.log(this.name),
                show3: function () {
                    return function () {
                        console.log(this.name)
                    }
                },
                show4: function () {
                    return () => console.log(this.name)
                }
            }
            var person2 = { name: 'person2' }
    
            person1.show1()
            person1.show1.call(person2)
    
            person1.show2()
            person1.show2.call(person2)
    
            person1.show3()()
            person1.show3().call(person2)
            person1.show3.call(person2)()
    
            person1.show4()()
            person1.show4().call(person2)
            person1.show4.call(person2)()

    答案:

    person1.show1()   // person1
    person1.show1.call(person2)  // person2
    
    person1.show2()   // window
    person1.show2.call(person2)  // window
    
    person1.show3()()  // window
    person1.show3().call(person2)   // person2
    person1.show3.call(person2)()  // window
    
    person1.show4()()   // person1
    person1.show4().call(person2)   // person1
    person1.show4.call(person2)()   // person2

    我容易错的点在show2和show4,分析如下:

    person1.show2() 实际是执行:()=>console.log(this.a),根据“箭头函数的this指向外层作用域”,该箭头函数外层没有函数了,即指向全局作用域

    这里很有迷惑性的地方是:容易把person1这个对象的{}大括号理解为函数作用域,实际上对象并没有生成作用域!!

    person1.show2.call(person2)这个根据“箭头函数直接应用bind、call、apply不起作用”,很容易可知这里this依然指向全局

    person1.show4()()实际是执行了以下两步:

    1. 执行:function () { return ... }返回一个箭头函数
    2. return回来的这个箭头函数再执行

    该箭头函数执行时它的外层作用域是这个show4的function,这个function的this指向person1,所以箭头函数中的this指向person1

    很容易可得person1.show4().call(person2)指向person1

    person1.show4.call(person2)()这个执行的时候,显式绑定将person2绑定到show4这个function上,那么依上面的分析,该箭头函数指向show4的function,所以箭头函数的this指向了person2

    注意箭头函数:

    箭头函数没有自己的this,它的this指向的是调用箭头函数的外层function,箭头函数的this就是指向,如果箭头函数没有外层函数,则指向window。

    下面看另一道题:

            var name = 'window'
    
            function Person(name) {
                this.name = name;
                this.show1 = function () {
                    console.log(this.name)
                }
                this.show2 = () => console.log(this.name)
                this.show3 = function () {
                    return function () {
                        console.log(this.name)
                    }
                }
                this.show4 = function () {
                    return () => console.log(this.name)
                }
            }
    
            var personA = new Person('personA')
            var personB = new Person('personB')
    
            personA.show1()
            personA.show1.call(personB)
    
            personA.show2()
            personA.show2.call(personB)
    
            personA.show3()()
            personA.show3().call(personB)
            personA.show3.call(personB)()
    
            personA.show4()()
            personA.show4().call(personB)
            personA.show4.call(personB)()

    答案:

    personA.show1()  // personA
    personA.show1.call(personB)  // personB
    
    personA.show2()   // personA
    personA.show2.call(personB)  // personA
    
    personA.show3()()   // window
    personA.show3().call(personB)  // personB
    personA.show3.call(personB)()  // window
    
    personA.show4()()  // personA
    personA.show4().call(personB)   // personA
    personA.show4.call(personB)()  // personB

    这组例子和上一题的对比我有两个疑惑点:

    1. show2为什么会输出两次personA?不是指向外层作用域吗?这里外层作用域难道不是全局了?
    2. new绑定的优先级不是高于显示绑定吗?为什么personA.show1.call(personB)还能变成personB?

    首先针对第一个疑惑点要说明的是:构造函数创建对象后其实多了一层构造函数的作用域,如图所示:

    可以看到personA的scope和person1的差别:person1中的show1作用域仅仅是global,而personA中show1的函数作用域链是从构造函数产生的闭包开始的!

    所以这样就很容易能知道show2的执行为什么会不同了:

    personA的show2中的this指向构造函数形成的闭包函数,即Person函数,所以这里输出personA

    第二个疑惑点

  • 相关阅读:
    数据结构与算法题目集(中文)6-12 二叉搜索树的操作集 (30分)
    性能测试案例
    jmeter 常用监听器
    性能测试面试题
    jmeter 之 dubbo
    jmeter5 分布式测试,未成功
    jmeter之OPMS项目管理参数化与断言实战;
    jmeter时间戳处理相关
    jmeter控制器下遍历一组参数
    The Wall (medium)
  • 原文地址:https://www.cnblogs.com/ningyn0712/p/11750216.html
Copyright © 2020-2023  润新知