写在前面

这里是小飞侠Pan🥳,立志成为一名优秀的前端程序媛!!!

本篇文章收录于我的专栏:前端精进之路

同时收录于我的github前端笔记仓库中,持续更新中,欢迎star~


了解this

this 就是一个指针,指向调用函数的对象。

际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用


一.绑定方式

this
thisundefined

独立函数调用

obj.foo()foothisobjcall()apply()thisfoo.call(obj)newthisthis

2.根据函数的调用方式的不同,this 会指向不同的对象:

fun();window.fun();

二.一些函数的this分析

1.setTimeout

setTimeout(function () {
   console.log(this); //Window
}, 1000);

2.div的点击

<div class="box">123</div>
<script>
   const boxDiv = document.querySelector(".box");
   boxDiv.onclick = function () {
      console.log(this);
       //<div class="box">123</div>
   };
</script>

3.数组的forEach

      var names = ["abc", "cba", "nba"];
      names.forEach(function (item) {
        console.log(item, this);
      });
      var names = ["abc", "cba", "nba"];
      names.forEach(function (item) {
        console.log(item, this);
      }, "abc");



三.this绑定优先级规则

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

毫无疑问,默认规则的优先级是最低的,因为存在其他规则时,就会通过其他规则的方式来绑定this


2.显示绑定优先级高于隐式绑定

call(),apply()

var obj = {
  name: "obj",
  foo: function() {
    console.log(this);
  }
}

obj.foo.call('abc') //[String: 'abc']
obj.foo.apply('abc')//[String: 'abc']

bind()

function foo() {
  console.log(this);
}

var obj = {
  name: "obj",
  foo: foo.bind("aaa")
}

obj.foo() //[String: 'aaa']

3.new绑定优先级高于隐式绑定

new
var obj = {
  name: "obj",
  foo: function() {
    console.log(this);
  }
}

var f = new obj.foo() //foo {}
newfooobjobj

4.new绑定优先级高于bind

new绑定和call、apply是不允许同时使用的,所以不存在谁的优先级更高
new绑定可以和bind一起使用,new绑定优先级更高

function foo() {
  console.log(this);
}

var bar = foo.bind("aaa")

var obj = new bar() //foo {}

5.this规则之外– 忽略显示绑定

apply/call/bind:当传入null/undefined时,自动将this绑定成全局对象

      function foo() {
        console.log(this);
      }

      foo.apply("abc"); //String:"abc"
      foo.apply({}); //Object

      foo.apply(null); //window
      foo.call(undefined); //window

      var bar = foo.bind(null);
      bar(); //window

6.this规则之外- 间接函数引用

function foo() {
  console.log(this);
};

var obj1 = {
  name: "obj1",
  foo: foo
};

var obj2 = {
  name: "obj2"
};

obj1.foo(); //obj1
(obj2.foo = obj1.foo)(); //window

7.箭头函数

简介

箭头函数不会绑定this、arguments属性;
箭头函数不能作为构造函数来使用(不能和new一起来使用,会抛出错误);

箭头函数简写:

1.如果函数执行体只有返回一个对象, 那么需要给这个对象加上()

var bar = () => ({name: "ha", age: 17})

2.如果函数执行体中只有一行代码, 那么可以省略大括号

nums.forEach(item => console.log(item))

this绑定规则

箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined。

var name = "ha"

var foo = () => {
  console.log(this);
}

foo() //window
var obj = {foo: foo}
obj.foo() //window
foo.call("bac") //window

不论通过什么方式调用,this 绑定的是最近一层非箭头函数的 this

应用场景

var obj = {
  data: [],
  getData: function() {
    setTimeout(function() {
      var result = ["abc","cba","nba"]
      this.data = result
    },2000)
  }
}

obj.getData()
console.log(obj.data);//Array(0)
//此时obj拿不到result数组,
//因为this指向出了问题:setTimeout的this指向是window,此时obj的data仍是空数组

改进:

var _this = this
var obj = {
  data: [],
  getData: function() {
    var _this = this
    setTimeout(function() {
      var result = ["abc","cba","nba"]
      _this.data = result
    },1000)
  }
}

obj.getData()
console.log(obj);

使用箭头函数:

var obj = {
  data: [],
  getData: function() {
    setTimeout(() => {
      var result = ["abc","cba","nba"];
      this.data = result;
    },1000)
  }
}

obj.getData();
console.log(obj);
/*data: Array(3)
0: "abc"
1: "cba"
2: "nba"
length: 3
*/

如果getData也是一个箭头函数,那么setTimeout中的回调函数中的this指向谁呢?

window

var obj = {
  data: [],
  getData: () => {
    setTimeout(() => {
      console.log(this); //window
    }, 1000);
  },
};
obj.getData();

四.面试题

var name = "window"
var person = {
  name: "person",
  sayName: function() {
    console.log(this.name);
  }
}

function sayName() {
  var sss = person.sayName;
  sss();//window
  person.sayName();//person
  (person.sayName)();//person:这里的括号加与不加都是一样的
  (b = person.sayName)();//window:间接函数引用
}
sayName()

总结

定义对象不产生作用域,对象不是作用域,函数是作用域

var name = "window"
var person1 = {
  name: "person",
  foo2: () => console.log(this.name);
  foo4: function() {
    return () => {
      console.log(this.name)
    }
  }
}

var person2 = {name: 'person2'}

person1.foo2()//window
person1.foo2.call(person2)//window

person1.foo4()()//person1
person1.foo4.call(person2)()//person2
person1.foo4().call(person2)//person1
var name = "window"
function Person(name) {
  this.name = name
  this.foo2 = () => console.log(this.name)
  this.foo4 = function() {
    return () => {
      console.log(this.name)
    }
  }
}
var person1 = new Person('person1')
var person2 = new Person('person2')

person1.foo2()//person1
person1.foo2.call(person2)//person1

person1.foo4()()//person1
person1.foo4.call(person2)()//person2
person1.foo4().call(person2)//person1

检验自己是否真正理解: