javascript中this指向的理解

一.定义
  • this是javascript中的一个关键字
  • this会在执行上下文绑定一个对象
  • this在不同的执行条件下会绑定不同的对象
  • this永远指向最后调用它的那个对象
  • this函数执行过程中,this一旦被确定了,就不可以再更改

二.绑定规则

  • 默认绑定
  • 隐式绑定
  • call/apply/bind显示绑定
  • new绑定
2.1.默认绑定

独立的函数调用,我们可以理解成函数没有被绑定到某个对象上进行调用。

scss 复制代码
  function foo() {
    console.log(this); // window
  }
  foo()
  • foo前面没有调用的对象就是全局对象window, 这就相当于window.a()
  • 严格模式下,不能将全局对象用于默认绑定,this会绑定到undefined
2.2.1隐式绑定

函数还可以作为某个对象的方法调用,通俗点就是,对象拥有某个方法,通过这个对象访问方法直接调用,这时this就指这个上级对象

javascript 复制代码
  const person = {
    name: 'maomao',
    foo: function() {
      console.log(this.name); // 'maomao'
    }
  }
  person.foo()
  • fn被person发起调用,进行了隐式绑定,那么this会隐式的被绑定到obj对象上
2.2.2隐式丢失

案例一:

csharp 复制代码
  function foo() {
    console.log(this.name); // 'undefined'
  }
  const person = {
    name: 'maomao',
    foo: foo
  }
  const fn = person.foo
  fn()
  • 这里并没有直接调用,而是通过person找到对应的fn的内存地址,直接赋值给变量p
  • 然后通过p直接调用,没有绑定任何的对象,相当于默认绑定
  • this也就是全局对象window, window中取出name属性,必定为undefined

案例二:

php 复制代码
  var name = 'haohao'
  const person = {
    name: 'maomao',
    foo: function() {
      console.log(this.name); // 'haohao'
    }
  }
  function bar(fn) {
    fn()
  }
  bar(person.foo)
  • 首先bar中的fn为一个回调函数
  • fn=person.foo参数传递就是隐式赋值,他们都是指向fn=person.foo引用,也就是他们的内存地址
  • 因为他们的this丢失,也就是函数独立调用,默认绑定规则,this为全局的window对象
  • 但是有些场景,不想让隐式丢失,就出现显示绑定。
2.3显示绑定

在某些场景下,this的改变都是意想不到。那么我们可以,javascript所有的函数都可以使用call、apply、bind方法

2.3.1 call/apply

  • call()第一个参数为固定绑定的this对象,
  • call()第二个参数及第三个第四个等等参数,都作为参数传递给所调用的函数。
  • call()apply()第一个参数相同的,后面的参数,call是参数列表,apply是数组。
  • 在调用这个函数时,会将this绑定到这个传入的对象上。 call()
javascript 复制代码
  var name = 'haohao'
  const person = {
    name: 'maomao',
    foo: function(age, height) {
      console.log(this.name, age, height); // 'maomao, 18, 1.88'
    }
  }
  function bar(fn) {
    fn.call(person, 18, 1.88)
  }
  bar(person.foo)

apply()

javascript 复制代码
  var name = 'haohao'
  const person = {
    name: 'maomao',
    foo: function(age, height) {
      console.log(this.name, age, height); // 'maomao, 18, 1.88'
    }
  }
  function bar(fn) {
    fn.apply(person, [18, 1.88])
  }
  bar(person.foo)
2.3.2 bind
  • bindcall,第一个参数和第二个及以后的参数相同,不同的是返回一个this绑定后的函数,调用返回后端函数,就可以拿到期望的this
javascript 复制代码
  var name = 'haohao'
  const person = {
    name: 'maomao',
    foo: function(age, height) {
      console.log(this.name, age, height); // 'maomao, 18, 1.88'
    }
  }
  function bar(fn) {
    let f = fn.bind(person, 20, 1.88)
    f()
  }
  bar(person.foo)
2.3.3 内置函数
  • 我们会调用一些javascript的内置函数,或者一些第三方库中的内置函数。
  • 这些内置函数会要求我们传入另外一个函数;
  • 我们自己并不会显示的调用这些函数,而且javascript内部或者第三方库会帮助我们执行;
案例一:setTimeout
javascript 复制代码
  setTimeout(function() {
    console.log(this)
  }, 1000)
  • setTimeout中会传入一个函数,这个函数中的this通常是window
  • 这个和setTimeout源码的内部调用有关。
  • setTimeout内部是通过apply进行绑定的this对象,并且绑定的是全局对象;
案例二:数组的forEach
javascript 复制代码
  const names = ['aaa', 'bbb', 'ccc']
  names.forEach(function(item) {
    console.log(this); // window
  })
  • forEach中传入的函数打印的也是window对象;
  • 默认情况下传入的函数是自动调用函数(默认绑定)
  • 我们可以改变该函数的this指向, 如下;
javascript 复制代码
  const names = ['aaa', 'bbb', 'ccc']
  const obj = {
    name: 'maomao'
  }
  names.forEach(function(item) {
    console.log(this); // window
  }, obj)
案例三:div的点击
javascript 复制代码
  const box = document.querySelector('.box')
  box.onclick = function() {
    console.log(this); // box对象
  }
  • 点击的时候,执行传入的回调函数被调用时,会将box对象绑定到该函数中
2.4new绑定

javascript中的函数可以当做一个类型构造函数来使用,也就是使用new关键字。 使用new关键字来调用函数时,会执行如下的操作;

  • 1.创建一个新对象;
  • 2.这个对象的[[prototype]]指向构造函数的prototype属性;
  • 3.this指向了这个新对象;
  • 4.如果函数没有返回其他对象,那么就返回这个新对象;
javascript 复制代码
  // 创建Person
  function Person(name) {
    console.log(this); // Person {}
    this.name = name // Person {name: 'maomao'}
  }
  var p = new Person('maomao')
  console.log(p);

三.规则优先级

3.1.默认规则的优先级最低

存在其他规则时,就会通过其他规则的方式来绑定this

3.2.显示绑定优先级>隐式绑定

javascript 复制代码
  function foo() {
    console.log(this);
  }

  const obj1 = {
    name: 'obj1',
    foo: foo
  }

  const obj2 = {
    name: 'obj2',
    foo: foo
  }

  // 隐式绑定
  obj1.foo() // obj1
  obj2.foo() // obj2

  //隐式绑定和显示绑定同时存在
  obj1.foo.call(obj2) // obj2, 说明显示绑定优先级更高
3.4.new绑定优先级>bind
  • new绑定和callapply是不允许同时使用的
javascript 复制代码
  function foo() {
    console.log(this);
  }
  const obj = {
    name: "why",
    foo: foo
  }
  const fn = foo.bind(obj)
  const bar = new fn() //foo
3.5优先级
  • new绑定 > 显示绑定(bind)> 隐式绑定 > 默认绑定
四.ES6箭头函数
  • 箭头函数时ES6新增的语法
ini 复制代码
  const foo = () => {}
  • 箭头函数不绑定this, 根据外层作用域来决定this.
案例一:
javascript 复制代码
  const obj = {
    data: [],
    getData: function() {
      setTimeout(() => {
        console.log(this) // obj
      }, 1000)
    }
  }
  obj.getData()
案例二:
javascript 复制代码
const obj = {
    data: [],
    getData: () => {
      setTimeout(() => {
        console.log(this) // window
      }, 1000)
    }
  }
  obj.getData()
  • 箭头函数不绑定this, 不断的从上层作用域找,那么找到了全局作用域;
  • 在全局作用域内,this代表的就是window
相关推荐
xing25164 分钟前
pytest-html
前端·html·pytest
茂茂在长安14 分钟前
Linux 命令大全完整版(11)
java·linux·运维·服务器·前端·centos
知识分享小能手1 小时前
Html5学习教程,从入门到精通,HTML5 简介语法知识点及案例代码(1)
开发语言·前端·javascript·学习·前端框架·html·html5
IT、木易1 小时前
大白话React第二章深入理解阶段
前端·javascript·react.js
晚安7201 小时前
Ajax相关
前端·javascript·ajax
图书馆钉子户1 小时前
怎么使用ajax实现局部刷新
前端·ajax·okhttp
bin91531 小时前
DeepSeek 助力 Vue 开发:打造丝滑的单选按钮(Radio Button)
前端·javascript·vue.js·ecmascript·deepseek
qianmoQ1 小时前
第五章:工程化实践 - 第五节 - Tailwind CSS 常见问题解决方案
前端·css
那就可爱多一点点2 小时前
超高清大图渲染性能优化实战:从页面卡死到流畅加载
前端·javascript·性能优化
不能只会打代码3 小时前
六十天前端强化训练之第一天HTML5语义化标签深度解析与博客搭建实战
前端·html·html5