细说JavaScript中的this指向与绑定规则

 更新时间:2023年05月29日 11:27:52   作者:泠沅  
本文主要详细介绍了JavaScript中的this指向与绑定规则,默认绑定,隐式绑定,显示绑定,new绑定这四个规则,文中有相关的代码示例供大家参考,感兴趣的同学可以阅读下

this的指向

通常在浏览器中,在全局中使用this,该this指向的是window对象,无论是否开启了严格模式。但我们一般使用this,也是在函数中进行使用。所有的函数在被调用的时候,会产生一个函数执行上下文,该上下文中记录这函数的作用域链、AO对象以及当前这个函数的this指向。我们看下面代码:

function foo() {
  console.log(this)
}
foo()//window
var obj = {
  name: 'why',
  foo: foo
}
obj.foo()//obj
foo.apply("abc")//String{'abc'}

上面代码中,我们定义了一个函数foo来输出调用它的时候this的指向,从上往下分别指向的是window、obj、String{'abc'},所以我们可以知道:

  • 函数在调用时,JavaScript会默认给this绑定一个值;
  • this的绑定和定义的位置(编写的位置)没有关系;
  • this的绑定和调用方式以及调用的位置有关系;
  • this是在运行时被动态绑定的,而不是编译时固定下来的

判断this绑定的4条规则

规则1:默认绑定

独立函数调用的时候,this永远绑定的是window对象,如下示例:

function foo() {
   console.log(this)
}
function foo2() {
   foo()
}
var obj = {
  name: "xiaomin",
  foo: function() {
    console.log(this)
  }
}
foo()//window
foo2()//window
var bar = obj.foo
bar()//window

规则2:隐式绑定

通过某个对象发起调用的函数,哪个对象发起调用的函数,那么该调用函数的this就隐式绑定在了这个对象:

var obj1 = {
  name: "obj1",
  foo: function () {
    console.log(this);
  },
};
var obj2 = {
  name: "obj2",
  bar: obj1.foo,
  obj1: obj1,
};
obj1.foo();//obj1
obj2.obj1.foo();//obj1
obj2.bar();//obj2

规则3:显示绑定

通过函数的方法call、apply、bind将this显示绑定了某个对象上,那么该函数的this就指向到这个对象上:

function foo() {
       console.log(this)
}
var obj = {
   name: "obj"
}
foo.call(obj)
foo()//obj
foo.apply(obj)
foo()//obj
var newfoo = foo.bind(obj)
newfoo()//obj

规则4:new绑定

我们有如下代码:

function Person(name, age) {
  this.name = name
  this.age = age
  console.log(this)//p
}
var p = new Person("kobe",12);

在这里我们有一个构造函数Person,并用它创建了一个对象,这里简单说明一下通过new调用构造函数创建对象时的5个步骤:

  • 在内存中创建一个空对象
  • 将该对象的[[prototype]]指向构造函数的prototype属性
  • 构造函数里的this指向这个空对象
  • 开始执行构造函数的函数体代码
  • 如果构造函数未返回内容,将该对象作为返回值返回出去

从上面我们可以看到,在使用new创建对象的时候,在第三个步骤会将构造函数内部的this绑定到创建的这个对象上,也就是上面代码中,Person函数中打印的this就是会是通过new关键字创建的对象p。

this绑定的优先级

当同时出现上列规则的多种规则绑定的时候,这时候this的指向就会根据上面绑定规则的优先级进行绑定:

  • 默认绑定优先级最低
  • 显示绑定优先于隐式绑定,如下列代码打印的this就不是obj而是String {'aaa'}
function foo() {
  console.log(this);//String {'aaa'}
}
var obj = {
  name: "obj",
  foo: foo.bind("aaa"),
};
obj.foo();
  • new绑定优先于隐式绑定,如下列代码打印出来的就不是obj,而是创建出来的对象f
var obj = {
  name: "obj",
  foo: function () {
    this.name = "kkk";
    console.log("this:", this);//foo {name: 'kkk'}
  },
};
var f = new obj.foo();
  • new绑定优先bind绑定(new绑定不能同时与call、apply同时使用),如下代码this打印出来的就是obj的对象而不是String{'aaa'}
function foo() {
  console.log(this);
}
var bar = foo.bind("aaa");
var obj = new bar();
//var obj2 = new foo.apply("123");//这样写会报错

除了四个this绑定规则外的特殊情况

1、在显示绑定中我们绑定了null或者undefined,this会绑定到window上

function foo() {
  console.log(this)
}
foo.call({})//{}
foo.call(null)//window
foo.call(undefined)//window

2、函数的间距引用,在下列代码中,赋值表达式 p.foo = o.foo 的返回值是目标函数的引用,因此调用位置是 foo(),不是o.foo()。所以打印出来的this是window而不是o或者p

function foo() {
  console.log(this);
}
var o = { foo: foo };
var p = {};
o.foo(); // o
(p.foo = o.foo)(); // window

3、箭头函数。箭头函数是不会有自己的this的,在调用箭头函数的时候,在它的函数执行上下文中并不会生成它this的记录,而如果在箭头函数的函数体中使用到了this,那么它将会在它的上层作用域里面去找this,看下面代码

var obj = {
  data: [],
  changeData: function () {
    console.log("普通函数this:", this);
    (() => {
      console.log("箭头函数this:", this);
    })();
    setTimeout(() => {
      this.data = ["1", "2", "3"];
      console.log("this:", this);
    }, 1000);
  },
};
obj.changeData();

打印结果:

可以看出,上面打印的this其实都是指向的obj。在箭头函数内它自身没有this,那么它就向外层寻找,找到了changeData这个函数,而这时由于隐式绑定规则,changeData由obj调用的,那么changeData的this就指向的obj,所以箭头函数的this指向的就是obj。

以上就是细说JavaScript中的this指向与绑定规则的详细内容,更多关于JavaScript this的资料请关注脚本之家其它相关文章!

相关文章

  • JavaScript设计模式之缓存代理模式原理与简单用法示例

    JavaScript设计模式之缓存代理模式原理与简单用法示例

    这篇文章主要介绍了JavaScript设计模式之缓存代理模式原理与简单用法,结合实例形式简要分析了javascript缓存代理模式的基本原理、使用方法及相关操作注意事项,需要的朋友可以参考下
    2018-08-08
  • 谈一谈javascript闭包

    谈一谈javascript闭包

    这篇文章主要介绍了javascript闭包,闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现,感兴趣的小伙伴们可以参考一下
    2016-01-01
  • 一篇文章带你入门前端的滑块验证怎么做

    一篇文章带你入门前端的滑块验证怎么做

    滑块验证也被称为拼图验证码,是一种用于验证用户是否为人类而不是机器人的常见方法,这篇文章主要介绍了前端滑块验证怎么做的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-11-11
  • 微信小程序实现顶部选项卡(swiper)

    微信小程序实现顶部选项卡(swiper)

    这篇文章主要为大家详细介绍了微信小程序实现顶部选项卡效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • BootStrap实现树形目录组件代码详解

    BootStrap实现树形目录组件代码详解

    这篇文章主要介绍了BootStrap实现树形目录组件代码详解的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • 教你javascript如何获取对象的key和value

    教你javascript如何获取对象的key和value

    获取对象所有key的方法,需要使用 Object.keys(obj) 方法,Object.keys(obj)方返回一个数组,这个数组包含obj对象中的所有key,这篇文章主要介绍了javascript如何获取对象的key和value,需要的朋友可以参考下
    2022-12-12
  • Bootstrap表单简单实现代码

    Bootstrap表单简单实现代码

    这篇文章主要为大家详细介绍了Bootstrap表单的简单实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • javascript中Object使用详解

    javascript中Object使用详解

    这篇文章主要介绍了javascript中Object使用详解,非常全面详尽,有需要的小伙伴参考下
    2015-01-01
  • js仿淘宝商品放大预览功能

    js仿淘宝商品放大预览功能

    本文主要介绍了js仿淘宝商品放大预览功能的实例。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03
  • javascript bom是什么及bom和dom的区别

    javascript bom是什么及bom和dom的区别

    BOM是浏览器对象模型,DOM是文档对象模型,前者是对浏览器本身进行操作,而后者是对浏览器(可看成容器)内的内容进行操作。这篇文章给大家介绍javascript bom是什么及bom和dom的区别,感兴趣的朋友一起学习吧
    2015-11-11

最新评论