目录
1.2.1 关于 this 指向最后调用函数的那个对象,该怎么理解?
1.3.1 call()、apply()、bind() 三者区别
1.3.2 使用 call() 解决 setTimeout 内 this 丢失的问题
1.3.3 ☆★☆★ 函数返回的函数被调用,除非被 call 修改 this 指向,否则都是 window 在调用 ☆★☆★
1.3.6 在函数内使用 call 显式绑定一个对象,实现函数内部 this 指向 始终指向该对象
1.3.7 冷门知识:forEach、map、filter 第二个参数可以改变 this 指向
1.3.8 ☆★☆★ 总结了一下 显式绑定 需要注意的点 ☆★☆★
1.4.2 字面量形式创建对象 VS new 构造函数创建对象
1.5.1 基本用法 —— 通过查找作用域链,确定箭头函数的 this
1.5.2 字面量对象中,普通函数与箭头函数的区别: 只有一层函数的题目
1.5.3 字面量对象中,普通函数与箭头函数的区别:函数嵌套(返回函数)的题目
1.5.4 构造函数对象中,普通函数和箭头函数的区别:只有一层函数的题目
1.5.5 构造函数对象中,普通函数和箭头函数的区别:函数嵌套(返回函数)的题目
1.5.6 箭头函数 不能被 显式绑定函数(call、apply、bind)修改 this 指向
1.5.7 ☆★☆★ 箭头函数必坑指南 / 不能使用箭头函数的场景 ☆★☆★
非严格模式下,this 指向全局对象(window / self / global)
严格模式下,函数内的 this 指向 undefined,全局中的 this 指向不会改变
举个栗子~
- "use strict";
-
- // var 定义的变量 a 挂载到 window 对象上
- var a = 10;
-
- function foo () {
- // 严格模式下,函数内 this 指向 undefind
- console.log('this1 --- ', this) // undefined
-
- // 报错,Uncaught TypeError: Cannot read properties of undefined (reading 'a')
- console.log(this.a)
-
- console.log(window.a) // 10
- }
-
- // 严格模式 不会改变全局中 this 的指向
- console.log('this2', this) // window
-
- foo();
let、const 声明的全局变量,不会被绑定到 window 上
var 声明的全局变量,会被绑定到 window 上
- let a = 10
- const b = 20
-
- function foo () {
- console.log(this.a) // undefined
- console.log(this.b) // undefined
- }
-
- foo();
-
- console.log(window.a) // undefined
关键点:
- // window 中的 a
- var a = 1;
-
- function foo () {
- // 函数中的 a
- var a = 2
-
- console.log(this) // Window{...}
-
- // 打印的是 this.a,不是 a,因此是 window 下的 a(是 window 调用的 foo 函数)
- console.log(this.a) // 1
- }
-
- foo()
再举个例子~
- var a = 1
-
- function foo () {
-
- var a = 2
-
- function inner () {
- // inner 内没有 a,因此往上面的 foo 的函数作用域找
- // foo 内有 a,但是 foo 是 window 调用的,foo 内的 this 就是 window
- // 打印的是 this a,不是 a,因此要判断正确的 this,也就是 window
- // 最终输出 1
- console.log(this.a)
- }
-
- inner()
- }
-
- foo()
当 函数引用 有 上下文对象 时,如 obj.foo() 的调用方式,foo() 内的 this 指向 obj
也就是说,谁调用函数,函数内的 this 就指向谁(无论是普通对象、还是全局对象),this 永远指向最后调用它的那个对象(不考虑箭头函数)
foo() 定义在 window 上,但是是 obj 对象调用了它(也就是给 obj 临时加了个 foo() 方法)
obj.foo() 相当于 window.obj.foo(),此时的 this 指向 最后调用函数 的对象,也就是 obj(window 不是最后调用函数的对象,obj 才是最后一个)
- function foo () {
- console.log(this.a)
- }
-
- var obj = { a: 1, foo }
-
- var a = 2
-
- obj.foo() // 1
隐式丢失:被 隐式绑定 的函数,在特定的情况下,会丢失绑定对象
容易发生 隐式丢失 的两种情况:
关键点:
- function foo () {
- console.log(this.a)
- };
-
- var obj = { a: 1, foo };
-
- var a = 2;
-
- var foo2 = obj.foo;
-
- var obj2 = { a: 3, foo2: obj.foo }
-
- // -----------------------------------------------------------------
-
- // 此处的 this 指向 obj,被 obj 调用进行了隐式绑定,因此打印 obj 中的 a
- // this 指向调用者 obj
- obj.foo(); // 1
-
- // foo2 指向了 obj.foo 函数
- // 由于使用 另一个变量 foo2 给函数取别名,发生了 this 丢失,导致 obj 丢了
- // obj 丢了,就找上层 this;是 window 调用了 foo2,除了 obj 外,上层就是 window 了
- // 综上:foo2() 发生了隐式丢失,调用者是 window,使得 foo() 中的 this 指向 window
- foo2(); // 2
-
- // obj2.foo2() 发生了隐式丢失,调用者是 obj2,使得 foo() 中的 this 指向 obj2
- obj2.foo2(); // 3
如果把 一个函数 当成参数 传递到 另一个函数 中时,会发生 隐式丢失 的问题
隐式丢失,与包裹着 函数参数 的 外层函数 的 this 指向无关(比如外层函数的 this 指向 obj2对象,但是隐式丢失后,this 和 obj2 不会有关系,只跟 window/undefined 有关系)
- function foo () {
- console.log(this.a)
- }
-
- function doFoo (fn) {
- // 因为这里是 window 调用的它,所以 doFoo() 函数内的 this 本来就指向 window
- console.log(this) // Window{...}
-
- // 函数当参数传入,发生了隐式丢失(也就是 obj 没了),因此 foo 指向了 window
- fn() // 2
- }
-
- var obj = { a: 1, foo }
-
- var a = 2
-
- var obj2 = { a: 3, doFoo }
-
- // 将 obj.foo 当成参数传递到 doFoo 函数中,发生了隐式丢失,因此 foo 指向了 window
- doFoo(obj.foo)
-
- // doFoo 此时被 obj2 调用,this 指向 obj2
- // 但是由于 obj.foo 函数被当作参数传入,导致 this 隐式丢失
- // 隐式丢失 与包裹着的函数 this 没有关系,也就是和 obj2 没有关系
- // 所以指向 window,打印 window 中的 a,而不是 obj2 中的 a
- obj2.doFoo(obj.foo) // 2
严格模式下:
- "use strict"
-
- function foo () {
- console.log(this.a)
- }
-
- function doFoo (fn) {
- // 被 obj2 调用,this 指向 obj2
- console.log(this) // { a:3, doFoo: f }
-
- // 函数当参数,发生 this 隐式丢失,隐式丢失和 函数参数 的 外层函数this 没有关系
- // 因此指向 window,也就是 window.a = 2
- // 又因为 严格模式 函数内的 this 始终为 undefind,因此获取不到 a 变量,报错
- fn() // Uncaught TypeError: Cannot read property 'a' of undefined
- }
-
- var obj = { a: 1, foo }
-
- var a = 2
-
- var obj2 = { a: 3, doFoo }
-
- obj2.doFoo(obj.foo)
再来一个,常见的 setTimeout,将函数作为参数
- var obj2 = {
- a: 2,
-
- foo1: function () {
- // 普通函数内的 this 指向调用它的对象
- console.log(this.a) // 2
- },
-
- foo2: function () {
- // setTimeout 回调中的 this(对象调用绑定的 this),会丢失,因此指向 window
- setTimeout(function () {
- console.log(this) // window
- console.log(this.a) // 3
- }, 0)
- }
- }
-
- // 全局变量
- var a = 3
-
- obj2.foo1()
- // 虽然是被 obj2 调用的,但是由于定时器接收函数作为参数,导致 this 丢失
- // 因此指向的 obj2 丢失,因此最终指向了 window
- obj2.foo2()
通过 call()、apply()、bind() 方法,直接指定 this 的绑定对象,如 foo.call(obj))
- function foo () {
- console.log(this.a)
- }
-
- var obj = { a: 1 }
-
- var a = 2
-
- // 默认绑定,因此打印 window 上的 a
- foo() // 2
-
- // call() 改变 this 指向,并立即执行
- foo.call(obj) // 1
-
- // apply() 改变 this 指向,并立即执行
- foo.apply(obj) // 1
-
- // bind() 改变 this 指向,需要手动执行
- // 此处使用 bind 创建了一个新的函数,但是没有用变量接收这个新函数,更没有调用
- // 此处 没有 调用函数,只是新生成了一个函数
- foo.bind(obj) // 不执行
-
- // 如果接收到的第一个参数为空、null、undefined 的话,则不改变 this
- foo.call() // 2
- foo.call(null) // 2
- foo.call(undefined) // 2
注意:
- var obj1 = {
- a: 1
- }
-
- var obj2 = {
- a: 2,
-
- foo1: function () {
- console.log(this.a)
- },
-
- foo2: function () {
- setTimeout(function () {
- console.log(this) // { a: 1 }
- console.log(this.a) // 1
- }.call(obj1), 0)
- }
- }
-
- var a = 3
-
- // 此处 this 指向 调用函数的对象,也就是 obj2
- obj2.foo1() // 2
-
- // 此处函数内有个定时器,定时器的参数是个函数,导致 this 丢失
- // 给定时器内的参数函数添加 call 方法,将他绑定到 obj1 上
- obj2.foo2()
匿名函数的 this,永远指向 window
- var obj1 = {
- a: 1
- }
-
- var obj2 = {
- a: 2,
- foo1: function () {
- console.log(this.a)
- },
- foo2: function () {
- function inner () {
- console.log(this) // window
- console.log(this.a) // 3
- }
- inner()
- }
- }
-
- var a = 3
-
- obj2.foo2()
虽然是 obj2 调用了 foo2(),但是 foo2 内部的函数,不是 obj2 调用的,而是 window 调用的
再举个例子~(这个例子很重要):
- function foo () {
- console.log(this.a)
- return function () {
- console.log(this.a)
- }
- }
- var obj = { a: 1 }
- var a = 2
-
- // foo.call(obj) 将 this 指向 obj,并自动执行函数,因此打印 1
- // foo 函数返回了一个函数,这个匿名函数被调用,foo.call(obj)()【 相当于 foo()() 】
- // 此时,新返回的匿名函数,不是被 obj 调用,而是被 window 调用,因此打印 2
- foo.call(obj)()
换汤不换药系列~:
- var obj = {
- a: 'obj',
- foo: function () {
- console.log(this.a)
- return function () {
- console.log(this.a)
- }
- }
- }
- var a = 'window'
- var obj2 = { a: 'obj2' }
-
- // obj.foo() 打印 obj.a = obj,返回一个函数
- // obj.foo 调用后,返回的函数被调用,且是 window 调用,所以打印 window.a = window
- obj.foo()() // obj、window
-
- // obj.foo 被改变 this 指向 obj2,并立即执行,打印 obj2.a = obj2
- // obj.foo 被 obj2 调用后,返回的函数被调用,且是 window 调用,所以打印 window.a = window
- obj.foo.call(obj2)() // obj2 window
-
- // obj.foo 先被调用执行,this 指向调用函数的对象,所以打印 obj.a = obj
- // obj.foo 执行后返回一个函数,这个函数被 call 绑定到了 obj2 上,并自动执行
- // 所以打印 obj2.a = obj2
- obj.foo().call(obj2)
foo.call() 和 foo().call() 的区别:
- function foo () {
- console.log(this.a)
- }
- var obj = { a: 1 }
- var a = 2
-
- // foo() 会正常打印出 window 下的 a,也就是 2
- foo()
-
- // foo.call(obj )由于显式绑定了 this,所以会打印出 obj 下的 a,也就是 1
- foo.call(obj)
-
- // foo().call(obj) 开始会执行 foo() 函数,打印出 2
- // 实际上是对 foo() 函数的 返回值 执行.call(obj) 操作
- // foo() 函数的返回值是 undefined,因此报错
- foo().call(obj)
如果 函数返回的值 是一个函数呢?如下所示:
- function foo () {
- console.log(this.a)
- return function () {
- console.log(this.a)
- }
- }
- var obj = { a: 1 }
- var a = 2
-
- // 虽然 foo() 函数返回了一个匿名函数,但是并没有调用它,调用应该写成 foo()()
- foo() // 2
-
- // 改变了 foo this 指向,直接调用 foo,但是并没有调用 foo 的返回函数
- // 所以纸打印了一次 obj 内的 a
- foo.call(obj) // 1
-
- // 先让 window 调用 foo,此时 this 指向 window,打印 window.a = 2
- // 再让 foo() 的返回函数,调用 call 方法,改变 this 指向 obj
- // 并且 call 让函数直接调用,因此打印 obj.a = 1
- foo().call(obj) // 2,1
- function foo () {
- console.log(this.a)
- return function () {
- console.log(this.a)
- }
- }
- var obj = { a: 1 }
- var a = 2
-
- // window 调用,打印 window.a = 2
- foo() // 2
-
- // 让 foo 通过 bind 指向 obj
- // 由于 bind 不会自动执行新生成的函数,因此 foo.bind(obj) 并没有执行 foo
- foo.bind(obj) // 不打印
-
- // 先执行了 foo,此时打印 window.a = 2
- // 使用 bind 改变了 foo 返回函数的 this 指向
- // 由于 bind 不会自动执行新生成的函数,因此 并没有让 foo 的返回函数执行,所以不打印
- foo().bind(obj) // 2
- function foo1 () {
- console.log(this.a)
- }
-
- var a = 1
-
- var obj = {
- a: 2
- }
-
- var foo2 = function () {
- // 函数内部显示绑定一个对象
- foo1.call(obj)
- }
-
- // 使用 window 调用 函数,而函数内部 绑定到了 obj 上,所以打印 obj.a = 2
- foo2()
-
- // 将 foo2 显式绑定到 window 上
- // 而 foo2 内部仍然是 foo1 被指向 obj,所以打印 obj.a = 2
- foo2.call(window)
这三个 JavaScript 方法,都接受两个参数:
下面的三个方法内,都将 this 指向了 obj,所以打印的也全是 obj.a = obj
- function foo (item) {
- console.log(item, this.a)
- }
-
- var obj = {
- a: 'obj'
- }
-
- var a = 'window'
-
- var arr = [1, 2, 3]
-
- // arr.forEach(foo, obj)
- // arr.map(foo, obj)
-
- arr.filter(function (i) {
- // return 之前所有选项都可以打印出来
- // this.a,this 被第二个参数指定为了 obj 对象
- console.log(i, this.a)
- return i > 2
- }, obj)
this 指向新生成的对象
- var name = 'aaa';
-
- // 构造函数
- function Person (name) {
- this.name = name
- this.foo1 = function () {
- console.log(this.name)
- }
- this.foo2 = function () {
- return function () {
- console.log(this.name)
- }
- }
- }
-
- var person1 = new Person('Test');
-
- // 打印的是对象里的值
- person1.foo1() // Test
-
- // 执行匿名函数,是 window 调用的,因此打印 window 下的 name
- person1.foo2()() // aaa
使用 new 构造函数创建的对象,字面量形式创建的对象,基本没什么大的区别
如果对象中,存在 函数类型(不是箭头函数)的属性,那么解法都一样
举个栗子~:
- var name = 'window'
- function Person (name) {
- this.name = name
- this.foo = function () {
- console.log(this.name)
- // 匿名函数最终都是被 window 执行的,除非被显示绑定给其他对象
- return function () {
- console.log(this.name)
- }
- }
- }
- var person2 = {
- name: 'person2',
- foo: function() {
- console.log(this.name)
- // 匿名函数最终都是被 window 执行的,除非被显示绑定给其他对象
- return function () {
- console.log(this.name)
- }
- }
- }
-
- var person1 = new Person('person1')
-
- person1.foo()() // person1 window
- person2.foo()() // person2 window
主要容易考的感觉还是在 函数返回函数 的时候,多看几遍揣摩吧
个人理解:如果函数返回了(匿名)函数,被返回的(匿名)函数若要执行,则一般是 window 执行的,除非被显式绑定给其他对象
- var name = 'window'
-
- function Person (name) {
- this.name = name
- this.foo = function () {
- console.log(this.name)
- return function () {
- console.log(this.name)
- }
- }
- }
-
- var person1 = new Person('person1')
-
- var person2 = new Person('person2')
-
-
- // foo 先被 call 显示绑定给 person2
- // call 会自动执行函数,因此打印了 person2.name = person2
- // 返回的匿名函数,又被 window 直接执行(因为没被显示绑定给其他对象)
- // 因此打印 window.name = window
- person1.foo.call(person2)() // person2 window
-
- // foo 先执行,直接打印 person1.name = person1
- // foo 返回的函数被显示绑定给了 person2,并自动执行
- // 因此虽然是匿名函数,但是有了 call 显示绑定,所以打印 person2.name = person2
- person1.foo().call(person2) // person1 person2
箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值;
如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this;否则,this 为 undefined
综上所述,箭头函数内的 this 始终由外层作用域决定;无法被 call 等方式修改;在定义时就已经确定 this 指向了,执行时无法改变 this 指向
举个栗子~
- var obj = {
- name: 'obj',
-
- // 箭头函数
- foo1: () => {
- console.log(this.name) // window
- },
-
- // 普通函数
- foo2: function () {
- console.log(this.name) // obj
- // 箭头函数
- return () => {
- console.log(this.name) // obj
- }
- }
- }
-
- // 全局变量
- var name = 'window'
-
- // 对象 obj 不属于作用域(作用域只有全局作用域、函数作用域、块级作用域)
- // foo1() 箭头函数的外层作用域是 window,所以会打印出 window
- obj.foo1()
-
- // 首先会执行 obj.foo2(),这不是箭头函数,所以它里面的 this 指向调用它的 obj 对象
- // 返回的匿名函数是一个箭头函数,它的 this 由外层作用域决定,也就是 foo2 的函数作用域
- obj.foo2()()
思路分析:
理解上面的概念很重要呢,涉及到了 80% 的题目~O(∩_∩)O
不使用箭头函数,this 指向调用函数的对象,也就是 obj1
使用箭头函数,this 由外层作用域决定,也就是 window 全局作用域(对象不是作用域哈)
- var name = 'window'
-
- var obj1 = {
- name: 'obj1',
- // 不使用箭头函数
- foo: function () {
- console.log(this.name)
- }
- }
-
- var obj2 = {
- name: 'obj2',
- // 使用箭头函数
- foo: () => {
- console.log(this.name)
- }
- }
-
- // 不使用箭头函数,this 指向调用函数的对象,也就是 obj1
- obj1.foo() // obj1
-
- // 使用箭头函数,this 由外层作用域决定,也就是 window 全局作用域(对象不是作用域哈)
- obj2.foo() // window
普通函数,谁调用指向谁,指向 obj
返回的普通函数,谁调用指向谁,匿名函数没有 call 绑定,所以是 window 调用,指向 window
箭头函数,this 由外层作用域决定,定义的时候就决定了,不是执行的时候决定的
返回的箭头函数,this 由外层作用域决定,定义的时候就决定了,不是执行的时候决定的
举个栗子~
- var name = 'window'
-
- var obj1 = {
- name: 'obj1',
- // 普通函数,返回普通函数
- foo: function () {
- console.log(this.name)
- return function () {
- console.log(this.name)
- }
- }
- }
-
- var obj2 = {
- name: 'obj2',
- // 普通函数,返回箭头函数
- foo: function () {
- console.log(this.name)
- return () => {
- console.log(this.name)
- }
- }
- }
- var obj3 = {
- name: 'obj3',
- // 箭头函数,返回普通函数
- foo: () => {
- console.log(this.name)
- return function () {
- console.log(this.name)
- }
- }
- }
-
- var obj4 = {
- name: 'obj4',
- // 箭头函数,返回箭头函数
- foo: () => {
- console.log(this.name)
- return () => {
- console.log(this.name)
- }
- }
- }
-
- // 普通函数,谁调用指向谁,指向 obj
- // 返回的普通函数,谁调用指向谁,匿名函数没有 call 绑定,所以是 window 调用,指向 window
- obj1.foo()() // 'obj1' 'window'
-
- // 普通函数,谁调用指向谁,指向 obj2
- // 返回的箭头函数,this 由外层作用域决定
- // 定义的时候就决定了,不是执行的时候决定的,也就是在 obj2.foo 函数作用域里,指向 obj2
- obj2.foo()() // 'obj2' 'obj2'
-
- // 箭头函数,this 由外层作用域决定
- // 定义的时候就决定了,外层作用域是 window(没有对象作用域),指向 window
- // 返回的普通函数,谁调用只想谁,匿名函数没有 call 绑定,所以是 window 调用,指向 window
- obj3.foo()() // 'window' 'window'
-
- // 箭头函数,this 由外层作用域决定
- // 定义的时候就决定了,外层作用域是 window(没有对象作用域),指向 window
- // 返回的箭头函数,this 由外层作用域决定
- // 外层作用域是函数作用域,外层是箭头函数,外层箭头函数的 this 前面的分析得到了指向 window,因此此处仍然是 window
- obj4.foo()() // 'window' 'window'
new 对象(普通/箭头函数都指向 新生成的对象):
字面量对象(普通函数指向 新生成的对象,箭头函数指向 window):
- var name = 'window'
-
- function Person (name) {
- this.name = name
- // 普通函数
- this.foo1 = function () {
- console.log(this.name)
- }
- // 箭头函数
- this.foo2 = () => {
- console.log(this.name)
- }
- }
-
- var person2 = {
- name: 'person2',
- // 箭头函数
- foo2: () => {
- console.log(this.name)
- }
- }
-
- var person1 = new Person('person1')
-
- // new对象
- // 普通函数调用时,谁调用就指向谁,因此指向 person1
- person1.foo1() // person1
-
- // new对象
- // 箭头函数调用时,this 由外层作用域决定,且指向函数定义时的 this 而非执行时
- // 箭头函数的外层作用域是 Person 构造函数作用域
- // 构造函数在被 new 的时候,this 会指向新生成的对象
- // 所以此时 this 指向 新生成的对象 person1
- person1.foo2() // person1
-
- // 字面量对象
- // 箭头函数调用时,this 由外层作用域决定,且指向函数定义时的 this 而非执行时
- // 箭头函数的外层作用域是 window(不存在对象作用域)
- // 所以此时 this 指向 window
- person2.foo2() // window
普通函数,谁调用指向谁
返回的普通函数,谁调用指向谁,window 调用,指向 window,除非 call 显式绑定给其他对象
箭头函数,由外层作用域决定 this,外层作用域是构造函数,构造函数在 new 时指向新生成的对象
返回的箭头函数,由外层作用域决定 this,外层作用域可能是 普通函数作用域、也可能是箭头函数作用域
- var name = 'window'
-
- function Person (name) {
- this.name = name
-
- this.foo1 = function () {
- console.log(this.name)
- return function () {
- console.log(this.name)
- }
- }
-
- this.foo2 = function () {
- console.log(this.name)
- return () => {
- console.log(this.name)
- }
- }
-
- this.foo3 = () => {
- console.log(this.name)
- return function () {
- console.log(this.name)
- }
- }
-
- this.foo4 = () => {
- console.log(this.name)
- return () => {
- console.log(this.name)
- }
- }
- }
-
- var person1 = new Person('person1')
-
- // 普通函数,谁调用指向谁,person1
- // 返回的普通函数,谁调用指向谁,window 调用,指向 window
- person1.foo1()() // 'person1' 'window'
-
- // 普通函数,谁调用指向谁,person1
- // 返回的箭头函数,由外层作用域决定 this
- // 外层作用域是 普通函数作用域,普通函数在此处指向了 person1
- person1.foo2()() // 'person1' 'person1'
-
- // 箭头函数,由外层作用域决定 this
- // 外层作用域是构造函数,构造函数在 new 时指向新生成的对象,person1
- // 返回的普通函数,谁调用就指向谁,window 调用指向 window
- person1.foo3()() // 'person1' 'window'
-
- // 箭头函数,由外层作用域决定 this
- // 外层作用域是构造函数,构造函数在 new 时指向新生成的对象,person1
- // 返回的箭头函数,由外层作用域决定 this
- // 外层作用域是 箭头函数作用域,也就是 person1
- person1.foo4()() // 'person1' 'person1'
箭头函数的 this 指向,只有外层作用域决定,call() 函数无法修改 箭头函数的 this 指向
- var name = 'window'
-
- var obj1 = {
- name: 'obj1',
-
- foo1: function () {
- console.log(this.name)
- return () => {
- console.log(this.name)
- }
- },
-
- foo2: () => {
- console.log(this.name)
- return function () {
- console.log(this.name)
- }
- }
- }
-
- var obj2 = {
- name: 'obj2'
- }
-
- // 普通函数被显示绑定给 obj2 了,所以打印 obj2
- // 返回的箭头函数,this 由外层作用域决定,也就是 foo1 函数作用域,也就是 obj2
- obj1.foo1.call(obj2)() // 'obj2' 'obj2'
-
- // 普通函数先执行,谁调用指向谁,所以 obj1
- // 返回的箭头函数不被 call 影响,始终由外层作用域决定,也就是函数作用域,也就是 obj1
- obj1.foo1().call(obj2) // 'obj1' 'obj1'
-
- // 箭头函数不被 call 影响,始终由外层作用域决定,也就是 window 作用域
- // 返回的普通函数,没被 call 改变 this 指向,因此谁调用指向谁,windwow 调用指向 window
- obj1.foo2.call(obj2)() // 'window' 'window'
-
- // 箭头函数直接执行,由外层作用域决定,也就是 window 作用域
- // 返回的普通函数,被 call 改变了 this 指向,因此指向 obj2
- obj1.foo2().call(obj2) // 'window' 'obj2'
必坑指南:
不能使用箭头函数的场景:
举个栗子~
- /**
- * 使用箭头函数定义对象的方法
- */
- let obj = {
- value: 'LinDaiDai',
- // 箭头函数作用域由外层作用域决定,这样会打印 window 下的 value
- getValue: () => console.log(this.value)
- }
-
- obj.getValue() // undefined
-
-
- /**
- * 定义原型方法
- */
- function Foo (value) {
- this.value = value
- }
-
- // 箭头函数作用域由外层作用域决定,这样会打印 window 下的 value
- Foo.prototype.getValue = () => console.log(this.value)
-
- const foo1 = new Foo(1)
- foo1.getValue() // undefined
-
-
- /**
- * 构造函数使用箭头函数
- */
- const Foo = (value) => {
- this.value = value;
- }
- const foo1 = new Foo(1)
- // 事实上直接就报错了 Uncaught TypeError: Foo is not a constructor
- console.log(foo1);
-
-
- /**
- * 作为事件的回调函数
- */
- const button = document.getElementById('myButton');
- button.addEventListener('click', () => {
- // 我们想改的显然是 button 中的文字
- // 但此处 this 由于箭头函数,不再指向 button,而指向 window
- console.log(this === window); // => true
- this.innerHTML = 'Clicked button';
- });
下面的文章确实十分……酸爽
每道题都做了,边看边加上自己的理解整理了这篇文章
受益良多,很感谢作者的干货😄🌼