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

第二个疑惑点

几道关于this的经典练习题的理解与分析的更多相关文章

  1. MYSQL经典练习题,熟悉DQL

    MYSQL经典练习题 (本练习题可让你熟悉DQL,快速的上手DQL) 首先,先在数据库中建立基本数据库以及表项: DROP DATABASE IF EXISTS `test`; CREATE DATA ...

  2. 【转载】经典10道c/c++语言经典笔试题(含全部所有参考答案)

    经典10道c/c++语言经典笔试题(含全部所有参考答案) 1. 下面这段代码的输出是多少(在32位机上). char *p; char *q[20]; char *m[20][20]; int (*n ...

  3. Python经典练习题1:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?

    Python经典练习题 网上能够搜得到的答案为: for i in range(1,85): if 168 % i == 0: j = 168 / i; if i > j and (i + j) ...

  4. 【视频+图文】Java基础经典练习题(一)输出2-100之间的素数,及素数个数

    目录 第一题:判断2-100之间有多少个素数,并输出所有素数. 1.视频讲解: 2.思路分析: 代码讲解:以i=4为例 4.为大家准备了彩蛋: 能解决题目的代码并不是一次就可以写好的 我们需要根据我们 ...

  5. Python入门36道经典练习题

    [程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? num_list=[] cou=0 for i in range(1,5): for j in rang ...

  6. SQL 经典练习题

    create database 练习题gouse 练习题go create table Student( Sno char(3) primary key, Sname char(8) not null ...

  7. python基础阶段 经典练习题 拾英札记(2)

    因为编程的练习题是交互式的,在不断调试和不断渐进完善中,你会有一种成就感和快乐感,不断的修缮,不断的尝试. 其实,认知自己,和探索世界,也是这样的啊. 只要不放弃,要坚持. #7  根据列表lt,实现 ...

  8. MySQL经典练习题

    表名和字段 –1.学生表 Student(s_id,s_name,s_birth,s_sex) –学生编号,学生姓名, 出生年月,学生性别 –2.课程表 Course(c_id,c_name,t_id ...

  9. SQL经典练习题50--mysql

    --1.学生表 Student(Sid,Sname,Sage,Ssex)? --Sid 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 --2.课程表? Course(Cid, ...

随机推荐

  1. 暑假集训test-8-29

    今天瓜成一坨了. 瓜的说不出话来. 直接退役算了我. T1 傻逼题,但是我傻逼地敲了一个线段树合并,然后把空间炸了,只剩20分, 直接dfs维护子树大小,子树中最大最小值即可统计答案. //Achen ...

  2. Feign远程调用源码阅读

  3. MongoDB点滴

    0 http://blog.csdn.net/mydeman/article/details/6652387 1 MongoDB 内置连接池,不需要使用额外的连接池驱动 Note: The Mongo ...

  4. spark-submit 应用程序第三方jar文件

    第一种方式:打包到jar应用程序 操作:将第三方jar文件打包到最终形成的spark应用程序jar文件中 应用场景:第三方jar文件比较小,应用的地方比较少 第二种方式:spark-submit 参数 ...

  5. verifier 调试内存泄露

    没啥技术含量,都是老段子了, 这次记下来,只是我想说,我也做过,留个念相. 前置条件,电脑里面必须得有Verifier,有了之后把自己的驱动加进去, WinDBG上双机,然后就可以跑了,跑一段时间就可 ...

  6. The linux command 之进程

    ******************查看进程********************* 一.使用ps命令 [me@linuxbox ~]$ ps PID TTY TIME CMD pts/ :: ba ...

  7. Python自学:第五章 使用函数range( )

    # -*- coding: GBK -*- for value in range(1,5): print(value) 输出为: 1 2 3 4

  8. SPR, subpixel rendering

    参考例子:https://www.grc.com/ctwhat.htm https://en.wikipedia.org/wiki/Subpixel_rendering http://archernz ...

  9. [JZOJ3339]【NOI2013模拟】wyl8899和法法塔的游戏

    题目 题目大意 给你一个数列,每次给出\(r,a,b\),你要找到\(l\in [a,b]\)使得\([l,r-1]\)的异或和最小, 并且要修改\(r\)位置的数. 思考历程 当我看到这题的时候,已 ...

  10. JavaScript - 常用对象相关

    1. String对象 length : 字符串的长度 charAt(index) : 返回指定位置的字符串, 下标从0开始 indexOf(str) : 返回指定的字符串在当前字符串中首次出现的位置 ...