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. C++从string中删除所有的某个特定字符【转载】

    转载自https://www.cnblogs.com/7z7chn/p/6341453.html C++中要从string中删除所有某个特定字符, 可用如下代码 str.erase(std::remo ...

  2. detours学习

    最近学习detours3.0,总结下学习过程,给后来学习者一点参考,也便于自己以后复习 首先应该知道detours可以干什么,学习之前最好看一下detours文档,这个文档很简单,只有4篇文章,相对比 ...

  3. union, enum, and struct, 以及结构填充和位字段实现。

    Table 4-9 Compiler storage of data objects by byte alignment Type Bytes Alignment char, bool, _Bool ...

  4. 【POJ】3259 Wormholes

    题目链接:http://poj.org/problem?id=3259 题意:n个农场,m条双向路径,w条单向路径(虫洞).单向虫洞路径是负值.农夫想知道自己能不能看到自己(X). 题解:其实刚开始没 ...

  5. Activiti学习笔记7 — ReceiveTask机器自动任务的使用

    一. 创建流程规则,如下图 二.发布流程 /** * 2.发布一个流程 */ @Test public void testDeployProcess() { RepositoryService rep ...

  6. 判断APP是否已安装

    NSString *str = [NSString stringWithFormat:@"%@://%@",[dic objectForKey:@"ios_url_sch ...

  7. vim 底行模式 操作命令

    1. 当前设置行号: set nonu    取消行号显示:                    2.   :set number 显示行号     (下次使用就没有了,要设置脚本 vim ~/ . ...

  8. 修改jupyter保存文件目录

    参考: https://blog.csdn.net/lyxuefeng/article/details/79469189 步骤 打开 cmd 输入命令 jupyter notebook --gener ...

  9. 【JDK】:java.lang.Integer源码解析

    本文对JDK8中的java.lang.Integer包装类的部分数值缓存技术.valueOf().stringSize().toString().getChars().parseInt()等进行简要分 ...

  10. IPsec分析/测试/

    一   局域网拓扑图 局域网环境搭建步骤: (升级最新版本 ,恢复出厂设置后) 1 两台网关wan口直连,分别接两台pc , 2 局域网网络测试,正常情况下PC1 和PC2 互通 ,测试通过在进行ip ...