📕 重学JavaScript: this中的隐式绑定场景

简介: 隐式绑定就是根据函数调用的方式来确定函数内部的this指向,这种方式比较隐晦,你需要注意一些规则和特例。今天我们就专门来聊聊关于隐式绑定的几个场景。

📕 重学JavaScript: this中的隐式绑定场景

嗨,大家好!这里是道长王jj~ 🎩🧙‍♂️

我相信大家了解了JavaScript的this关键字代表什么含义,这里我就不过多的阐述。

我这里就简要地概括一下:

  1. this是一个关键字,它表示当前执行上下文中的一个对象,也就是说,它指向谁取决于函数是怎么调用的。
  2. this有两种绑定方式,一种是显示绑定,一种是隐式绑定。

显示绑定就是用call/apply/bind这些方法来指定函数内部的this指向,这种方式比较直接,你可以自由地把this绑定到任何对象上。

隐式绑定就是根据函数调用的方式来确定函数内部的this指向,这种方式比较隐晦,你需要注意一些规则和特例。

今天我们就专门来聊聊关于隐式绑定的几个场景。

1️⃣ 全局上下文

当你在全局环境中使用this时,它指向全局对象(浏览器中是window,Node.js中是global)。

这是默认的绑定方式,也是最不安全的方式,因为你可能不小心修改了全局对象的属性或方法。

比如,你在全局环境中定义了一个变量a和一个函数fn,然后用this来访问它们,就像这样:

var a = 1;
function fn() {
   
  console.log(this.a);
}
console.log(this.a); // 1
fn(); // 1

这里的this都指向全局对象,所以可以访问到a和fn。但是如果你不小心把this.a赋值为其他值,就会影响全局变量a,就像这样:

var a = 1;
function fn() {
   
  this.a = 100;
  console.log(this.a);
}
console.log(this.a); // 1
fn(); // 100
console.log(this.a); // 100

这里的fn函数内部的this也指向全局对象,所以它把this.a赋值为100,相当于把全局变量a赋值为100。这样就会导致全局变量被污染,可能会引发一些难以发现的bug。

2️⃣ 直接调用函数

当你直接调用一个函数时,它内部的this也指向全局对象。

这和全局上下文类似,但是有一个例外,就是当你在严格模式下调用函数时,它内部的this会指向undefined。

这是为了防止你误操作全局对象而设置的安全措施。

比如,你定义了一个函数fn,在非严格模式下直接调用它,就像这样:

function fn() {
   
  console.log(this);
}
fn(); // window

这里的fn函数内部的this指向全局对象window。但是如果你在严格模式下直接调用它,就像这样:

"use strict";
function fn() {
   
  console.log(this);
}
fn(); // undefined

这里的fn函数内部的this指向undefined。

这是因为在严格模式下,JS不允许你隐式地使用全局对象作为this,而是要求你显示地指定this的值。

如果你没有指定this的值,那么就会默认为undefined。这样可以避免你不小心修改了全局对象的属性或方法。

3️⃣ obj.fn()的形式调用

当你用一个对象来调用它的方法时,它内部的this指向这个对象。

这是最常见的绑定方式,也是最符合直觉的方式,因为你可以把这个对象看作是方法的拥有者或接收者。

比如,你有一个对象叫obj,它里面有一个属性a和一个方法fn,然后用obj来调用它的方法fn,就像这样:

var obj = {
   
  a: 1,
  fn: function() {
   
    console.log(this.a);
  }
};
obj.fn(); // 1

这里的obj.fn()内部的this指向obj对象,所以可以访问到obj对象的属性a。但是如果你把obj.fn赋值给另一个变量,并用这个变量来调用函数,就像这样:

var obj = {
   
  a: 1,
  fn: function() {
   
    console.log(this.a);
  }
};
var anotherFn = obj.fn;
anotherFn(); // undefined

这里的anotherFn()内部的this不再指向obj对象,而是指向全局对象,所以无法访问到obj对象的属性a。

这是因为anotherFn只是一个普通的函数,它不是obj对象的方法,所以它不会继承obj对象的this。

4️⃣ DOM事件绑定(特殊)

当你给一个DOM元素绑定一个事件处理函数时,它内部的this指向这个DOM元素。

这是一个特殊的情况,因为这里涉及到了浏览器的事件机制,它会把事件处理函数作为DOM元素的方法来调用。

比如,你有一个按钮元素叫btn,它里面有一个文本内容叫click me,然后你给它绑定了一个点击事件处理函数fn,就像这样:

<button id="btn">click me</button>
<script>
  var btn = document.getElementById("btn");
  function fn() {
    
    console.log(this); // <button id="btn">click me</button>
    console.log(this.innerHTML); // click me
  }
  btn.addEventListener("click", fn);
</script>

这是因为浏览器会把fn函数作为btn元素的方法来调用,就像这样:

btn.fn();

所以fn函数内部的this就指向了btn元素。

5️⃣ new构造函数绑定

当你用new关键字来调用一个构造函数时,它内部的this指向一个新创建的对象。

这是一种特殊的绑定方式,因为这里涉及到了JS的原型链机制,它会把构造函数作为新对象的原型来调用。

比如,你定义了一个构造函数叫Person,它里面有一个属性name和一个方法sayName,然后用new关键字来创建一个实例叫p,就像这样:

function Person(name) {
   
  this.name = name;
  this.sayName = function() {
   
    console.log(this.name); // Tom
  };
}
var p = new Person("Tom");

这是因为JS会把Person函数作为p对象的原型来调用,就像这样:

p.__proto__ = Person.prototype;
Person.call(p, "Tom");

所以Person函数内部的this就指向了p对象。😁

6️⃣ 箭头函数

当你使用箭头函数时,它内部的this不会根据调用方式改变,而是继承自它所在的词法作用域(lexical scope)。

也就是说,箭头函数没有自己的this,它会沿着作用域链向上寻找最近的一个普通函数,然后把它内部的this作为自己的this。

比如,你定义了一个普通函数fn,在它里面定义了一个箭头函数arrowFn,并用this来访问a属性,就像这样:

var a = 1;
function fn() {
   
  var a = 2;
  var arrowFn = () => {
   
    console.log(this.a);
  };
  arrowFn();
}
fn(); // 1

这里的arrowFn函数内部的this不是指向fn函数或者全局对象,而是指向fn函数外面的那个普通函数(在这里就是全局环境)。

这是因为箭头函数没有自己的this,它会沿着作用域链向上寻找最近的一个普通函数(在这里就是全局环境),

然后把它内部的this(在这里就是全局对象)作为自己的this。

也就是说,箭头函数内部的this和它外面的普通函数内部的this是一样的。

💥 出现多种隐式绑定时,优先级谁最高?

我先说答案:new > call、apply、bind > obj.fn() > 直接调用。

当一个函数有多种绑定方式时,它会按照这个优先级来确定内部的this指向。😁

比如,你有一个构造函数叫Person,它里面有一个属性name和一个方法sayName,然后你用new关键字来创建一个实例叫p,并用call方法来指定this指向obj对象,就像这样:

function Person(name) {
   
  this.name = name;
  this.sayName = function() {
   
    console.log(this.name);
  };
}
var obj = {
   
  name: "Tom"
};
var p = new Person("Jerry").sayName.call(obj);

p.sayName() //Jerry

这里的p.sayName()内部的this指向谁呢?

根据优先级,我们可以知道,new绑定的优先级高于call绑定,所以p.sayName()内部的this指向p对象,而不是obj对象。

所以,当你调用p.sayName()时,就会打印出Jerry

那箭头函数呢?

其实箭头函数不属于这几个场景的优先级,因为箭头函数没有自己的this,它会继承自它所在的词法作用域(lexical scope)的this。

也就是说,箭头函数内部的this和它外面的普通函数内部的this是一样的。

所以,箭头函数内部的this的优先级取决于它外面的普通函数的优先级。


🎉 你觉得怎么样?这篇文章可以给你带来帮助吗?如果你有任何疑问或者想进一步讨论相关话题,请随时发表评论分享您的想法,让其他人从中受益。🚀✨

目录
相关文章
|
4天前
|
JavaScript 前端开发
js中改变this指向、动态指定函数 this 值的方法
js中改变this指向、动态指定函数 this 值的方法
|
16天前
|
前端开发 JavaScript
JavaScript:this-关键字,2024中级前端开发面试解答
JavaScript:this-关键字,2024中级前端开发面试解答
|
19天前
|
自然语言处理 JavaScript 前端开发
在JavaScript中,this关键字的行为可能会因函数的调用方式而异
【5月更文挑战第9天】JavaScript中的`this`关键字行为取决于函数调用方式。在非严格模式下,直接调用函数时`this`指全局对象,严格模式下为`undefined`。作为对象方法调用时,`this`指向该对象。用`new`调用构造函数时,`this`指向新实例。通过`call`、`apply`、`bind`可手动设置`this`值。在回调和事件处理中,`this`可能不直观,箭头函数和绑定方法可帮助管理`this`的行为。
17 1
|
19天前
|
JavaScript 前端开发
深入探索JavaScript:如何改变this的指向
深入探索JavaScript:如何改变this的指向
10 2
|
19天前
|
前端开发 JavaScript 数据安全/隐私保护
前端javascript的DOM对象操作技巧,全场景解析(二)
前端javascript的DOM对象操作技巧,全场景解析(二)
|
19天前
|
移动开发 缓存 JavaScript
前端javascript的DOM对象操作技巧,全场景解析(一)
前端javascript的DOM对象操作技巧,全场景解析(一)
|
19天前
|
JavaScript 前端开发
11.JavaScript 事件的概念以及绑定方法
11.JavaScript 事件的概念以及绑定方法
|
19天前
|
JavaScript 前端开发
【专栏】`Function.prototype.apply` 在JavaScript中用于动态设定函数上下文(`this`)和参数列表
【4月更文挑战第29天】`Function.prototype.apply` 在JavaScript中用于动态设定函数上下文(`this`)和参数列表。它接受两个参数:上下文对象和参数数组。理解`apply`有助于深入JS运行机制。文章分三部分探讨其原理:基本概念和用法、工作原理详解、实际应用与注意事项。在应用中要注意性能、参数类型和兼容性问题。`apply`可用于动态改变上下文、传递参数数组,甚至模拟其他语言的调用方式。通过深入理解`apply`,能提升代码质量和效率。
|
19天前
|
JavaScript 前端开发 数据安全/隐私保护
|
19天前
|
自然语言处理 JavaScript 前端开发
js_关键字this指向哪里?
js_关键字this指向哪里?
8 0