欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简析js中的this的指向

程序员文章站 2022-04-29 08:18:09
...

  回想当初在切图网做前端项目,用到js,经常用到this;那我们就谈谈js中this,如果说你没弄清this指向的问题,那基本可以说js没入门。

  this指向的问题的文章,上网搜资料能搜一大把,基本上都是说this总是指向某个对象的,指向函数的调用者的。

  如果某个函数没有调用者时,this是指向window的。

  先来看看是怎么总结出来,“this总是指向函数的调用者的”

  console.log(this)//window

  var fun=function(){

  console.log(this);

  };

  fun();//打印window

  // 等价于如下的调用方式

  this();

  window();

  // 匿名函数 可以理解成window创建某个变量保存这个匿名函数,然后删除了这个变量

  (function(){

  console.log(this);

  })();// 打印window

  这里window调用函数,函数里的this指向window。

  对象也是一样

  数组、函数、自定义对象、以及dom对象都是对象,this是指向这个对象的。其他对象的例子不一一

  举了,这里再举一下dom对象的例子

  

  

  

  

  var btn=document.getElementById('btn');

  // 点击按钮时弹出myBtn

  btn.onclick=function(){

  alert(this.name);

  }

  

  我们点击按钮,触发点击事件,这个onclick函数是btn调用,this指向btn没问题。

  再看一下构造函数中的this

  var Person=function(name,age){

  this.name=name;

  this.age=age;

  this.sayName=function(){

  alert(this.name);

  }

  };

  Persontotype.sayAge=function(){

  alert(this.age);

  };

  var p=new Person("切图网",18);

  p.sayName();//弹出 切图网

  p.sayAge();//弹出 18

  new一个函数时,函数也会执行的。可以看做p调用了Person这个构造函数,里面的this.name、this.age 、this.sayName中的this都是指向p的;

  p.sayName()、p.sayAge()是p调用函数,这两个里面的this当然指向对象p了。

  从上面的代码中,基本可以总结了,this总是函数调用者的。那么再看看如果函数没用调用者呢?

  var o={

  fn : function(){

  console.log(this); // 标记1

  var a=function(){

  console.log(this);// 标记2

  };

  a();

  }

  };

  o.fn();//标记1 打印对象o,标记2 打印window

  你说上述代码中执行语句a(),a调用者是谁?是对象o吗,是window吗,都不是,如不信,你改成o.a()或者window.a(),浏览器肯定会报错的。

  a是没有调用者,你只能说在fn的作用域中,a被调用了。而此时函数没有调用者时,里面的this指向window的。

  this的指向的问题我是说明白了,再总结一下:如果函数有调用者时,this指向调用者,如果没有调用者,this指向window的。上述代码中,都没有涉及闭包问题。

  这里举个例子

  var b=function(){

  console.log(this); // 标记1

  return function(){

  console.log(this);// 标记2

  }

  }

  var c=b();//标记1 打印window

  c();// 标记2 打印window c是被window调用的,打印window没问题

  var a={

  fn : c

  }

  a.fn();// 标记2 打印对象a,没问题

  //如下方式呢

  var e={

  fn : function(){

  c();

  }

  }

  e.fn();// 标记2 打印window 因为c()是没有调用者的

  可以看出,不管是不是闭包,还是那句话,能找到调用者就指向调用者,找不到就指向window。

  《js高级程序设计》里面是这么说的,匿名函数的执行环境具有全局性的。我是这么看的,找不到调用者时,执行函数就具有全局性。跟你这个函数是不是有名匿名没有任何关系。

  第二部分

  如何保证this,是我们想要的this呢

  有几个方法,这里大致说下

  1.不把某个函数名,直接赋值某个变量,而是外面加一层函数,然后再调用,换句话说,给你机会来让这个函数执行时指定调用者或者不设置调用者,直接上代码

  

  

  

  

  var name="切图网";

  var btn=document.getElementById('btn');

  var f=function(){

  alert(this.name);

  };

  btn.onclick=f;

  

  上述代码,点击按钮时弹出的是btn对象的name:mybtn。如果想要弹出游戏账号拍卖window中的name,可以改成如下代码

  

  

  

  

  var name="切图网";

  var btn=document.getElementById('btn');

  var f=function(){

  alert(this.name);

  };

  btn.onclick=function(){

  f();

  };

  

  2.设置变量缓存this,如

  var name="yyy";

  var Person=function(name){

  this.name=name;

  (function(){alert(this.name)})();

  }

  new Person("xxx");

  上代码运行会弹出window的name:yyy,如果想弹出对象的name:xxx,可以改成

  var name="yyy";

  var Person=function(name){

  this.name=name;

  var self=this;

  (function(){alert(self.name)})();

  }

  new Person("xxx");

  3.应用call、apply方法来指定this

  var name="yyy";

  var o={name: "xxx"};

  var fun=function(x,y){

  alert(this.name)

  return x+y;

  }

  fun(3,4);

  // 等于于如下的调用

  fun.call(window,3,4);

  fun.call(this,3,4);

  fun.apply(window,[3,4]);

  fun.apply(this,[3,4]);

  上述代码运行弹出window的name:yyy,如果要弹出o的name,可以改成

  var name="yyy";

  var o={name: "xxx"};

  var fun=function(x,y){

  alert(this.name)

  return x+y;

  }

  fun.call(o,3,4);

  fun.apply(o,[3,4]);

  4.应用框架函数,一般的框架都有给函数绑定上下文的函数(基本也都是应用apply和call),比如jquery的$xy().这里写个函数

  function proxy(fn,context){

  return function(){

  fn.apply(context,arguments);

  }

  }

  var o={name: "xxx"};

  var fun=function(x,y){

  alert(this.name)

  return x+y;

  }

  var fun2=proxy(fun,o);

  fun2(3,4);

  文/丁向明

  做一个有博客的web前端自媒体人,专注web前端开发,关注用户体验,加我qq/微信交流:6135833

  dingxiangming