JavaScript中this的绑定规则与优先级详解

作者:函数茶馆

时间:2026-10-23

浏览:539

本文深入解析JavaScript中this关键字的绑定机制,指出其绑定发生在运行时而非编写时。详细阐述了默认绑定、隐式绑定、显式绑定及new绑定四种规则及其优先级,并通过代码示例说明隐式丢失与硬绑定的处理,帮助开发者准确理解this指向。

文章目录

JavaScript this绑定机制概述

前言

在JavaScript开发中,this关键字的使用频率极高,但许多开发者对其具体指向往往感到困惑。许多人容易从字面含义误解,认为this指向函数自身,但实际上,this的绑定发生在函数运行时,而非代码编写阶段。其最终指向的上下文完全取决于函数被调用时的具体条件,与函数声明的位置无关,仅由调用方式决定。

核心结论:this的绑定在函数被调用时发生,其指向完全取决于函数的调用位置与方式。

一、this的绑定规则

JavaScript中this主要遵循四种绑定规则,下文将逐一解析每种规则的具体含义及它们之间的优先级关系。

  • 默认绑定(严格/非严格模式)
  • 隐式绑定
  • 显式绑定
  • new绑定

默认绑定与严格模式差异

1.1 默认绑定(严格/非严格模式)

  • 当函数以独立形式调用时,适用默认绑定规则,此时this指向全局对象(在浏览器环境中为window)。
  • 在严格模式下,默认绑定规则失效,this将绑定为undefined。

独立函数调用


function foo() {
 console.log(this.a);
}
var a = 2;
foo(); // 2

严格模式下:


function foo() {
 "use strict";
 console.log(this); //undefined
 console.log(this.a); //Uncaught TypeError: Cannot read property 'a' of undefined
}
var a = 2;
foo();

需注意以下两种特殊情况:


var age = "18";
var obj = {
 name: "heyushuo",
 age: 25,
 fn: function() {
 function sayName() {
  console.log(this); //window
  console.log(this.age); //undefined
 }
 sayName();
 }
};
obj.fn();

即便函数sayName定义在obj.fn内部,它依然被视为独立函数调用,因此this仍指向window。


var a = "global";
var obj = {
 a: 2,
 foo: function() {
 console.log(this.a); //global
 }
};
var bar = obj.foo; // 函数别名!
bar();

虽然变量bar是obj.foo的一个引用,但它实际指向的是函数本身。因此,执行bar()等同于不带任何修饰的独立函数调用,故应用默认绑定规则。

隐式绑定与隐式丢失

1.2 隐式绑定

当函数引用存在明确的上下文对象时(例如通过obj.foo形式引用函数foo),隐式绑定规则会将函数内部的this绑定至该上下文对象。


var obj = {
 name: "heyushuo,
 foo: function() {
 console.log(this.name); //heyushuo
 }
};

obj.foo();

在对象属性引用链中,只有最后一层调用对象对this的绑定起作用。


var obj = {
 name: "heyushuo",
 obj1: {
 name: "kebi",
 foo: function() {
  console.log(this.name); // kebi
 }
 }
};

obj.obj1.foo();

隐式丢失

原本被隐式绑定的函数若失去上下文引用,将回退应用默认绑定,导致this指向全局对象(严格模式下为undefined)。

第一种情况:


var a = "global";
var obj = {
 a: 2,
 foo: function() {
 console.log(this.a); //global
 }
};
var bar = obj.foo; // 函数别名!
bar();

尽管bar是obj.foo的引用,但它实际指向函数本身。因此,执行bar()实际上是一个不带任何修饰的独立函数调用,从而应用默认绑定规则。

第二种情况:当函数作为回调函数传入时:


var a = "global";
var obj = {
 a: 2,
 foo: function() {
 console.log(this.a); //global
 }
};
var bar = obj.foo; // 函数别名!
function doFoo(fn) {
 fn(); // <-- 调用位置!
}
doFoo(bar); //global

//和下边这种一样
setTimeout(obj.foo, 300);

显式绑定与硬绑定

1.3 显示绑定

通过call()或apply()方法实现。若第一个参数指定为一个对象,则在调用函数时将该对象绑定至this,此过程称为显示绑定。


function foo() {
 console.log(this.a);
}
var obj = {
 a: 2
};
foo.call(obj); // 2

基于显示绑定衍生出一种常用模式——硬绑定,代码如下:


function foo(something) { 
 console.log( this.a, something ); 
 return this.a + something;
}
// 简单的辅助绑定函数
function bind(fn, obj) { 
 return function() {
 return fn.apply( obj, arguments ); //内部已经强制绑定了传入函数this的指向
 };
}
var obj = { 
 a:2
};
var bar = bind( foo, obj ); 
var b = bar( 3 ); // 2 3
console.log( b ); // 5

无论bar函数如何被调用,它始终会在obj上执行fn,强制将fn的this绑定至obj。这种方式有效解决了前文提到的隐式丢失问题。鉴于硬绑定是常见模式,ES5标准中提供了内置方法Function.prototype.bind。


function foo(something) { 
 console.log( this.a, something ); 
 return this.a + something;
}
var obj = { 
 a:2
};
var bar = foo.bind( obj );
var b = bar( 3 ); // 2 3 
console.log( b ); // 5

new绑定与构造函数调用

1.4 new绑定

使用new关键字调用函数(即构造函数调用)时,会自动执行以下操作:

  • 创建(或构造)一个全新的对象。
  • 该新对象会执行[[原型]]连接操作。
  • 该新对象会绑定到函数调用时的this。
  • 若函数未返回其他对象,则new表达式中的函数调用将自动返回该新对象。

例如:


function foo() { 
 this.name = "heyushuo";
 this.age = 25
} 
foo.prototype.sayName = function(){
 console.log(this.name+this.age);
}
var bar = new foo();

console.log(bar); //{name: "heyushuo", age: 25}
//这个新对象会绑定到函数调用的 this。所以此时的this就是bar对象
console.log( bar.age ); // 25

下图展示了new foo()生成的对象结构。

JavaScript this绑定机制概述

this绑定优先级判断

二、四种绑定关系的优先级

判断this指向时,可遵循以下优先级顺序:

1. 函数是否在new中调用(new绑定)?若是,this绑定新创建的对象。


var bar = new foo()

2. 函数是否通过call、apply(显式绑定)或硬绑定调用?若是,this绑定指定的对象。


var bar = foo.call(obj2)

3. 函数是否在某个上下文对象中调用(隐式绑定)?若是,this绑定该上下文对象。


var bar = obj1.foo()

4. 若以上均不满足,则使用默认绑定。严格模式下绑定为undefined,否则绑定为全局对象。


var bar = foo()

总结

以上就是本文的全部内容,希望这些关于this绑定规则与优先级的解析能对您的学习或工作有所帮助,感谢支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章