Skip to content

11. this指向与call、apply、bind、箭头函数

参考:文章

函数调用

全局上下文

非严格模式和严格模式中this都是指向顶层对象(浏览器中是window)

js
  this === window // true
  'use strict'
  this === window // true

函数上下文

普通函数调用模式

js
  var name = 'window'
  var doSth = function() {
    console.log(this.name)
  }
  doSth() // 'window'

  // 

  let name2 = 'window'
  let doSth2 = function() {
    console.log(this === window)
    console.log(this.name2)
  }
  doSth2() // true undefined

var会将变量挂在顶层对象(浏览器window)中,而let不会。

可以类比为(默认绑定)

js
  doSth.call(undefined)
  doSth.apply(undefined)

对象中函数的调用方式

js
  var name = 'window'
  var doSth = function() {
    console.log(this.name)
  }
  var student = {
    name: '若川'
    doSth: doSth,
    other: {
      name: 'other',
      doSth: doSth
    }
  }

  student.doSth() // '若川' -> student.doSth.call(student)
  student.other.doSth() // 'other' -> student.other.doSth.call(student.other)

有时,把对象中的函数赋值给一个变量,就变成普通函数的规则(默认绑定)

js
  var studentDoSth = student.doSth
  studentDoSth() // 'window'
  // 类比: studentDoSth.call(window)

call、apply、bind调用模式

call、apply方法

语法:

js
  fun.call(thisArg, arg1, arg2, ...)
  fun.apply(thisArg, argsArray)
  • thisArg:非严格模式,null和undefined可以被替换为window。如果是原始值,会直接指向该原始值的自动包装对象。
  • arg1,argsArray: 指定调用函数时的参数

返回值是调用方法的返回值,若没有,则返回undefined

bind方法

语法:

js
  const f = func.bind(thisArg, arg1, arg2, ...)
  f()

与call类似,但是返回值是一个函数

构造函数调用模式

js
    function Student(name){
        this.name = name;
        console.log(this); // {name: '若川'}
        // 相当于返回了
        // return this;
    }
    var result = new Student('若川');

new操作符调用后,this指向生成的新对象

原型链中的调用模式

js
  function Student(name){
      this.name = name;
  }
  var s1 = new Student('若川');
  Student.prototype.doSth = function(){
      console.log(this.name);
  }
  s1.doSth(); // '若川'

同对象调用模式

箭头函数调用模式

箭头函数
  • 没有自己的this、super、arguments
  • 不能使用new调用
  • 没有原型对象
  • 不可以改变this绑定
  • 形参名称不可以重复

箭头函数没有this绑定,必须通过查找作用域链来决定值

  • 如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this
  • 否则,this值为全局对象
js
  var name = 'window';
  var student = {
      name: '若川',
      doSth: function(){
          // var self = this;
          var arrowDoSth = () => {
              // console.log(self.name);
              console.log(this.name);
          }
          arrowDoSth();
      },
      arrowDoSth2: () => {
          console.log(this.name);
      }
  }
  student.doSth(); // '若川'
  student.arrowDoSth2(); // 'window'

DOM事件处理函数调用

addEventListener、attachEvent、onClick
js
<button class="button">onclick</button>
<ul class="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
    var button = document.querySelector('button');
    button.onclick = function(ev){
        console.log(this);
        console.log(this === ev.currentTarget); // true
    }
    var list = document.querySelector('.list');
    list.addEventListener('click', function(ev){
        console.log(this === list); // true
        console.log(this === ev.currentTarget); // true
        console.log(this);
        console.log(ev.target);
    }, false);
</script>

onclickaddEventListener指向绑定事件的元素

currentTarget和target
  • currentTarget是绑定事件的元素
  • target是当前触发事件的元素
内联事件处理函数
js
<button class="btn1" onclick="console.log(this === document.querySelector('.btn1'))">点我呀</button>
<button onclick="console.log((function(){return this})());">再点我呀</button>

手写

call和apply类似

js
  Function.prototype.mycall = function(thisArg, ...args) {
    // 1. Let func be the this value. 将当前函数赋值给fun变量
    let func = this
    // 2. If IsCallable(func) is false, throw a TypeError exception. 判断当前函数是否可执行
    if(!func instanceof Function) {
      throw new TypeError(`${this} is not a function`)
    }
    thisArg.func = func
    return thisArg.func()
  }

KESHAOYE-知识星球