细说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的资料请关注脚本之家其它相关文章!

相关文章

  • 前端构建工具之gulp的配置与搭建详解

    前端构建工具之gulp的配置与搭建详解

    gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学习起来很容易,下面这篇文章主要给大家介绍了关于前端构建工具之gulp的配置与搭建的相关资料,需要的朋友可以参考下。
    2017-06-06
  • js使用for循环与innerHTML获取选中tr下td值

    js使用for循环与innerHTML获取选中tr下td值

    这篇文章主要与大家分享了js使用for循环与innerHTML获取选中tr下td值的方法,很简单,但很实用,有需要的朋友可以参考下
    2014-09-09
  • js内存泄漏场景、如何监控及分析详解

    js内存泄漏场景、如何监控及分析详解

    js内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存,这篇文章主要给大家介绍了关于js内存泄漏场景、如何监控及分析的相关资料,需要的朋友可以参考下
    2021-11-11
  • 微信小程序实现图形验证码

    微信小程序实现图形验证码

    这篇文章主要为大家详细介绍了微信小程序实现图形验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 使用ImageMagick进行图片缩放、合成与裁剪(js+python)

    使用ImageMagick进行图片缩放、合成与裁剪(js+python)

    由于需要在服务器端处理,使用就研究使用imagemagick来进行。同时准备封装了一个Node.js和Python的方法,主要还是讲一下然后使用imagemagick来对图片进行缩放、合成后进行裁剪吧
    2013-09-09
  • 微信小程序数据分析之自定义分析的实现

    微信小程序数据分析之自定义分析的实现

    这篇文章主要介绍了微信小程序数据分析之自定义分析的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Javascript变量的作用域和作用域链详解

    Javascript变量的作用域和作用域链详解

    这篇文章主要介绍了Javascript变量的作用域和作用域链详解,本文用一个实例和运行结果来讲解这两个知识,需要的朋友可以参考下
    2015-04-04
  • JS中使用正则表达式g模式和非g模式的区别

    JS中使用正则表达式g模式和非g模式的区别

    这篇文章给大家详细介绍了JS中使用正则表达式g模式和非g模式的区别,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-04-04
  • JS图片懒加载的优点及实现原理

    JS图片懒加载的优点及实现原理

    这篇文章主要介绍了JS图片懒加载的优点及实现原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Bootstrap treeview实现动态加载数据并添加快捷搜索功能

    Bootstrap treeview实现动态加载数据并添加快捷搜索功能

    本文实现了运用bootstrap treeview实现动态加载数据,并且添加快捷搜索功能,需要的朋友参考下
    2018-01-01

最新评论