zoukankan      html  css  js  c++  java
  • 白话js this指向问题

    前言

      通过本文,你大概能了解this基础指向的问题,抛开例子去说this太虚幻,这里还是结合几篇博文做个整理,算是个人的记录了。

      先说概念,this指向与申明无关,永远指向距离自己最近最终调用者。我们从几种调用情况去理解,下面看看例子理解下:

    1.函数的直接调用

    function a(){
        var age = '25';
        console.log(this.age);//undefined
        console.log(this);//window
        
    }
    a();

      如上,我们申明一个函数,然后直接调用,a()前面没任何调用它的对象,这时候我们一般理解为被全局window对象调用,那我们就得去window去找age属性,很明显window没有,这里输出undefined。

      我们改改代码,用window去调用函数a,同时定义a的age属性,如下:

    window.age = "26";
    function a(){
        var age = '25';
        console.log(this.age);//26
        console.log(this);//window
    }
    window.a();

      那我们可以这样理解,针对函数调用,我们在一个函数内申明this,我们去看它最终是被谁调用,如果最终的调用前啥都没有,this就会指向window,这里只是针对js非严格模式。

    function a(){
        var age = '25';
        console.log(this.age);//undefined
        console.log(this);//window
    }
    function b(){
        a();
    }
    b();

      你以为我说到这,函数调用的this问题就说完了?不存在的,死记硬背难啊,情况多变,为什么函数直接调用,前面啥都没有就指向window,为什么?

      我在知乎看到一篇从函数调用原理讲this的文章,这里就引入下,这是知乎原文 this 的值到底是什么?一次说清楚

      函数一般常见三种调用方式,其实对于我是两种
     
      1.func(a,b)---普通函数调用
     
      2.obj.child.method(context,a,b)---调用对象内的某个方法,这个方法相当于对象的子属性
     
      3.func.call(context,a,b)---这个我确实在调用中没怎么用过。
     
      对于前两种,普通调用,对象属性的函数调用我们都常见,而第三种其实才是我们原本函数该有的调用,那我们这个this的讲解就偏偏与第三种有关系了。我们将前两者改写为第三种调用。
    func(a,b) ==>func.call(undefined,a,b)
    obj.child.method ==> obj.child.method.call(obj.child,a,b)
    //因为不确定obj里面的method是属于obj的属性还是boj child的属性,再加个
    obj.method ==> obj.method.call(obj,a,b)

      那我们就可以将所有的函数调用统一为  func.call(context,a,b)这一种,如果不是这一种,按照上面去改写,其中context就是我们一直苦苦寻找的this.

      OK,上面是函数的普通调用,咱们来改写上面的例子。

    function a(){
        var age = '25';
        console.log(this.age);//undefined
        console.log(this);//window
        
    }
    a();//等价于a.call(undefined);

      那按照我们上面说的,this应该是undefined啊,为毛是Window,这里又插入一个小规则

      如果你传的 context 就 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)

      那这里我们就明白为啥普通函数直接调用,this指向window了。

      2.函数作为对象属性方法被调用

      怎么去解释,我们还是用上面函数调用的改写去理解,先看一个例子。

    var a = {
        age:"29",
        fn:function(){
            console.log(this.age);  //29
        }
    }
    a.fn();//等价于 a.fn.call(a)
    //参照
    obj.method ==> obj.method.call(obj,a,b)来看
    
    

      method fn是对象a的一个属性,照着上面的对等公式,最终this指向就是对象a自己,也验证了上面我们说的,this指向它最终的的调用者。

      再来看一个例子:

    var a = {
        age:10,
        func:{
            age:12,
            fn:function(){
                console.log(this.age); //12
            }
        }
    }
    a.func.fn();//等价于 a.method.fn.call(a.method)
    //参照obj.child.method ==> obj.child.method.call(obj.child,a,b)来看

      func是对象a的一个child属性,而方法fn包含在func内,所以参照这个公司,this指向了a.func,而a.func提供了age属性,这里就输出12了,问题不大吧?

      那我们现在来融合函数调用与对象调用来看个例子:

    var a = {
        age:10,
        func:{
            age:12,
            fn:function(){
                console.log(this.age); //undefined
                console.log(this); //window
            }
        }
    }
    var j = a.func.fn;
    j();//等价于 window.j()或者j.call(undefined)

      跟我读,this指向最终,且离自己最近的调用者,最终调用的是方法j(),按照改写说得通,按照我们说的方法前面啥都没有就是window也说的通,就是这个意思了。

     3.构造函数的调用

      我们先来看个例子,当我们输出a.user,this指向了谁?

    function Fn(){
        this.age = 25;
    }
    var a = new Fn();
    console.log(a.age);//25

      先明白this指向谁,我们要弄懂什么是构造函数,new干嘛了?var a =new Fn()干嘛了?

      构造函数就是初始化一个实例对象,当我们new Fn()其实就是将Fn()复制了一份,并作为对象返回,赋值给了变量a。

      我们可以console a,得到的就是Fn()函数的实例,而且继承了Fn里面的age属性,所以此时this指向a,a里面有age属性。

      我们来白话一遍,这样说,当我们用构造函数方法,this指向我们new出来返回的对象,就是复制Fn得到了一个Fn副本,this指向了Fn副本,而这个Fn副本被赋予给了变量a,于是this指向了a,这个Fn副本继承了原函数的属性,所以这里顺利的输出了25.(并不是复制了整个函数,这句话有问题,我暂时不理解)

     构造函数与return

      我在上面说,构造函数this会指向new之后的实例(复制出来的副本),但如果在函数里有return,this指向可能会发生变化。

    function Fn(){  
        this.age = 17;  
        return {age:18};
    }
    var a = new Fn();  
    console.log(a); //{age:18}
    console.log(a.age);//18

      很明显,return的对象赋值给了变量a,这里输出了18.再来看看这段代码:

    function Fn()  
    {  
        this.age = '25';  
        return function(){};
    }
    var a = new Fn();  
    console.log(a.age); //undefined

      再来一段代码:

    function Fn()  
    {  
        this.age = 11;  
        return 1;
    }
    var a = new Fn();  
    console.log(a.age); //11

      我们可以做个大致判断,当在构造函数中return 一个对象时,this会指向这个对象,如上面的第一 ,第二段代码,但如果return的不是一个对象,那就不会改变this指向,还是指向new 出来的实例。

      ------取自JS权威指南8.2.3节

      大概整理到这,后期再回来填坑。

    参考资料

    彻底理解js中this的指向,不必硬背。

    this 的值到底是什么?一次说清楚

     this详解

  • 相关阅读:
    自定义view代码
    省份封装代码
    监听锁屏广播,开启1个像素的Activity
    双进程守护
    新增,查询,删除,修改下方即可
    #Android笔记#解决textview使用SpannableString实现图文混排并设置了行高时,图片与文字显示混乱
    显示地图
    局部页面传值Model
    JS的跳转
    helper实现隐藏前台特效
  • 原文地址:https://www.cnblogs.com/echolun/p/8809991.html
Copyright © 2011-2022 走看看