深入解析JavaScript中this关键字的绑定规则与优先级

作者:木棉时间:2026-10-30 22:01:14浏览:556

本文详细解析JavaScript中this关键字的四种绑定规则:默认绑定、隐式绑定、显式绑定和new绑定。通过对比不同调用方式下的指向差异,阐明绑定优先级(new > 显式 > 隐式 > 默认)。同时深入探讨箭头函数不绑定this的特性及其简写语法,并结合面试题解析复杂场景下的this指向逻辑。

全局作用域中的this

  • 在浏览器环境中,非严格模式下this指向window对象;而在严格模式下,this则指向undefined。
  • Node环境:指向{}
    • 当文件被视为模块时,加载编译过程会将其封装在一个函数中,并通过apply({})或call({})执行该函数。

函数的调用方式决定了this的指向。

在大多数情况下,this出现在函数内部。其指向与函数定义的位置无关,而是完全取决于函数的调用方式(即绑定规则)。

function foo(){
	console.log(this);
}
var obj = {
	foo: foo
}
//不同的调用方式this的指向不同,不同的调用方式对应着不同的绑定规则
foo();//window
obj.foo();//obj
foo.call("123");//String{"abc"}

this的绑定规则

  1. 默认绑定:当函数以独立方式调用时,this指向全局对象。
  2. 隐式绑定:当通过对象调用方法时,this会隐式地指向当前调用该方法的对象。
  3. 显示绑定:通过函数的apply、call、bind方法改变函数中this的指向
    • 显式绑定:通过apply或call方法调用函数时,会自动执行函数,且第一个参数用于指定this的指向。其中,apply方法的第二个参数为数组,而call方法的后续参数为参数列表。
    • bind方法:不会自动调用函数,而是返回一个已经绑定好this的新函数。其传参方式与call相同。
  4. new绑定 :通过new关键字调用函数,new 函数()
    • 创建一个全新的对象。
    • 这个新对象会执行prototype连接。
    • 执行构造函数中的代码,为新对象添加属性(此步骤完成this绑定)。
    • 如果函数没有返回其他对象,表达式将返回这个新创建的对象。

this绑定的优先级(权重)

  • 隐式绑定(bind>call/apply) > 隐式绑定 > 默认绑定
function fn() {
  console.log(this);
}
fn.bind(123).apply(321);
  • new绑定 > 隐式绑定 > 默认绑定
  • new绑定 > 显式绑定(通过bind绑定this的函数,可以被new关键字改变this指向)
function Fn(){
  console.log(this);
}
fn.bind("132");
var obj = new Fn();
  • new关键字不能与call或apply一起使用,因为new会主动调用函数,call/apply也会主动调用函数,这样会产生冲突报错。

绑定优先级总结:new绑定 > 显式绑定 > 隐式绑定 > 默认绑定

this规则之外的特殊情况

忽略显式绑定

当apply、call或bind传入null或undefined时,会自动将this绑定为全局对象。

function fn(){
  console.log(this);
}
fn.apply(null);
fn.apply(undefined);

间接函数引用

var obj1 = {
	foo: function(){
		console.log(this);
	}
}
var obj2 = {}
;(obj2.bar = obj1.foo)()//括号中包含赋值表达式,属于独立函数调用,是默认绑定,指向window

箭头函数不会绑定this,arguments属性。箭头函数不能作为构造函数使用(即不能使用new关键字创建对象)。

  • 简写一:当参数只有一个时,可以省略括号。
  • 简写二:当函数体只有一行代码时,可以省略大括号,并且会将这一行代码的返回值作为return值。
var nums = [0, 1, 2, 3, 4, 5];
var result = nums
  .filter(item => item % 2 === 0)
  .map(item => item * 10)
  .reduce((preVal, curVal) => preVal + curVal, 0);
console.log(result);
  • 简写三:如果只有一行代码且需要返回一个对象,那么要将对象用括号包裹。因为省略"{}"后,解析器无法正确解析对象的"{}"。
var foo = () => ({ name: "foo", age: 18 });//这样解析时会将对象当作一个整体

箭头函数的this绑定

箭头函数不遵循this的四种标准规则。箭头函数内部没有绑定this,也不能通过call/apply/bind改变this指向。箭头函数的this指向由外层作用域决定。

var obj = {
  getData() {
    setTimeout(function () {
      console.log(this);
    }, 200);
  },
};
//setTimeout中的函数属于独立调用,所以指向的是window
//如果想让this指向obj对象,setTimeout中使用箭头函数
obj.getData();

this相关面试题

面试题一:

var name = "window";
var person = {
  name: "person",
  sayName: function () {
    console.log(this.name);
  }
};
function sayName() {
  var sss = person.sayName;
  sss(); 
  person.sayName(); 
  (person.sayName)(); 
  (b = person.sayName)(); //包含赋值表达式,属于间接函数引用
}
sayName();

答案:window(默认绑定)、person(隐式绑定)、person(隐式绑定)、window(间接函数引用)

面试题二:

var name = 'window'
var person1 = {
  name: 'person1',
  foo1: function () {
    console.log(this.name)
  },
  foo2: () => console.log(this.name),
  foo3: function () {
    return function () {
      console.log(this.name)
    }
  },
  foo4: function () {
    return () => {
      console.log(this.name)
    }
  }
}
var person2 = { name: 'person2' }
person1.foo1(); 
person1.foo1.call(person2); 
person1.foo2();
person1.foo2.call(person2);
person1.foo3()();
person1.foo3.call(person2)();
person1.foo3().call(person2);
person1.foo4()();
person1.foo4.call(person2)();
person1.foo4().call(person2);

答案解析:

person1.foo1(); //person1:隐式绑定
person1.foo1.call(person2); //person2:显示绑定
person1.foo2();//window:箭头函数的this指向上层作用域的this
person1.foo2.call(person2);//window:箭头函数的this指向上层作用域的this,且不能改变箭头函数指向
person1.foo3()();//window:先执行person1.foo3(),然后拿到返回的函数再调用,属于独立调用,所以指向window
person1.foo3.call(person2)();//window:先执行person1.foo3.call(person2),拿到返回的函数再调用,属于独立调用
person1.foo3().call(person2);//person2:先执行person1.foo3(),拿到返回的函数通过call调用this指向了person2
person1.foo4()(); //person1:拿到返回的箭头函数后,箭头函数没有this,根据上层作用域决定,上层foo4函数指向的是person1对象(foo4是被person1直接调用的),所以内部箭头函数也指向peroson1
person1.foo4.call(person2)(); //person2:给foo4绑定this为person2,箭头函数调用this指向上层作用域,上层foo4的this被显示绑定为了person2,那么内部的箭头函数也是指向person2
person1.foo4().call(person2); //person1:call调用箭头函数,依然去上一层找,所以依然是person1

面试题三:

var name = 'window'
function Person (name) {
  this.name = name
  this.foo1 = function () {
    console.log(this.name)
  },
  this.foo2 = () => console.log(this.name),
  this.foo3 = function () {
    return function () {
      console.log(this.name)
    }
  },
  this.foo4 = function () {
    return () => {
      console.log(this.name)
    }
  }
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo1()
person1.foo1.call(person2)
person1.foo2()
person1.foo2.call(person2)
person1.foo3()()
person1.foo3.call(person2)()
person1.foo3().call(person2)
person1.foo4()()
person1.foo4.call(person2)()
person1.foo4().call(person2)

答案与解析:

person1.foo1() //person1
person1.foo1.call(person2) //person2
person1.foo2() //person1:箭头函数,指向上层作用域的this,上层作用域是“Person构造函数”
person1.foo2.call(person2) //person1::箭头函数,指向上层作用域的this,不能被显示绑定
person1.foo3()() //window:拿到返回的函数后调用,属于独立调用
person1.foo3.call(person2)() //window:拿到返回的函数后调用,属于独立调用
person1.foo3().call(person2) //person2:通过call显示绑定
person1.foo4()() //person1:返回的箭头函数去上层作用域找,上层foo的this指向person1
person1.foo4.call(person2)()//person2:返回的箭头函数去上层作用域找,上层this通过call指向了person2
person1.foo4().call(person2)//person1:箭头函数的this不能被显示绑定

面试题四:

var name = 'window'
function Person (name) {
  this.name = name
  this.obj = {
    name: 'obj',
    foo1: function () {
      return function () {
        console.log(this.name)
      }
    },
    foo2: function () {
      return () => {
        console.log(this.name)
      }
    }
  }
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.obj.foo1()()
person1.obj.foo1.call(person2)()
person1.obj.foo1().call(person2)
person1.obj.foo2()()
person1.obj.foo2.call(person2)()
person1.obj.foo2().call(person2)

答案与解析:

person1.obj.foo1()() //window:独立调用
person1.obj.foo1.call(person2)() //window:独立调用
person1.obj.foo1().call(person2) //person2:call显示绑定
person1.obj.foo2()() //obj:返回的是箭头函数,this由上层作用域foo2函数决定,foo2的this指向obj(foo2是被obj直接调用的),所以返回的箭头函数this也是指向obj
person1.obj.foo2.call(person2)()//person2:箭头函数上层作用域this被call指向person2,所以箭头函数也是指向person2
person1.obj.foo2().call(person2)//obj:箭头函数this不能被显示绑定

到此这篇关于深入了解JavaScript中的this关键字指向的文章就介绍到这了,更多相关JavaScript中的this内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章