打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
我也来说说this,谁说this总指向函数的调用者的
userphoto

2015.10.12

关注
先说句题外话,如果你觉得我讲得明白的话给个反馈,点个赞,留个言啥的。
学js,如果没弄明白this指向的问题,基本可以说js还没入门。
关于this指向的问题,上网搜资料能搜一大把,基本上都是说this总是指向某个对象的,指向函数的调用者的。
说对也对,但不全面,如果某个函数没有调用者时,this是指向window的。
先来看看是怎么总结出来,“this总是指向函数的调用者的”
  1. console.log(this)//window

  2. var fun = function(){
  3.         console.log(this);
  4. };

  5. fun();//打印window
  6. // 等价于如下的调用方式
  7. this.fun();
  8. window.fun();

  9. // 匿名函数 可以理解成window创建某个变量保存这个匿名函数,然后删除了这个变量
  10. (function(){
  11.         console.log(this);
  12. })();// 打印window
复制代码

这里window调用函数,函数里的this指向window。
对象也是一样
  1. var fun = function(){
  2.         console.log(this);
  3. };
  4. var o = {
  5.         fn : fun
  6. }
  7. o.fn();//打印对象o

  8. // 如下的方式也没问题
  9. var a = {
  10.         name : "xiao2",
  11.         sayName : function(){
  12.                 alert(this.name);
  13.         }
  14. };
  15. a.sayName();//弹出xiao2
复制代码

数组、函数、自定义对象、以及dom对象都是对象,this是指向这个对象的。其他对象的例子不一一举了,这里再举一下dom对象的例子
  1. <section>
  2.         <button id="btn" name="myBtn" style="width:100px;height:30px;">点击我</button>
  3. </section>
  4. <script>
  5. var btn = document.getElementById('btn');
  6. // 点击按钮时弹出myBtn
  7. btn.onclick = function(){
  8.         alert(this.name);
  9. }
  10. </script>
复制代码

我们点击按钮,触发点击事件,这个onclick函数是btn调用,this指向btn没问题。
再看一下构造函数中的this
  1. var Person = function(name,age){
  2.         this.name = name;
  3.         this.age = age;
  4.         this.sayName = function(){
  5.                 alert(this.name);
  6.         }
  7. };
  8. Person.prototype.sayAge = function(){
  9.         alert(this.age);
  10. };
  11. var p = new Person("老姚",18);
  12. p.sayName();//弹出 老姚
  13. p.sayAge();//弹出 18
复制代码

new一个函数时,函数也会执行的。可以看做p调用了Person这个构造函数,里面的this.name、this.age 、this.sayName中的this都是指向p的;
p.sayName()、p.sayAge()是p调用函数,这两个里面的this当然指向对象p了。
从上面的代码中,基本可以总结了,this总是函数调用者的。那么再看看如果函数没用调用者呢?
  1. var o = {
  2.         fn : function(){
  3.                 console.log(this);        // 标记1
  4.                 var a = function(){
  5.                         console.log(this);// 标记2
  6.                 };
  7.                 a();
  8.         } 
  9. };
  10. o.fn();//标记1 打印对象o,标记2 打印window
复制代码

你说上述代码中执行语句a(),a调用者是谁?是对象o吗,是window吗,都不是,如不信,你改成o.a()或者window.a(),浏览器肯定会报错的。
a是没有调用者,你只能说在fn的作用域中,a被调用了。而此时函数没有调用者时,里面的this指向window的。
this的指向的问题我是说明白了,再总结一下:如果函数有调用者时,this指向调用者,如果没有调用者,this指向window的。上述代码中,都没有涉及闭包问题。







这里举个例子
  1. var b = function(){
  2.         console.log(this);        // 标记1
  3.         return function(){
  4.                 console.log(this);// 标记2
  5.         }
  6. }
  7. var c = b();//标记1 打印window
  8. c();// 标记2 打印window c是被window调用的,打印window没问题

  9. var a = {
  10.         fn : c
  11. }
  12. a.fn();// 标记2 打印对象a,没问题

  13. //如下方式呢
  14. var e = {
  15.         fn : function(){
  16.                 c();
  17.         }
  18. }
  19. e.fn();// 标记2 打印window 因为c()是没有调用者的
复制代码

可以看出,不管是不是闭包,还是那句话,能找到调用者就指向调用者,找不到就指向window。
《js高级程序设计》里面是这么说的,匿名函数的执行环境具有全局性的。我是这么看的,找不到调用者时,执行函数就具有全局性。跟你这个函数是不是有名匿名没有任何关系。
第二部分
如何保证this,是我们想要的this呢
有几个方法,这里大致说下
1.不把某个函数名,直接赋值某个变量,而是外面加一层函数,然后再调用,换句话说,给你机会来让这个函数执行时指定调用者或者不设置调用者,直接上代码
  1. <section>
  2.         <button id="btn" name="myBtn" style="width:100px;height:30px;">点击我</button>
  3. </section>
  4. <script>
  5. var name="老姚";
  6. var btn = document.getElementById('btn');
  7. var f  = function(){
  8.         alert(this.name);
  9. };
  10. btn.onclick = f;
  11. </script>
复制代码

上述代码,点击按钮时弹出的是btn对象的name:mybtn。如果想要弹出window中的name,可以改成如下代码
  1. <section>
  2.         <button id="btn" name="myBtn" style="width:100px;height:30px;">点击我</button>
  3. </section>
  4. <script>
  5. var name="老姚";
  6. var btn = document.getElementById('btn');
  7. var f  = function(){
  8.         alert(this.name);
  9. };
  10. btn.onclick = function(){
  11.         f();
  12. };
  13. </script>
复制代码

2.设置变量缓存this,如
  1. var name = "yyy";
  2. var Person = function(name){
  3.         this.name = name;
  4.         (function(){alert(this.name)})();
  5. }
  6. new Person("xxx");
复制代码

上代码运行会弹出window的name:yyy,如果想弹出对象的name:xxx,可以改成
  1. var name = "yyy";
  2. var Person = function(name){
  3.         this.name = name;
  4.         var self = this;
  5.         (function(){alert(self.name)})();
  6. }
  7. new Person("xxx");
复制代码

3.应用call、apply方法来指定this
  1. var name = "yyy";
  2. var o = {name: "xxx"};
  3. var fun = function(x,y){
  4.         alert(this.name)
  5.         return x+y;
  6. }
  7. fun(3,4);
  8. // 等于于如下的调用
  9. fun.call(window,3,4);
  10. fun.call(this,3,4);
  11. fun.apply(window,[3,4]);
  12. fun.apply(this,[3,4]);
复制代码

上述代码运行弹出window的name:yyy,如果要弹出o的name,可以改成
  1. var name = "yyy";
  2. var o = {name: "xxx"};
  3. var fun = function(x,y){
  4.         alert(this.name)
  5.         return x+y;
  6. }
  7. fun.call(o,3,4);
  8. fun.apply(o,[3,4]);
复制代码

4.应用框架函数,一般的框架都有给函数绑定上下文的函数(基本也都是应用apply和call),比如jquery的$.proxy().这里写个函数
  1. function proxy(fn,context){
  2.         return function(){
  3.                 fn.apply(context,arguments);
  4.         }
  5. }
复制代码

举例如下
  1. var o = {name: "xxx"};
  2. var fun = function(x,y){
  3.         alert(this.name)
  4.         return x+y;
  5. }
  6. var fun2 = proxy(fun,o);
  7. fun2(3,4);
复制代码

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
jQuery插件开发
Web前端面试题Javascript篇汇总
JavaScript this 关键字详解
JavaScript中的DOM与BOM
javaScript中常用的设计模式
25个最基本的JavaScript面试问题及答案
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服