Js-this指向问题、call()、apply()、bind()改变this指向

爱被打了一巴掌 2023-03-01 06:29 291阅读 0赞

0-零 - this几种指向

  1. 在全局中this:指向window。
  2. 对象方法中this:this指向该对象本身。
  3. 回调函数中this:指向window。
  4. 事件回调中this:指向e.currentTarget,给谁添加的事件监听就指向那个元素。
  5. 箭头函数中this:指向箭头函数外层的this。
  6. 类中this:指向实例化对象,哪个对象调用这个方法、this就指向哪个对象;静态方法和静态属性中:this指向这个类。
  7. call()、apply()、bind()中:将函数中this的指向 改变为这三个方法的第一个参数、当第一个参数为空或者为null时,表示将函数中的this指定到window。

Ⅰ- 壹 - 全局中this

全局对象的 this 是window

  1. console.log(this);//window
  2. function abc(){
  3. console.log(this);//window,严格模式下undefined
  4. }
  5. abc();

Ⅱ - 贰 - 对象方法中this

  • 对象属性中使用 this,this 指向外层的 this 指向
  • 对象方法中使用 this,this 指向该对象本身

可以理解为,属性描述 this 时,这个时候对象还没有生成,所以属性中的 this 指向外层的 this 指向;当调用对象的方法时,对象已经生成,所以方法中的 this 指向该对象本身。

对象属性中使用 this,this 指向外层的 this 指向

  1. var a = 10;
  2. var obj1 = {
  3. a: 100,
  4. c: this.a, //属性中的this指向该对象的this,即window
  5. init: function () {
  6. console.log(this.a);//100 方法中的this指向该对象,即obj1
  7. console.log(this.c);//10
  8. }
  9. }
  10. obj1.init();

对象方法中使用 this,this 指向该对象本身

  1. var a = 10;
  2. var obj1 = {
  3. a: 100,
  4. c: this.a, //属性中的this指向上一层的this,即window
  5. init: function () {
  6. console.log(this.a);//100,方法中的this指向该对象,即obj1
  7. var obj = {
  8. a: 1,
  9. c: this.a, //属性中的this指向上一层的this,即obj1
  10. b: function () {
  11. console.log(this.a);//1,方法中的this指向该对象,即obj
  12. console.log(this.c);//100,方法中的this指向该对象,即obj
  13. }
  14. }
  15. obj.b();
  16. }
  17. }
  18. obj1.init();
  19. console.log(obj1.c);//10

Ⅲ - 叁 - 回调函数中this

将函数作为参数传入,无法确定该函数的原来的this指向。所以统一将回调函数中的this都指向window。

下面的案例中,如果函数abc()的this指向是window;函数obj.c()的this指向obj;将他们分别作为参数代入obj.b() 中,obj.b() 无法判读出他们原来的this指向。所以统一将this指向window。

  1. function abc() {
  2. console.log(this);
  3. }
  4. var obj = {
  5. a: function () {
  6. this.b(this.c);
  7. // this.b(abc);
  8. },
  9. b: function (fn) {
  10. fn();
  11. console.log(this); //方法中的this指向该对象,即obj
  12. },
  13. c: function () {
  14. console.log(this); //回调函数中的 this 指向 window
  15. }
  16. }
  17. obj.a();

同理,forEach()、filter()、map()、some()、every()、promise…中函数都是回调函数,它们的 this 也都指向 window。

  1. var arr=[1,2,3];
  2. arr.forEach(function(){
  3. console.log(this);//window
  4. })

Ⅳ - 肆 - 事件回调中this

事件侦听中的 this 指向 e.currentTarget,即给谁添加的事件侦听,this 就指向谁。

事件函数中的this,会覆盖普通对象中函数的this的指向;

  1. // 事件侦听
  2. document.addEventListener("click",clickHandler);
  3. // 事件回调函数
  4. function clickHandler(e){
  5. // this--->e.currentTarget
  6. console.log(this);//document
  7. }
  8. var obj = {
  9. d: () => {
  10. console.log(this);//window
  11. document.addEventListener("click", this.obj.loadHander);
  12. },
  13. loadHander(e) {
  14. console.log(this)//document
  15. }
  16. }
  17. obj.d();
  18. var obj = {
  19. d: () => {
  20. console.log(this); //window
  21. document.addEventListener("click", e => this.obj.loadHander(e));
  22. },
  23. loadHander(e) {
  24. console.log(this) //obj
  25. }
  26. }
  27. obj.d();

Ⅴ - 伍 - 箭头函数中this

箭头函数改变了this指向,将指向箭头函数外层的this

  1. var obj={
  2. a:function(){
  3. var arr=[1,2,3];
  4. arr.forEach(function(){
  5. console.log(this);//window 遵从于回调函数的this指向
  6. });
  7. arr.forEach(item=>{
  8. console.log(this);//obj 因为使用了箭头函数,就会忽略了回调函数的this指向
  9. })
  10. document.addEventListener("click",this.clickHandler);//obj
  11. document.addEventListener("click",e=>{
  12. console.log(this);//obj 因为使用箭头函数,就会忽略了事件函数中this指向
  13. })
  14. },
  15. clickHandler:function(e){
  16. console.log(this)//document 遵从于事件函数中this---e.currentTarget
  17. }
  18. }
  19. obj.a();
  20. var obj = {
  21. d: () => {
  22. console.log(this);//window
  23. document.addEventListener("click", this.obj.loadHander);
  24. },
  25. loadHander(e) {
  26. console.log(this, e.currentTarget)//this=>document e.currentTarget指向document
  27. }
  28. }
  29. obj.d();
  30. var obj = {
  31. d: () => {
  32. console.log(this); //window
  33. document.addEventListener("click", e => this.obj.loadHander(e));
  34. },
  35. loadHander(e) {
  36. console.log(this, e.currentTarget) //this=>obj e.currentTarget指向document
  37. }
  38. }
  39. obj.d();

使用箭头函数侦听事件回调,因为箭头函数是匿名函数,所以没有办法清除,可以通过自定义箭头函数来进行清除。

  1. //原始的
  2. document.documentElement.addEventListener("click", clickHandler);
  3. function clickHandler(e) {
  4. console.log(this);//html
  5. }
  6. //document.documentElement.removeEventListener("click", clickHandler);
  7. //普通的箭头匿名函数,因为是匿名函数,所以没有办法清除
  8. document.documentElement.addEventListener("click",e=>clickHandler())
  9. function clickHandler(e) {
  10. console.log(this);//window
  11. }
  12. //定义的箭头函数,可以removeEventListener
  13. var handler = e => { clickHandler(e)};
  14. document.documentElement.addEventListener("click", handler);
  15. function clickHandler(e) {
  16. console.log(this);//window
  17. }
  18. //document.documentElement.removeEventListener("click", handler);

Ⅵ - 陆 - 类中this

  • 类中的 this 指实例化的对象,谁调用方法,在类的函数中 this 就是那个实例对象
  • 静态属性和静态方法中的 this 指的是这个类

    //ES6中类的写法
    class Rect{

    1. constructor(){
    2. this.elem=this.createElem();
    3. }
    4. createElem(){
    5. if(this.elem) return this.elem;
    6. let div=document.createElement("div");
    7. Object.assign(div.style,{
    8. width:"50px",
    9. height:"50px",
    10. backgroundColor:"red",
    11. position:"absolute",
    12. left:"0px"
    13. });
    14. div.addEventListener("click",e=>this.clickHandler(e))
    15. return div;
    16. }

    }
    //实例化对象
    let rect=new Rect();
    //上面代码中的this全都指向rect

ES6中类的写法和ES5中类的写法:

  1. //ES6中类的写法
  2. class Box{
  3. static a=3;
  4. b=4;
  5. static c=this.a;//this指Box,static c=3;
  6. constructor(){
  7. }
  8. play(){
  9. //this 指实例化对象
  10. }
  11. static once(){
  12. //this 指Box
  13. }
  14. }
  15. // ES5中没有类,借用原型的概念实现类
  16. function Box(){
  17. //相当于ES6中constructor()
  18. }
  19. Box.a=3;//相当于ES6中的static a=3;
  20. Box.once=function(){
  21. //相当于ES6中的static once(){};
  22. }
  23. Box.prototype.b=4;//相当于上述中的b=4;
  24. Box.prototype.play=function(){
  25. //相当于上述中的play(){};
  26. }

Ⅶ - 柒 - call()、apply()、bind()方法改变this指向


























方法名 参数 简述
call() 第一个参数为this指向的对象,第二个参数为函数的参数只能一个一个的添加 函数会立刻执行,
apply() 第一个参数为this指向的对象,第二个参数为函数的参数可以是数组、列表或者扩展运算符 函数会立刻执行,
bind() 第一个参数就是函数里面 的this就是的内容 函数不会立刻执行,

一 call()

  • 会立即执行函数;
  • 如果有一个参数,且该参数为对象类型,则表示将函数中 this 的指向改变为这里带入的参数;
  • 函数中如果没有this,call就没有任何意义了,和普通的执行函数概念一样;
  • call() 在执行函数时,函数的参数从第二位开始依次写入;
  • 如果使用call() 或者apply() ,第一个参数为空或者是null,就意味着将函数中this 重定向到 window;

语法: 方法名.call(对象);

  1. function fn(_a,_b){
  2. this.a=_a;
  3. this.b=_b;
  4. }
  5. fn();//等同于
  6. fn.call();//立即执行函数,this指向window
  7. let obj={ };
  8. fn.call(obj);//立即执行函数,且this指向obj,将obj带入到函数替代函数中this的指向,原有的this会被指向obj
  9. fn(3,4);//等同于
  10. fn.call(obj,3,4);

二 apply()

  • apply() 和 call() 一样都是改变this的指向为第一个参数对象;
  • apply() 的参数只有2个,第一个参数为函数中 this 的指向,第二个参数是函数所需的所有参数的数组,列表
  • 如果使用call() 或者apply() ,第一个参数为空或者是null,就意味着将函数中this 重定向到 window;

    function fn(_a,_b){
    this.a=_a;
    this.b=_b;
    }
    fn();//等同于
    fn.call();//立即执行函数,this指向window

    let obj={ };
    fn.apply(obj);//立即执行函数,且this指向obj

    fn(3,4);//等同于
    fn.apply(obj,[3,4]);

1 获取数组的最小值案例

  1. var arr=[1,2,3,4,5];
  2. var min=Math.min.apply(null,arr);//Math方法使用
  3. //重构min
  4. var Maths={
  5. min:function(){
  6. if(arguments.length===0) return;
  7. var min=arguments[0];
  8. if(arguments.length===1) return min;
  9. for(var i=1;i<arguments.length;i++){
  10. min=min.arguments[i]?arguments:min;
  11. }
  12. return min;
  13. }
  14. }
  15. //使用
  16. Maths.min.apply(null,arr);

2 将一个元素集合转为数组

  1. <div></div>
  2. <div></div>
  3. <div></div>
  4. <div></div>
  5. <script>
  6. var divs=document.getElementsByTagName("div");
  7. console.log(divs);//HTMLCollection(5) [div, div, div, div, div]
  8. var arr=Array.prototype.slice.call(divs);
  9. //var arr=[].slice.call(divs);//跟上面的写法意思一样
  10. console.log(arr);//[div, div, div, div, div]
  11. //重构转换数组Array.prototype.slice.call() 实现原理:
  12. class Arrays{
  13. constructor(){
  14. }
  15. slice(start,end){
  16. if(start===undefined) start=0;
  17. if(end===undefined) end=this.length;
  18. var arr=[];
  19. for(var i=start;i<end;i++){
  20. arr.push(this[i]);
  21. }
  22. return arr;
  23. }
  24. }
  25. //使用
  26. var arr=new Arrays();
  27. arr.slice.call(document.getElementsByTagName("div"));
  28. </script>

三 bind()

  • 当需要在回调函数中重新执行回调函数中的this,就需要是用bind来指向对象
  • bind() 会返回一个对象,函数里面 的this就是绑定的内容。

    //函数会延时执行
    var obj={ a:1};

    1. setTimeout((function(){
    2. console.log(this);//打印{a:1}
    3. }).bind(obj),10000);//绑定到obj
  1. //在事件中 绑定this的指向为obj
  2. var obj={
  3. a:1,
  4. b:function(){
  5. this.handler=this.clickHandler.bind(this);
  6. document.addEventListener("click",this.handler)
  7. },
  8. clickHandler:function(e){
  9. console.log(this);
  10. document.removeEventListener("click",this.handler)
  11. }
  12. }
  13. obj.b();

1 红绿黄灯切换

  1. var id;
  2. function setLight() {
  3. arguments[0](arguments[1], arguments[2]);
  4. }
  5. function showLight(fn,fn2){
  6. clearTimeout(id);
  7. console.log(this.toString());
  8. id = setTimeout(fn, 2000, fn2, arguments.callee.bind(this));
  9. }
  10. setLight(showLight.bind("红"),showLight.bind("黄"),showLight.bind("绿"));

四 call()、apply()、bind()方法区别

  • 定时器 延时器 事件绑定 都不可以用因为call apply会立刻执行函数
  • call apply第一参数都一样为this的指向,call第二个参数只能一个一个的填写而apply可以是数组或者列表也可以使用扩展运算符 (…)
  • 可以使用bind() 将一个函数绑定为某个对象但不会立刻执行
  • 将函数中 this 的指向改变为这里带入的第一个参数,当第一个参数为空或者是null时,表示将函数中 this 重定向到 window;

    //在延时器中使用会立即执行不会等待10秒执行
    var obj={ a:1};

    1. setTimeout((function(){
    2. console.log(this);
    3. }).call(obj),10000);
  1. //
  2. function fn(_a,_b){
  3. this.a=_a;
  4. this.b=_b;
  5. }
  6. fn.call();//this指向window
  7. fn.apply();//this指向window
  8. let obj={ };
  9. fn.call(obj);//立即执行函数,且this指向obj
  10. fn.apply(obj);//立即执行函数,且this指向obj
  11. fn.bind(obj);//不执行,只是将this指向obj

0 - 0 - 知识点:

一 对象,事件 箭头函数 this

  1. var obj = {
  2. d: () => {
  3. console.log(this);//window
  4. document.addEventListener("click", this.obj.loadHander);
  5. },
  6. loadHander(e) {
  7. console.log(this, e.currentTarget)//this=>document e.currentTarget指向document
  8. }
  9. }
  10. obj.d();
  11. var obj = {
  12. d: () => {
  13. console.log(this); //window
  14. document.addEventListener("click", e => this.obj.loadHander(e));
  15. },
  16. loadHander(e) {
  17. console.log(this, e.currentTarget) //this=>obj e.currentTarget指向document
  18. }
  19. }
  20. obj.d();

二 this总结

  1. 在全局中this:指向window。
  2. 对象方法中this:this指向该对象本身。
  3. 回调函数中this:指向window。
  4. 事件回调中this:指向e.currentTarget,给谁添加的事件监听就指向那个元素。
  5. 箭头函数中this:指向箭头函数外层的this。
  6. 类中this:指向实例化对象,哪个对象调用这个方法、this就指向哪个对象;静态方法和静态属性中:this指向这个类。
  7. call()、apply()、bind()中:将函数中this的指向 改变为这三个方法的第一个参数、当第一个参数为空或者为null时,表示将函数中的this指定到window。

发表评论

表情:
评论列表 (有 0 条评论,291人围观)

还没有评论,来说两句吧...

相关阅读

    相关 this指向问题

    解题思路 1. 普通函数中,this是它的直接调用者,谁调用,this就指向谁。 2. 箭头函数,this指向跟外部作用域中this指向是同一个。 面试真题

    相关 this指向问题

    this指向,是我们在开发中不得不关注的一个点,当我们进行事件处理时,如果疏忽this的指向问题,可能会发生意想不到的错误。 那么,让我们来了解一下this吧。 this呢