zoukankan      html  css  js  c++  java
  • 关于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(上卷)》

  • 相关阅读:
    VIJOS-P1340 拯救ice-cream(广搜+优先级队列)
    uva 11754 Code Feat
    uva11426 GCD Extreme(II)
    uvalive 4119 Always an Interger
    POJ 1442 Black Box 优先队列
    2014上海网络赛 HDU 5053 the Sum of Cube
    uvalive 4795 Paperweight
    uvalive 4589 Asteroids
    uvalive 4973 Ardenia
    DP——数字游戏
  • 原文地址:https://www.cnblogs.com/bluey/p/4903425.html
Copyright © 2011-2022 走看看