美文网首页
关于this的深入认识

关于this的深入认识

作者: 悲欢自饮丶 | 来源:发表于2017-09-16 20:35 被阅读0次

从学习前端开始已经大概要两个月了,这几天突然发现this并没有想想中这么简单,之前很长一段时间对于this的认识停留在它的指向方法上。

  • 当以方法的形式调用时,this指向调用者
  • 当以函数的形式调用时,this指向window
  • 当以构造函数的形式调用时,this就是新创建的那个函数
  • 而改变this指向的方法有两种:apply和call

那时对this只是一个简单的认识,这么说来也没有任何理解上的问题。但是学到后来,发现this的应用光靠这些基础已经远远不够了。

从绑定方式上我姑且把它分为4种方式。

默认绑定

  • 独立函数调用:可以把这条规则看作是无法应用其他规则时的默认规则
  • 独立函数调用:如果使用了非严格模式,this 会绑定到全局对象(window)
  • 独立函数调用:如果使用严格模式( strict mode ),this 会绑定到 undefined
  • 这里有一个微妙但是非常重要的细节,虽然 this 的绑定规则完全取决于调用位置。
    • 但是只有 foo()运行在非 strict mode 下时,默认绑定才能绑定到全局对象;
    • 在严格模式底下foo()会绑给undefined

多说无用,下面来看代码.

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

      (function(){
        "use strict";
        foo();
      })()

这个时候严格模式不会影响默认绑定规则,此时输出的是2

        function foo() {
          "use strict";
          console.log( this.a );
        }
        var a = 2;
        foo(); 

现在这个时候会报错,a为undefined.

隐式绑定

  • 隐式绑定的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象

  • 对象属性引用链中只有最顶层或者说最后一层会影响调用位置

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

毋庸置疑this指向调用者obj,输出2

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

这个时候this指向obj2,输出42

  • 一个最常见的 this 绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而把 this 绑定到全局对象或者 undefined 上.(取决于是否是严格模式)
    function foo() {
            console.log( this.a );
        }
        var a = "hello word"; 
        var obj = {
            a: 2,
            foo: foo
        };
        
        var bar = obj.foo; 
        bar(); 

这个时候会发生隐式丢失,this指向全局对象:hello word

  • 参数传递其实也是一种隐式赋值,因此我们传入函数时也会被隐式赋值
        function foo() {
            console.log( this.a );
        }

        function doFoo(fn) {
            fn(); 
        }

        var a = "hello word"; 
        var obj = {
            a: 2,
            foo: foo
        };
        
        doFoo( obj.foo ); 

这个时候会发生隐式丢失,this指向全局对象:hello word

如果你把函数传入语言内置的函数而不是传入你自己声明的函数,你会发现结果是一样的,没有区别,比如定时器的内置函数:

        function foo() {
            console.log( this.a );
        }
        
        var a = "hello word"; 
        var obj = {
            a: 2,
            foo: foo
        };
        
        setTimeout( obj.foo, 1000 );  

结果输出的仍然是:hello word

显示绑定

  • 我们不想在对象内部包含函数引用,而想在某个对象上强制调用函数,具体点说,可以使用函数的 call(..) 和 apply(..) 方法来实现显示绑定.
        var a =0;
        function foo() {
            console.log( this.a );
        }
        var obj = {
            a:1
        };
        var obj2 = {
            a:2
        };
        var obj3 = {
            a:3
        };
        foo();
        foo.call( obj );
        foo.apply( obj2 );
        foo.call( obj3 );

如果没有给foo使用call方法,foo使用的就是默认绑定,foo()输出0,。使用call apply方法,输出分别为1,2,3

  • 什么是硬绑定:一种显示绑定的变种
    • 我们来看看这个显式绑定变种到底是怎样工作的。我们创建了函数 bar() ,并在它的内部手动调用了 foo.call(obj) ,因此强制把 foo 的 this 绑定到了 obj 。无论之后如何调用函数 bar ,它总会手动,在 obj 上调用 foo 。这种绑定是一种显式的强制绑定,因此我们称之为硬绑定。
        var a =1;
        function foo() {
            console.log( this.a );
        }

        var obj = {
            a:2
        };

        var obj_test = {
            a:"test"
        };

        var bar = function() {
            foo.call( obj );
        };
        
        bar(); //2
        setTimeout( bar, 1000 ); // 2
        bar.call( obj_test ); //2   

硬绑定的bar不可能再修改它的this(指的是foo中的this),是不是解决了之前的隐式丢失。(定时器内部this的调用是独立调用)

-简单的辅助绑定函数bind函数的作用:返回一个新的函数,并且指定该新函数的this指向

        function bind(fn, obj) {
            return function() {
                    return fn.apply( obj, arguments );
                };
        }
        
        var obj = {
            a:2
        };
        var obj_test = {
            a:22
        };
        
        
        var bar = bind( foo, obj);
        var b = bar(3); // 2 3 undefined
        console.log( b ); // 5
        bar.call(obj_test,3);//2 3 undefined

有了bind函数,我们可以把经过绑定的函数拿去使用(这样它就有默认值了)

new绑定

  • 我们重新定义一下JS中的“构造函数”。JavaScript,构造函数只是一些使用 new 操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。实际上,它们甚至都不能说是一种特殊的函数类型,它们只是被 new 操作符调用的普通函数而已。

  • 实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”

  • 使用 new 来调用函数,或者说发生构造函数调用时,对于我们的this来说。这个新对象会绑定到函数调用的 this 。

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

使用 new 来调用 foo(..) 时,我们会构造一个新对象并把它绑定到 foo(..) 调用中的 this 上。new 是最后一种可以影响函数调用时 this 绑定行为的方法,我们称之为 new 绑定。

绑定的优先级

最后我们来说一说绑定的优先级

new绑定 > 显示绑定 > 隐式绑定 > 默认绑定

绑定例外

es6中胖箭头this指向与我们现在的规则不一样

被忽略的this:apply call bind(null) this----> window

柯里化:为函数去预绑定参数

var obj = Object.create(null)

之后如果有机会我会在下面继续补充的。。。。

相关文章

  • 关于this的深入认识

    从学习前端开始已经大概要两个月了,这几天突然发现this并没有想想中这么简单,之前很长一段时间对于this的认识停...

  • 关于滑板的深入认识

    先从历史说起,它是1950年左右在美国兴起,当时经济不景气 ,有很多废弃工厂,青少年到处罢学,成堆街头游玩,想当于...

  • 原则-实现梦想目标的-快捷方式

    读过李笑来的书后对于原则有了更深的认识。 关于选择,关于注意力,关于元认知,关于什么最重要。 越深入了解,对自己对...

  • RxJava 从入门到爱上它 - 线程控制的深入理解

    RxJava 从入门到爱上它 - 认识 RxJava 从入门到爱上它 - "变换"的深入理解 关于Backpre...

  • 深入认识Document

    来源:深入认识Document作者:yuyuyu 前端开发中或多或少都要对DOM进行一些操作,比如我们常用的一些方...

  • 深入认识自己

    每天重复进行的坏习惯而不自知。有没有感觉自己的某些习惯,做着做着自己也很讨厌,而且感觉到很违反自己内心,但是仍然不...

  • 深入认识自己,写下关于以下的回答

    1、从遗传上找到自己的天赋 写出父亲的天赋 写出母亲的天赋 写出自己的天赋 2、观察自己的身体天赋 写出你自己是否...

  • 20200915主题审议培训

    问题来园:关于内容,关于幼儿、教师和资源。 我认识了什么,我学会了什么,探究了什么 整体感知——点上深入——表达表现

  • 先认识自己

    想要提升认知,首先要从认识自己下手,认识自己为什么会做各种各样的行为,只有先了解了自己,我们才能深入思考这个关于这...

  • 【认识自己】复盘(一)

    前面关于认识自己,从“我是谁”、“我不是谁”和“做情绪的主人”中逐步深入地开启自我探索。 尽管不会...

网友评论

      本文标题:关于this的深入认识

      本文链接:https://www.haomeiwen.com/subject/oxdusxtx.html