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 undefinedvar会将变量挂在顶层对象(浏览器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>onclick和addEventListener指向绑定事件的元素
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()
  }