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++ 枚举简单举例

    #include <iostream> enum Enumeration{ VAL1, VAL2, VAL3=100, VAL4 }; int main() { using namespa ...

  2. git tag操作

    git tag //查看tag git tag v1.0.0 c809ddbf83939a89659e51dc2a5fe183af384233 //在某个commit 上打tag git push o ...

  3. maven配置私服中可能遇到的问题

    文章目录 之前要写一个hsf的demo,maven的依赖是需要alibaba的私服的,所以出现了下面的错误. 具体参看另一篇文章:https://blog.csdn.net/dataiyangu/ar ...

  4. webAPI(DOM) 2.1 获取页面元素 | 事件1 | 属性操作 | 节点 | 创建元素 | 事件2

    js分三个部分: ECMAScript标准:js的基本语法 DOM:Ducument Object Model--->文档对象模型--->操作页面的元素 BOM:Browser Objec ...

  5. iOS开发系列-Category

    Category Category是OC中特有的语法.Category的作用 * 可以在不修改原来类的基础上,为这个类扩充一些方法 * 一个庞大的类可以分为多个模块开发 * 一个庞大的类可以由多个人来 ...

  6. Linux 实用指令(10)-RPM和YUM

    目录 RPM 和 YUM 1 rpm 包的管理 1.1 介绍 1.2 rpm包的简单查询指令 1.3 rpm包名基本格式 1.4 rpm包的其他查询指令: 1.5 卸载rpm 包 1.6 安装rpm包 ...

  7. 钉钉小程序----使用阿里的F2图表

    在钉钉小程序中使用F2的图表遇见很多问题 不能点击或者点击错乱的问题还没有解决,因为我解决不了........................... ------------------------- ...

  8. vsftp 被动模式配置

    直接复制粘切过来就能用 这里只讲下配置,安装方法可以直接yum 配置文件修改 anonymous_enable=NO #关闭匿名用户 xferlog_file=/var/log/vsftpd.log ...

  9. Leetcode - K Sum

    List<List<Integer>> kSum_Trim(int[] a, int target, int k) { List<List<Integer>& ...

  10. Makefile 从入门到放弃

    //如有侵权 请联系我进行删除 email:YZFHKM@163.com { 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作, ...