一、为什么会有this的出现

    “this关键词是JS中最复杂的机制之一,它是一个很特别的关键字,被自动定义在所有函数的作用域中”根据凯尔辛普森的书中描述,刚开始阅读时我对this的使用都感觉到有点一头雾水,虽然隐隐约约知道this的出现是为了使代码更简洁而且利于复用,同时this单指“这个“单词是非常意味鲜明的,但在各种情况下不同的this指向,反倒是让人觉得这个设计逻辑很反人类。

二、this

this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式,简单来说,只有在函数执行this才会有它的指向,如果函数不执行,则this没有任何意义。

三、this的绑定规则

1、默认绑定

默认绑定下,this默认指向window,什么时候会认为是默认绑定呢?即是函数的独立调用,this默认指向window,以及在全局作用域下this默认指向window。

function test(){  
    console.log(this === window); 
}
test();   //函数独立调用 this指向window

var a = 0 l
function foo(){
  console.log(this);  //this指向window
}
var obj = {
  a:2;
  foo:foo;
}
var bar = obj.foo;   //bar赋值为对象obj的foo方法  
bar();   //独立调用foo函数

2、隐式绑定

this体现为谁调用就指向谁。

var a = 888;
var obj = {
    a: 666;
    foo: function(){
          console.log(this);    // obj     
     }     
}    
var obj1 ={
  o:obj;
}
obj.foo();   //对象obj调用,则指向对象obj
obj1.o.foo(); //this指向obj,距离调用自己最近的对象

  

3、显式绑定

 显式绑定是指通过用call,apply以及bind方法来改变this的行为,相比隐式绑定,this指向变化过程。

  call()方法

  call()方法的作用:可以调用一个函数,于此同时,改变这个函数内部的this指向,此外call()方法还可以实现继承。

语法:

fn.call(想要this指向的地方,函数实参1,函数实参2);//第一个如果不改变this指向,则传null
//call()实现this指向的改变
const obj1 = {
  Name:'Essie',
  Age:23,
};
function fn(){
  console.log(this);  //window
  console,log(this.nickname);  //undefined
}
fn.call(this);  //this没有改变 函数调用fn(),指向window

function fn1(a,b){
  console.log(this);  //obj1
  console.log(this.nickname);  //Essie
  console.log(a+b);  //6
}
fn1.call(obj1,3,3);  //this指向obj1对象

//call()实现继承
function Father(Name,Age){
  this.name = Name;
  this.age = Age;
}
function Son(Name,Age){
  Father.call(this,Name,Age);  //call()方法下Son继承了Father里的name和age属性
}
const son = new Son('Essie',23);
console.log(JSON.stringfy(son));  //{"Name":"Essie","Age":23}

 apply()方法

apply需要传递数组,所以会有些不同。

语法:

fn.apply(想要this指向的地方,[函数实参1,函数实参2]);//第一个参数不改变this指向,传null
const obj1 = {
  Name:'Essie',
  Age:23,
};
function fn1(a){
  console.log(this);  //obj1
  console.log(this.nickname);  //Essie
  console.log(a);  //6
}
fn1.apply(obj1,['hello']);//this指向obj1,然后执行fn1()函数

 bind()方法

  bind()方法不会调用函数,但是可以改变函数内部的this指向,如果不需要立即调用,但又需要改变函数的内部指向, 则bind()是最为合适的。

语法:

函数 = fn.bind(想要this指向的地方,函数实参1,函数实参2);//第一个不改变,则传null
bind函数是有返回值的

  

4、new绑定

  用new来调用函数u,发生构造函数调用是,执行操作步骤是,首先创建一个全新的对象;新的对象会被执行[Prototype]连接;新对象会绑定到函数调用的this;如果函数没有手动返回对象,则返回创建的新对象。

语法例子

function foo(a){
     this.a = a;    
}

var bar = new foo(2);  //new了一个新对象并绑定到foo的this
console.log(bar.a);  //2

四、this绑定优先级

显示绑定>隐式绑定>默认绑定

new绑定>隐式绑定>默认绑定

五、箭头函数的调用

六、原型链中的this

七、主要注意的地方

this指向只在函数执行时才有其实际意义,而且this指向永远不取决于写在哪,而是取决于谁调用。

1、以函数形式独立调用时(普通函数、立即执行函数、setTimeOut)调用,this指向的都是Window全局。

2、以方法形式调用的时候,this指向调用方法的对象

3、以构造函数调用的时候,this指向实例对象

4、以事件绑定函数的形式调用的时,this指向绑定事件的对象

5、使用call、apply调用,this指向指定的对象