关于this的深入认识

从学习前端开始已经大概要两个月了,这几天突然发现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)

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,487评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,621评论 2 374
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,611评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,659评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,509评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,380评论 1 274
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,799评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,443评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,739评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,781评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,554评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,400评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,811评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,043评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,330评论 1 253
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,775评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,978评论 2 337

推荐阅读更多精彩内容