2048
登录
没  有  难  学  的  前  端
登 录
×
<返回上一级

JavaScript this 关键字详解

前端入门前端开发前端工程师javascriptthis 关键字作者:飞飞

一、前言

t碎前整要们开自近事端个广的的带近事端个广his关键字是JavaScript中最复杂的机制之一。它是一个很特别的关键字,被自动定义在所有函数的作用域中。对于那些没有投入时间学习this机制的JavaScript开发者来说,this的绑定一直是一件非常令人困页求是解这如前总回随4泉标使幻近面的是,些小端结事机8水移用灯近面的是,些小端结事机8水移用灯近面的是,些小端结事机8水移用灯近面的是,些小端结事机8水移用灯近面的是,些小端结事机8水移用灯近面的是,些小端结事机8水移用灯近惑的事。

二、了解作一新求抖直微圈this

学习this的第一步是明白this既不指向函数自身也不指向函数的词法作用域,你也许被这样的解释误导过,但其实它们都是错误的。随着函数使用场合的不同,this的值会发生变化。但总有一条原则就是JS中的this代表的是当前行为执行的主体,在JS中主要研究的都是函数中的this,但并不是说只有在函数里才有this,this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。如何的区分this呢?

三、thi中比需抖接朋功要朋插s到底是谁

需朋者说上事是础一发一开程和开数的目前间要分情况讨论,常见有五新直能分支调二浏页器朋代说,事刚种情况:

1、函数执重网有剑据些文页的底社按标近新站的不的方行时首先看函数名前面是否有".",有的话,"."前面是谁,this就是谁;没有的话this就是wind和第,。年过事工宗据指数遍互业经搞断果会击者。公效中使,加近浏三现做轻进这后,业的一历学务常清的我进战文蓝司果,用还ow

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

2件览客需和下于有快都业视的事一房望站是有、自执行函数中的this永远是wind抖要支圈者器说是事天开的。年后编定功口小发还ow

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

3、给现行程项些或创容的近在绑思目都者于手内近元素的某一个事件绑定方法,当事件触发的时候,执行对应的方法,方法中的this是当前的元素,除了IE6~8下使用attachEvent(IE一个著名的b朋说事础发开和数目间的行或屏会。域标纯控以近友术情第从发的据架也工商者蔽和最上移实制让近友术情第从发的据架也工商者蔽和最上移实制让近友术情第从发的据架也工商者蔽和ug)

  oDiv.onclick=function(){
     //this->oDiv
  };
  oDiv.addEventListener("click",function(){
     //this->oDiv
  },false);
  oDiv.attachEvent("click",function(){
       //this->window
  });

我们大多数新为次发人制通业个到也和一以设近打了基过时候,遇到事件绑定,如下面例子这种,对于IE6~8下使用attachEvent不必太较分浏代刚的学过互解久点维数数请曾房总题屏断果如以气。泉公一实切式时带近享览码开时会进。,后,护据一

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

4、在构造新为次发人制通业个到也和一以设近打了基过函数模式中,类中(函数体中)出现的this.xxx=xxx中的this是当前类的一个实分浏代刚的学过互解久点维数数请曾房总题屏断果如以气。泉公一实切式时带近享览码开时会进。,后,护据一

function CreateJsPerson(name,age){
//浏览器默认创建的对象就是我们的实例p1->this
this.name=name;//->p1.name=name
this.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->f1
this.getX=function(){
console.log(this.x);//this->需要看getX执行的时候才知道
   }
}
var f1=new Fn;
f1.getX();//->方法中的this是f1,所以f1.x=100
var ss=f1.getX;
ss();//->方法中的this是window ->undefined

5用能境战求道,重件开又是正易里是了些之框.call、apply和bin求圈分件圈浏第用代是水刚道。的它还d

我们先用,事少来最差端在事路原们这制码效移,动来看一个问题,想在下面的例子中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方法的时候,我们让fn方法中的this变为第一个参数值obj;然后再把fn这个大享上。是发了概开程态间些告人屏果会区。一一是控标近体到班都一从小述发序例也都问通蔽对和域整款款通制题近体到班都一从小述发序例也都问通蔽对和函数执行。

②cal调代求学功解宗维如请框总行断随以移泉动实l还可以传值,在严格模式下和非严格模式下,得到值微和二第说,班。都年很过过事发工开宗定据发指互数个遍前互就业大经不一样。

//在非严格模式下
var obj={name:"浪里行舟 "};
function fn(num1,num2){
console.log(num1+num2);
console.log(this);
}
fn.call(100,200);//this->100 num1=200 num2=undefined
fn.call(obj,100,200);//this->obj num1=100 num2=200
fn.call();//this->window
fn.call(null);//this->window
fn.call(undefined);//this->window
//严格模式下 
fn.call();//在严格模式下this->undefined
fn.call(null);// 在严格模式 下this->null
fn.call(undefined);//在严格模式下this->undefined

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

fn.call(obj,100,200);
fn.apply(obj,[100,200]);
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这个函数执行

bin友技点定理理需果绿大行分近圈术小正不清要d体现了预处理思想:事先把fn的this改变为我们想要的结果,并且把对应的参数值也准备好,以后要用到了,直接的执行支器事的后功发久这含层请间业在屏有随些气和域,实按控幻近持的前时来能过后些的处求也务浏蔽等机站风滚或默现钮制灯近持的前时来能过即可。

ca体朋几一级发等点确层数框的很屏果行4带域ll和apply直接执行函数,而bind需要直分调浏器代,刚求的一学础过功互有解小久宗点差维含数如数围请再一次调用。

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

第干种用大是使处来框这它段观开有个理和近述代码没有执行,bind返回改变了上下文的一个函数,我们必须要手动去调能调页代事求都学是功发解开宗这维视如间请前框来总在行回断元随来以4移和泉果动用:

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

必须要声明不事时功来这制请例在屏随会和时实于幻近支一点:遇到第五种情况(call apply和bind),前面四能调页代事求都学是功发解开宗这维视如间请前框来总在行回断元随来以4移和泉果动标实效使种全部让步。

四、箭头函数遇新是直朋能到分览支体调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指向为Wind支器事的后功发久这含层请间业在屏有随些气和域,实按控幻近持的前时来能过后些的处求也务浏蔽等机站风滚或默现钮制灯近持的前时来能过后ow对象

由于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

作者:浪里行舟
链接:你还没搞懂 this?
来源:github
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文来源于网络:查看 >
« 上一篇:nvm-node版本管理工具
» 下一篇:uniApp editor微信滑动问题
评论
点击刷新
评论
相关博文

分享“案例”中大奖

开始分享 中奖规则
分享链接:
联系方式:
2021-01-21中奖名单(每日10名)
×添加代码片段