this指向恐惧消除器

前言

this是JavaScript中最令人困惑的概念之一,但也是最重要的概念之一。本文将通过30个题目帮助你消除对this指向问题的恐惧心理,废话不多说了,直接发车🫏🫏🫏

基础篇

题目1:全局环境中的this

javascript 复制代码
console.log(this);

答案 :在浏览器中指向window对象,在Node.js中指向global对象

题目2:函数中的this(非严格模式)

javascript 复制代码
function showThis() {
  console.log(this);
}
showThis();

答案 :在非严格模式下指向window(浏览器)或global(Node.js)

题目3:函数中的this(严格模式)

javascript 复制代码
'use strict';
function showThis() {
  console.log(this);
}
showThis();

答案undefined

题目4:对象方法中的this

javascript 复制代码
const obj = {
  name: 'jjq',
  greet() {
    console.log(this.name);
  }
};
obj.greet();

答案'jjq'(指向调用方法的对象obj)

题目5:嵌套对象中的this

javascript 复制代码
const obj = {
  name: 'jjq',
  inner: {
    name: 'jiangjianqing',
    greet() {
      console.log(this.name);
    }
  }
};
obj.inner.greet();

答案'jiangjianqing'(指向直接调用方法的对象inner)

进阶篇

题目6:解构方法后的this

javascript 复制代码
const obj = {
  name: 'jjq',
  greet() {
    console.log(this.name);
  }
};
const { greet } = obj;
greet();

答案undefined(解构后相当于普通函数调用)

题目7:回调函数中的this

javascript 复制代码
const obj = {
  name: 'jjq',
  greet() {
    setTimeout(function() {
      console.log(this.name);
    }, 100);
  }
};
obj.greet();

答案undefined(回调函数的this默认指向全局对象)

题目8:箭头函数中的this

javascript 复制代码
const obj = {
  name: 'jjq',
  greet() {
    setTimeout(() => {
      console.log(this.name);
    }, 100);
  }
};
obj.greet();

答案'jjq'(箭头函数继承外层作用域的this)

题目9:构造函数中的this

javascript 复制代码
function Person(name) {
  this.name = name;
}
const jjq = new Person('jjq');
console.log(jjq.name);

答案'jjq'(构造函数中的this指向新创建的实例)

题目10:构造函数return对象时的this

javascript 复制代码
function Person(name) {
  this.name = name;
  return { name: 'jiangjianqing' };
}
const jjq = new Person('jjq');
console.log(jjq.name);

答案'jiangjianqing'(构造函数返回对象时,this指向被覆盖)

改变this指向篇

题目11:call方法改变this

javascript 复制代码
const obj1 = { name: 'jjq' };
const obj2 = { name: 'jiangjianqing' };

function greet() {
  console.log(this.name);
}

greet.call(obj1);
greet.call(obj2);

答案'jjq' 然后 'jiangjianqing'(call立即调用函数并改变this)

题目12:apply方法改变this

javascript 复制代码
const obj = { name: 'jjq' };

function greet(greeting) {
  console.log(`${greeting}, ${this.name}`);
}

greet.apply(obj, ['Hello']);

答案'Hello, jjq'(apply与call类似,但参数是数组)

题目13:bind方法改变this

javascript 复制代码
const obj = { name: 'jjq' };

function greet() {
  console.log(this.name);
}

const boundGreet = greet.bind(obj);
boundGreet();

答案'jjq'(bind返回一个绑定this的新函数)

题目14:多次bind的this

javascript 复制代码
const obj1 = { name: 'jjq' };
const obj2 = { name: 'jiangjianqing' };

function greet() {
  console.log(this.name);
}

const boundGreet = greet.bind(obj1).bind(obj2);
boundGreet();

答案'jjq'(bind只能绑定一次,后续bind无效)

题目15:箭头函数与bind

javascript 复制代码
const obj = { name: 'jjq' };

const greet = () => {
  console.log(this.name);
};

const boundGreet = greet.bind(obj);
boundGreet();

答案undefined(箭头函数的this无法被bind改变)

特殊场景篇

题目16:DOM事件处理函数中的this

html 复制代码
<button id="btn">Click me</button>
<script>
  document.getElementById('btn').addEventListener('click', function() {
    console.log(this);
  });
</script>

答案:指向触发事件的DOM元素(button元素)

题目17:箭头函数作为DOM事件处理函数

html 复制代码
<button id="btn">Click me</button>
<script>
  document.getElementById('btn').addEventListener('click', () => {
    console.log(this);
  });
</script>

答案:指向外层作用域的this(通常是window)

题目18:setTimeout中的this

javascript 复制代码
const obj = {
  name: 'jjq',
  greet() {
    setTimeout(function() {
      console.log(this.name);
    }, 100);
  }
};
obj.greet();

答案undefined(回调函数中的this默认指向全局对象)

题目19:setInterval中的this

javascript 复制代码
const obj = {
  count: 0,
  start() {
    setInterval(function() {
      this.count++;
      console.log(this.count);
    }, 1000);
  }
};
obj.start();

答案NaN(this指向全局对象,全局count为undefined,undefined++为NaN)

题目20:class中的this

javascript 复制代码
class Person {
  constructor(name) {
    this.name = name;
  }
  greet() {
    console.log(this.name);
  }
}
const jjq = new Person('jjq');
jjq.greet();

答案'jjq'(类方法中的this指向实例)

综合挑战篇

题目21:多层嵌套中的this

javascript 复制代码
const obj = {
  name: 'jjq',
  outer() {
    function inner() {
      console.log(this.name);
    }
    inner();
  }
};
obj.outer();

答案undefined(inner作为普通函数调用,this指向全局)

题目22:方法赋值后的this

javascript 复制代码
const obj1 = {
  name: 'jjq',
  greet() {
    console.log(this.name);
  }
};

const obj2 = {
  name: 'jiangjianqing'
};

obj2.greet = obj1.greet;
obj2.greet();

答案'jiangjianqing'(this指向调用方法的对象obj2)

题目23:立即执行函数中的this

javascript 复制代码
const obj = {
  name: 'jjq',
  greet() {
    (function() {
      console.log(this.name);
    })();
  }
};
obj.greet();

答案undefined(IIFE中的this指向全局对象)

题目24:链式调用中的this

javascript 复制代码
const calculator = {
  value: 0,
  add(num) {
    this.value += num;
    return this;
  },
  multiply(num) {
    this.value *= num;
    return this;
  },
  getValue() {
    return this.value;
  }
};

const result = calculator.add(5).multiply(2).getValue();
console.log(result);

答案10(每个方法都返回this,实现链式调用)

题目25:原型链中的this

javascript 复制代码
function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(this.name);
};

const jjq = new Person('jjq');
jjq.greet();

答案'jjq'(原型方法中的this指向调用该方法的实例)

终极挑战篇

题目26:this与闭包结合

javascript 复制代码
const obj = {
  name: 'jjq',
  tasks: ['task1', 'task2', 'task3'],
  showTasks() {
    this.tasks.forEach(function(task) {
      console.log(`${this.name} has ${task}`);
    });
  }
};
obj.showTasks();

答案 :三次'undefined has taskX'(回调函数中的this指向全局)

题目27:解决题目26的问题

javascript 复制代码
const obj = {
  name: 'jjq',
  tasks: ['task1', 'task2', 'task3'],
  showTasks() {
    this.tasks.forEach(function(task) {
      console.log(`${this.name} has ${task}`);
    }, this); // 使用forEach的第二个参数
  }
};
obj.showTasks();

答案 :三次'jjq has taskX'(通过forEach的第二个参数绑定this)

题目28:箭头函数作为类字段

javascript 复制代码
class Counter {
  count = 0;
  
  increment = () => {
    this.count++;
    console.log(this.count);
  };
}

const counter = new Counter();
const increment = counter.increment;
increment();

答案1(箭头函数类字段绑定实例this)

题目29:this与扩展运算符

javascript 复制代码
const obj = {
  name: 'jjq',
  greet(...args) {
    console.log(this.name, args);
  }
};

const greet = obj.greet;
greet.call(obj, 1, 2, 3);

答案'jjq' [1, 2, 3](扩展运算符不影响this)

题目30:最复杂的this综合题

javascript 复制代码
const obj1 = {
  name: 'jjq',
  greet() {
    return () => {
      console.log(this.name);
    };
  }
};

const obj2 = {
  name: 'jiangjianqing'
};

const greet = obj1.greet();
greet.call(obj2);

答案'jjq'(箭头函数的this在创建时确定,无法被call改变)

总结

好了 我先收摊

相关推荐
亭台烟雨中15 分钟前
【前端记事】关于electron的入门使用
前端·javascript·electron
泯泷29 分钟前
「译」解析 JavaScript 中的循环依赖
前端·javascript·架构
Senar1 小时前
Web端选择本地文件的几种方式
前端·javascript·html
iuyou️1 小时前
Spring Boot知识点详解
java·spring boot·后端
一弓虽1 小时前
SpringBoot 学习
java·spring boot·后端·学习
姑苏洛言1 小时前
扫码小程序实现仓库进销存管理中遇到的问题 setStorageSync 存储大小限制错误解决方案
前端·后端
烛阴2 小时前
JavaScript 的 8 大“阴间陷阱”,你绝对踩过!99% 程序员崩溃瞬间
前端·javascript·面试
光而不耀@lgy2 小时前
C++初登门槛
linux·开发语言·网络·c++·后端