zoukankan      html  css  js  c++  java
  • 详解javascript中的this的指向问题

    首先,要明白this 既不指向函数自身,也不指函数的词法作用域。this一般存在于函数中,表示当前函数的执行上下文,如果函数没有执行,那么this没有内容,只有函数在执行后this才有绑定。

    然后,我们来看看this四种绑定规则,也可以说在四种不同函数执行方式时this的指向。

    1.默认绑定(执行)

    默认执行:即没有其他绑定规则存在时的默认规则。这也是函数调用中最常用的规则。this指向window,严格模式下指向undefined

    function fn(){
            console.log(this)
        }
        fn()
    

    fn()打印到控制台结果为window

    开启严格模式后

     function fn(){
            "use strict"
            console.log(this)
        }
        fn()
    

    fn()打印到控制台结果为undefined

    2.隐式绑定(执行)

    通过对象执行(通过上下文对象执行) obj.fn():当前的执行对象

    function fn(){
                console.log(this.a)
            }
            var a = 10;
            var obj = {
                a:20,
                b:fn
            }
            var obj2 = {
                a:30,
                b:obj.b
            }
            obj2.b();    //??
    

    obj2.b(); 打印到控制台结果为30

    因为obj2.b();在上述代码中等价于obj2.fn(),所以此时this指向obj2,所以打印结果为30;

    多层调用

      function fn(){
                console.log(this.a)
            }
            var a = 10;
            var obj = {
                a:20,
                b:fn
            }
            var obj2 = {
                a:30,
                b:obj.b
            }
            var obj3 = {
                a:40,
                b:obj2
            }
            obj3.b.b()    //?
    

    obj3.b.b() 打印结果为30

    上述代码调用结果为obj3.b->obj2,obj2.b->obj.b->fn,因为this只获取最近一层调用的上下文对象,即obj2

    所以结果为30

    隐式丢失(函数别名)

    注意:这里存在一个陷阱,大家在分析调用过程时,要特别小心

    function fn() { 
        console.log( this.a );
    }
    
    var a = 2;
    
    var obj = { 
        a: 3,
        b: fn 
    };
    
    var bar = obj.b;
    bar(); //?
    

    bar() 打印结果为2

    为什么会这样,obj.b 赋值给bar,那调用bar()为什么没有触发隐式绑定,使用的是默认绑定呢。

    这里有个概念要理解清楚,obj.b 是引用属性,赋值给bar的实际上就是fn函数(即:bar指向fn本身)。

    那么,实际的调用关系是:通过bar找到fn函数,进行调用。整个调用过程并没有obj的参数,所以是默认绑定,全局属性a。

    隐士丢失(回调函数)

    function fn(){
                console.log(this.a)
            }
            var a=20;
            var obj = {
                a:20,
                b:fn
            }
    setTimeout(obj.b, 2000);
    function setTimeout(cb,t){
                // t
                cb()     //?
    }
    

    cb()打印结果为20

    同样的道理,虽然参传是obj.fn,因为是引用关系,所以传参实际上传的就是fn对象本身的引用。对于setTimeout的调用,还是 setTimeout -> 获取参数中fn的引用参数 -> 执行 fn 函数,中间没有obj的参与。这里依旧进行的是默认绑定。

    3.显示绑定(执行)

     function fn(){
                console.log(this.a)
            }
    
           var obj1= {
                a:10
            }
           var  obj2 ={
                a:20
            }
           var obj3 ={
                a:30
            }
          fn.bind(obj1)();
          fn.call(obj2);
          fn.apply(obj3);
    

    fn.bind(obj1)();打印结果为10

    fn.call(obj2); 打印结果为20

    fn.apply(obj3); 打印结果为30

    这里要注意fn.bind(obj1)后面还要加一个括号才执行!

    4.new 绑定(构造函数执行(通过new执行))

    js中的new操作符,和其他语言中(如JAVA)的new机制是不一样的。js中,它就是一个普通函数调用,只是被new修饰了而已。

    使用new来调用函数,会自动执行如下操作:

    如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
    从这点可以看出,this指向的就是对象本身。

    function foo(a) { 
        this.a = a;
    }
    
    var a = 2;
    
    var bar1 = new foo(3);
    console.log(bar1.a); // ?
    
    var bar2 = new foo(4);
    console.log(bar2.a); // ?
    
    

    因为每次调用生成的是全新的对象,该对象又会自动绑定到this上,所以打印结果分别为3,4

    绑定规则优先级

    优先级是这样的,以按照下面的顺序来进行判断:
    数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。
    数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是 指定的对象。
    数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。
    果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到 全局对象。

  • 相关阅读:
    Python是如何进行内存管理的?
    scrapy利用set()对数据进行去重
    python快速抓取新闻标题及内容
    python爬虫第三方库
    Spring使用@Scheduled定时调度
    redis启动失败
    视图系统
    路由系统
    Django框架 part 2
    Django框架
  • 原文地址:https://www.cnblogs.com/mhcll/p/11439900.html
Copyright © 2011-2022 走看看