首页 存档 技术 查看内容

【郑州-第八十二期】JS中this的指向

2018-3-30 13:00 |来自: 互联网 323 0

摘要: JS中this的指向 小课堂【郑州第八十二期】 分享人:王相博 1.背景介绍在Java语言中,this关键字的含义是明确且具体的,表示当前对象。而在javascript中,this是动态绑定的,它可以是全局对象、当前对象或者任意 ...



JS中this的指向

小课堂【郑州第八十二期】

分享人:王相博






1.背景介绍

在Java语言中,this关键字的含义是明确且具体的,表示当前对象。而在javascript中,this是动态绑定的,它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。这就导致了this具备了多重含义,可以使得javascript更灵活的使用。但是,带来了灵活性的同时也会给我们初学者带来不少困惑。

2.知识剖析

全局环境中的this

        console.log(this);        

总结:在全局作用域中它的 this 执行当前的全局对象(浏览器端是 Window,node 中是 global)

严格模式 ‘use strict’下的this

        'use strict';         function test() {         console.log(this);         };                  test();                  // undefined        

原因:this 并不会指向全局,而是 undefined,这样的做法是为了消除 js 中一些不严谨的行为

在javascritp中,不一定只有对象方法的上下文中才有this, 全局函数调用和其他的几种不同的上下文中也有this指代。 它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。JavaScript 中函数的调用有以下几种方式:作为对象方法调用,作为函数调用,作为构造函数调用,和使用 apply 或 call 调用。

1.作为对象方法调用:this 被自然绑定到该对象

       var obj = {          name: 'qiutc',          foo: function() {          console.log(this.name);          }        }          obj.foo();          // 'qiutc'        

2.作为函数调用:this被绑定到全局对象

        function test() {          console.log(this);          };          test();          // Window        

3.作为构造函数调用:this 绑定到新创建的对象上

       function Person(name) {          this.name = name;          console.log(this);          }          var p = new Person('dawa');          // Person {name: "dawa"}        

注:构造函数不使用new调用,则和普通函数一样。一般地,构造函数首字母大写

4.使用 apply 或 call 调用:在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。

 function cat(){}  cat.prototype={    name:"tom",    food:"fish",    say: function(){      console.log(this.name " love " this.food);    }};  var blackCat = new cat;  blackCat.say();  whiteDog = {name:"dog",food:"bone"};  blackCat.say.call(whiteDog);  bird = {food:"fly", name:"blue"};  blackCat.say.apply(bird);        

3、常见问题

        var obj = {          name: 'qiutc',          foo: function() {           console.log(this);          },          foo2: function() {           console.log(this);           setTimeout(this.foo, 1000);          }         }                 obj.foo2();        

现象:两次打印的this不一样

4、解决方案

可以这么这么解决:利用 闭包 的特性来处理

var obj = {           name: 'qiutc',           foo: function() {            console.log(this);           },           foo2: function() {            console.log(this);            var _this = this;            setTimeout(function() {             console.log(this); // Window                       console.log(_this); // Object {name: "qiutc"}            }, 1000);           }          }                    obj.foo2();

可以看到直接用 this 仍然是 Window;因为 foo2 中的 this 是指向 obj,我们可以先用一个变量 _this 来储存,然后在回调函数中使用 _this,就可以指向当前的这个对象了

执行这段代码我们会发现两次打印出来的 this 是不一样的:
第一次是 foo2 中直接打印 this,这里指向 obj 这个对象,我们毋庸置疑;
但是在 setTimeout 中执行的 this.foo ,却指向了全局对象,这里不是把它当作函数的方法使用吗?这一点经常让很多初学者疑惑;
其实,setTimeout 也只是一个函数而已,函数必然有可能需要参数,我们把 this.foo 当作一个参数传给 setTimeout 这个函数,就像它需要一个 fun 参数,在传入参数的时候,其实做了个这样的操作 fun = this.foo,看到没有,这里我们直接把 fun 指向 this.foo 的引用;执行的时候其实是执行了 fun() 所以已经和 obj 无关了,它是被当作普通函数直接调用的,因此 this 指向全局对象。
这个问题是很多异步回调函数中普遍会碰到的;

5、编码实战

 var p = document.getElementsByTagName("p");  function cat(){}  cat.prototype={    name:"tom",    food:"fish",    say: function(){      console.log(this.name " love " this.food);    }};  var blackCat = new cat;  blackCat.say();  whiteDog = {name:"dog",food:"bone"};  blackCat.say.call(whiteDog);  bird = {food:"fly", name:"blue"};  blackCat.say.apply(bird);  function changeStyle(attr,value){    this.style[attr] = value;  }  var box = document.getElementsByTagName("p");  window.changeStyle.call(box[1],"borderTop","20px solid black");        

6.扩展思考

问题:如何理解this?

当一个函数被调用时,拥有它的object会作为this传入。在全局下,就是window or global,其他时候就是相应的object。 也可以看到,call和apply就是利用这一点实现更改this 值的

分享

        'use strict';         function foo() {          console.log(this);         }         setTimeout(foo, 1);         // window        

现象:加了严格模式,foo 调用也没有指定 this,应该是出来undefined,但是这里仍然出现了全局对象

难道是严格模式失效了吗? 并不,即使在严格模式下,setTimeout 方法在调用传入函数的时候,如果这个函数没有指定了的 this,那么它会做一个隐式的操作-自动地注入全局上下文,等同于调用 foo.apply(window) 而非 foo(); 当然,如果我们在传入函数的时候已经指定 this,那么就不会被注入全局对象,比如: setTimeout(foo.bind(obj), 1);;

7.参考文献

参考一:深入浅出 JavaScript 中的 this

参考二:JavaScript 中的 this !

参考三:JavaScript中的this用法与指向

参考四:如何理解 JavaScript 中的 this 关键字?

8、更多讨论

this含义为何如此丰富?

理解this的指向有何意义?




ppt地址:https://ptteng.github.io/PPT/PPT/js-02-js'this.html#/

文本地址:http://jnshu.com/daily/20555?uid=8495

视频地址:https://v.qq.com/x/page/m03938kxaoe.html