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改变)

总结

好了 我先收摊

相关推荐
计算机程序设计开发7 分钟前
相机租赁网站基于Spring Boot SSM
spring boot·后端·数码相机·毕设·计算机毕设
__淡墨青衫__9 分钟前
Django之旅:第六节--mysql数据库操作增删改查(二)
后端·python·django
ElasticPDF_新国产PDF编辑器25 分钟前
Vue 项目 PDF 批注插件库在线版 API 示例教程
javascript
yufei-coder25 分钟前
配置Next.js环境 使用vscode
开发语言·javascript·vscode·next.js
京东云开发者31 分钟前
业务复杂度治理方法论--十年系统设计经验总结
后端
陈珙_SkyChen31 分钟前
后端思维之高并发方案
后端
阿白的白日梦41 分钟前
JSX 元素隐式具有类型 "any",因为不存在接口 "JSX.IntrinsicElements"。ts 无法使用 JSX,除非提供了 "--js
前端·javascript·typescript
uhakadotcom42 分钟前
nginx的JavaScript魔力:njs简介与实践
javascript·后端·面试
敖正炀1 小时前
打破双亲委派模型
后端
用户4099322502121 小时前
深入掌握FastAPI与OpenAPI规范的高级适配技巧
前端·javascript·后端