一、前言

this关键字是JavaScript中最简单的机制之一。它是一个很特地的关键字,被主动定义在所有函数的作用域中。对于那些没有投入工夫学习this机制的JavaScript开发者来说,this的绑定始终是一件十分令人困惑的事。

二、理解this

学习this的第一步是明确this既不指向函数本身也不指向函数的词法作用域,你兴许被这样的解释误导过,但其实它们都是谬误的。随着函数应用场合的不同,this的值会发生变化。但总有一条准则就是JS中的this代表的是以后行为执行的主体,在JS中次要钻研的都是函数中的this,但并不是说只有在函数里才有this,this实际上是在函数被调用时产生的绑定,它指向什么齐全取决于函数在哪里被调用。如何的辨别this呢?

三、this到底是谁

这要分状况探讨,常见有五种状况:

1、函数执行时首先看函数名后面是否有".",有的话,"."后面是谁,this就是谁;没有的话this就是window

function fn(){  console.log(this);}var obj={fn:fn};fn();//this->windowobj.fn();//this->objfunction sum(){     fn();//this->window}sum();var oo={ sum:function(){ console.log(this);//this->oo       fn();//this->window  }};oo.sum();

2、自执行函数中的this永远是window

  (function(){ //this->window })();  ~function(){ //this->window }();

3、给元素的某一个事件绑定办法,当事件触发的时候,执行对应的办法,办法中的this是以后的元素,除了IE6~8下应用attachEvent(IE一个驰名的bug)

  • DOM零级事件绑定
  oDiv.onclick=function(){     //this->oDiv  };
  • DOM二级事件绑定
  oDiv.addEventListener("click",function(){     //this->oDiv  },false);
  • 在IE6~8下应用attachEvent,默认的this就是指的window对象
  oDiv.attachEvent("click",function(){       //this->window  });

咱们大多数时候,遇到事件绑定,如上面例子这种,对于IE6~8下应用attachEvent不用太较真

function fn(){  console.log(this);}document.getElementById("div1").onclick=fn;//fn中的this就是#divldocument.getElementById("div1").onclick=function(){console.log(this);//this->#div1fn();//this->window};

4、在构造函数模式中,类中(函数体中)呈现的this.xxx=xxx中的this是以后类的一个实例

function CreateJsPerson(name,age){//浏览器默认创立的对象就是咱们的实例p1->thisthis.name=name;//->p1.name=namethis.age=age;this.writeJs=function(){console.log("my name is"+this.name +",i can write Js");   };//浏览器再把创立的实例默认的进行返回}var p1=new CreateJsPerson("尹华芝",48);

必须要留神一点:类中某一个属性值(办法),办法中的this须要看办法执行的时候,后面是否有".",能力晓得this是谁。大家无妨看下接下来的这个例子,就可明确是啥意思。

function Fn(){this.x=100;//this->f1this.getX=function(){console.log(this.x);//this->须要看getX执行的时候才晓得   }}var f1=new Fn;f1.getX();//->办法中的this是f1,所以f1.x=100var ss=f1.getX;ss();//->办法中的this是window ->undefined

5.call、apply和bind

咱们先来看一个问题,想在上面的例子中this绑定obj,怎么实现?

var obj={name:"浪里行舟"};function fn(){console.log(this);//this=>window}fn();obj.fn();//->Uncaught TypeError:obj.fn is not a function

如果间接绑定obj.fn(),程序就会报错。这里咱们应该用fn.call(obj)就能够实现this绑定obj,接下来咱们具体介绍下call办法:

  • call办法的作用:

①首先咱们让原型上的call办法执行,在执行call办法的时候,咱们让fn办法中的this变为第一个参数值obj;而后再把fn这个函数执行。

②call还能够传值,在严格模式下和非严格模式下,失去值不一样。

//在非严格模式下var obj={name:"浪里行舟 "};function fn(num1,num2){console.log(num1+num2);console.log(this);}fn.call(100,200);//this->100 num1=200 num2=undefinedfn.call(obj,100,200);//this->obj num1=100 num2=200fn.call();//this->windowfn.call(null);//this->windowfn.call(undefined);//this->window
//严格模式下 fn.call();//在严格模式下this->undefinedfn.call(null);// 在严格模式 下this->nullfn.call(undefined);//在严格模式下this->undefined
  • **apply和call办法的作用是截然不同的,都是用来扭转办法的this关键字并且把办法
    执行,而且在严格模式下和非严格模式下对于第一个参数是null/undefined这种状况的规
    律也是一样的。**

两者惟一的区别:call在给fn传递参数的时候,是一个个的传递值的,而apply不是一个个传,而是把要给fn传递的参数值对立的放在一个数组中进行操作。然而也相当子一个个的给fn的形参赋值。总结一句话:call第二个参数开始承受一个参数列表,apply第二个参数开始承受一个参数数组

fn.call(obj,100,200);fn.apply(obj,[100,200]);
  • bind:这个办法在IE6~8下不兼容,和call/apply相似都是用来扭转this关键字的,然而和这两者有显著区别:
fn.call(obj,1,2);//->扭转this和执行fn函数是一起都实现了fn.bind(obj,1,2);//->只是扭转了fn中的this为obj,并且给fn传递了两个参数值1、2,                     然而此时并没有把fn这个函数执行var tempFn=fn.bind(obj,1,2);tempFn(); //这样才把fn这个函数执行

bind体现了预处理思维:当时把fn的this扭转为咱们想要的后果,并且把对应的参数值也筹备好,当前要用到了,间接的执行即可。

call和apply间接执行函数,而bind须要再一次调用。

  var a ={        name : "Cherry",        fn : function (a,b) {            console.log( a + b)        }    }  var b = a.fn;  b.bind(a,1,2)

上述代码没有执行,bind返回扭转了上下文的一个函数,咱们必须要手动去调用:

 b.bind(a,1,2)() //3

必须要申明一点:遇到第五种状况(call apply和bind),后面四种全副退让。

四、箭头函数this指向

箭头函数正如名称所示那样应用一个“箭头”(=>)来定义函数的新语法,但它优于传统的函数,次要体现两点:更简短的函数并且不绑定this

var obj = {    birth: 1990,    getAge: function () {        var b = this.birth; // 1990        var fn = function () {            return new Date().getFullYear() - this.birth; // this指向window或undefined        };        return fn();    }};

当初,箭头函数齐全修复了this的指向,箭头函数没有本人的this,箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this

换句话说,箭头函数的this看外层的是否有函数,如果有,外层函数的this就是外部箭头函数的this,如果没有,则this是window

    <button id="btn1">测试箭头函数this_1</button>    <button id="btn2">测试箭头函数this_2</button>    <script type="text/javascript">           let btn1 = document.getElementById('btn1');        let obj = {            name: 'kobe',            age: 39,            getName: function () {                btn1.onclick = () => {                    console.log(this);//obj                };            }        };        obj.getName();    </script>

上例中,因为箭头函数不会创立本人的this,它只会从本人的作用域链的上一层继承this。其实能够简化为如下代码:

   let btn1 = document.getElementById('btn1');        let obj = {            name: 'kobe',            age: 39,            getName: function () {                console.log(this)            }        };   obj.getName();

那如果上一层并不存在函数,this指向又是谁?

    <button id="btn1">测试箭头函数this_1</button>    <button id="btn2">测试箭头函数this_2</button>    <script type="text/javascript">           let btn2 = document.getElementById('btn2');        let obj = {            name: 'kobe',            age: 39,            getName: () => {                btn2.onclick = () => {                    console.log(this);//window                };            }        };        obj.getName();    </script>

上例中,尽管存在两个箭头函数,其实this取决于最外层的箭头函数,因为obj是个对象而非函数,所以this指向为Window对象

因为this在箭头函数中曾经依照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无奈对this进行绑定,即传入的第一个参数被疏忽

var obj = {    birth: 1990,    getAge: function (year) {        var b = this.birth; // 1990        var fn = (y) => y - this.birth; // this.birth仍是1990        return fn.call({birth:2000}, year);    }};obj.getAge(2018); // 28

扩大浏览

箭头函数-廖雪峰
JS中的箭头函数与this
this、apply、call、bind