• 关于js中的this


    关于js中的this

    this是javascript中一个很特别的关键字,也是一种很复杂的机制,学习this的第一步就是要明白this既不指向函数自身也不指向函数的词法作用域,this实际上是函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用

    1. 调用位置

    现在来说一下调用位置:调用位置就是函数在代码中被调用的位置(而不是声明的位置)。
    那么怎么找到它的调用位置呢?最重要的是要分析“调用栈”(就是为了到达当前执行位置所调用的所有函数)

     
    function baz(){
         //当前调用栈是:baz
         //因此,当前调用位置是全局作用域
         console.log("baz");
         bar();//<-- bar的调用位置
    
    }
    function bar(){
         //当前调用栈是:baz->bar
         //因此,当前调用位置是在baz中
         console.log("bar");
         foo();//<--foo的调用位置
    }
    function foo(){
         //当前调用栈是:baz->bar->foo
         //因此,当前调用位置是在bar中
         console.log("foo");
    
    }    
    baz();//<--baz的调用位置`
     
    

    分析调用栈,可以将调用栈想象成一个函数调用链(比如:foo函数里面注释的这一句‘当前调用栈是:baz->bar->foo’)在这条函数调用链的所在的函数的前一个函数,就是所在函数的调用位置(foo函数中baz->bar->foo)

    还有另外一种查看调用栈的方法,就是使用浏览器的调试工具(我所使用的是chrome浏览器)
    你可以在工具中给每个函数的里面的第一行(不是注释,其他行也可以)设置一个断点,然后运行(刷新一下)

    enter description here
    在工具中展示的调用列表,找到栈中的第二个元素(从栈顶往下第二个),这就是该函数的真正的调用位置。

    2. 绑定规则

    现在我们已经找到了调用位置,那调用位置如何决定this的绑定对象呢?
    this的绑定规则有四条,而且应用多条规则时还要注意它们的优先级(这里没讲)

    1. 默认绑定

    可以把这条规则看作无法应用其他规则时的默认规则,最常用的函数调用类型:独立函数调用

    function foo(){
    console.log(this.a);
    }
    var a=2;
    foo();//2
    

    首先要明白,在全局作用域中声明上的变量就是全局对象中一个同名属性
    接下来,我们在调用foo()时,this.a被解析成了全局对象a。因为在本例中函数调用的时候应用了this的默认绑定(在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的),因此this指向全局对象。
    但是要注意:以上的情况实在非严格模式下,但是在严格模式下,全局对象无法使用默认绑定,因此this会绑定到undefined。

    2.隐式绑定

    function foo(){
    console.log(this.a);
    }
    var obj={
    a:2,
    foo:foo};
    obj.foo();//2

    enter description here
    在这个例子中,函数foo被当作引用属性添加到obj中,但严格的说它并不属于obj对象,然后,调用位置会使用obj上下文来引用函数,可以说
    函数被调用时obj对象“包含”它。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象,因为调用foo()时this被绑定到obj,因此this.a和obj.a是一样的。
    但是,对象属性引用链中个只有最顶层或者说最后一层会影响调用位置。

    function foo(){
            console.log(this.a);
    }
    var obj2={
    a:42,
    foo:foo
    };
    var obj1={
    a:2,
    obj2:obj2
    };
    obj1.obj2.foo();//42
    

    enter description here
    但是存在一个问题,被隐式绑定的函数有可能会丢失绑定对象,然后应用默认绑定规则,这里就不细讲了(比如在传入回调函数时.......)。

    3.显示绑定

    隐式绑定时,我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this隐式绑定到这个对象上。但是我们想粗暴一点怎么办的?
    javascript提供的大多数函数(除了一些非常特殊的函数)都有一些有用的特性,在这里我们可以使用函数的call(...)和apply(...)方法,这两个方法的区别在于参数的传递。
    它们的第一个参数是一个对象,它们会把这个对象绑定到this,接着在调用的时候指向这个this,因为你可以直接指定this的绑定对象,因此我们称之为显示绑定。

    function foo(){
    console.log(this.a);
    }
    var obj={a:2};
    foo.call(obj);//2
    

    通过foo.call(...)我们可以在调用foo时强制把它的this绑定到obj上。但是显示绑定还是无法解决丢失绑定问题,但是显示绑定的一个变种可以解决这个问题,这里不讲了)

    4.new绑定

    javascript中的new操作符和那些面向类的语言的机制完全不同,在javascript中,那所谓的“构造函数”只不过是使用new操作符时被调用的函数,但它并不属于这个类,也不会实例化一个类,就是被new操作符调用的普通函数而已。
    使用new来调用汗书时,会执行下列操作
    1.创建一个全新的对象。
    2.这个对象会执行[[原型]]连接
    3.这个新对象会绑定到函数调用的this
    4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

    function foo(a)
    { this.a=a;}
    var bar=new foo(2);
    console.log(bar.a);//2
    

    我们会构造一个新的对象并将它绑定到foo(..)调用中的this上。
    以上就是this的四种绑定规则。

    参考书籍《你不知道的JavaScript(上卷)》

  • 相关阅读:
    MySQL的四种事务隔离级别
    线上CPU飚高(死循环,死锁...)
    Tomcat7 调优及 JVM 参数优化
    tomcat8.5配置高并发
    Tomcat 8.5 基于 Apache Portable Runtime(APR)库性能优化
    android 高德地图 轨迹平滑处理
    android高德地图绘制线 渐变处理
    按下home键,重新打开,应用重启
    小米9屏下指纹判断
    android 9.0以上charles https抓包
  • 原文地址:https://www.cnblogs.com/bluey/p/4903425.html
Copyright © 2020-2023  润新知