谈谈js中的this指向

一,出现this的地方

1. 什么是this?

函数运行的主体,谁运行这个函数,this就是谁,分严格模式和非严格模式, 严格模式下window都为undefined,反之window对象

2. this作用

this提供了一种简明的方式来隐式传递一个对象引用,可以让函数接口设计的简单且容易复用

3. 什么出现this

this是在运行时绑定,而不是在编写时绑定,this实际值取决于函数调用时的上下文。this的绑定和函数声明的位置没有关系,只取决于函数的调用方式。在JavaScript中,当函数被调用时,会创建一个活动记录(执行时上下文),这个记录包含函数在何处调用、函数的调用方法和传入参数等信息,this会记录其中一个属性。判断this实际绑定值,关键在于分析函数实际调用的位置。

ES6打破了这种局面,在定义的时候已经定义好了this

4. 如何修改this指向
  1. call/apply/bind第一个参数
  call/apply的区别?
    call单个传值,apply已数组打包的方式传值  => fn.call(obj, 1,2,3)  fn.apply(obj, [1,2,3]);
    bind:预处理,事先处理好了,事件常用  IE6 ~ IE8不兼容
 	 eg: oDiv.onclick = function() {}.bind(this)
 	 
 模拟call

 capply和apply用途, 快速求数组最值
 	Array.prototype.getMax = function() {
 		return Math.max.apply(this, this);
  	};
 	Array.prototype.getMix = function() {
 		return Math.min.apply(this, this);
 	};
  1. 将当前this赋值给一个对象,存储下来, 作用域链去机制去查找, var _this = this; jQ常用 var $that = $(this);
  2. new 类() 改变函数里面的this为当前类的实例, 不加new是window对象,在非严格模式下,严格模式下undefined
	=>new 一个类执行四部曲:
  		1.  私有作用域预解释(带var和function的分别进行声明和定义)
  		2.  隐式创建一个新对象  ( let obj = {} )
  		3. 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) 
  		4. 执行构造函数中的代码(为这个新对象添加属性) this.xxx = xxx;
  		5. 隐式返回新对象 return obj;
  		    注意: 如果自己写return的话, 基本数据类型不受影响,如果返回引用数据类型,会把this对象给覆盖了
  1. es6 箭头函数 (arrow function) => 定义的时候已经完成了

5. 总结this出现的情况

  1. 自执行函数中的this(自执行函数) ==>window
  2. 函数执行返回函数中的this ==>匿名函数是window
  3. 对象中的this ==> 这个对象,对象的方法用箭头函数是window
  4. 普通函数执行的两种情况(前面有没有点<.>) ===>有点,this就是前面的,没有就是window
  5. 给DOM元素绑定事件中的this ==> DOM元素
  6. call/apply中的this ==>> params1参数
  7. bind中的this 在类的构造函数中 oDiv.onclick = function() {this.num =1}.bind(this);
  8. 定时器和超时器中的this(setInterval/setTimeout) ==> window
  9. *回调函数中的this(callback), ==> window
  10. 构造函数中的this(new Class) ==> 类的某个实例
  11. *ES6中箭头函数中的this ==> 上级作用域里面的this
  12. 当前作用域里面没有this,上级作用域里的this,上级没有在上级,直到window为止
  13. 在Node里面没有this,都是模块
- 1.箭头函数里面没有this,上级this,解决定时器,赋值问题(函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。)  **this对象的指向是可变的,但是在箭头函数中,它是固定**

- 2.箭头函数不能用类,不能new ,因为没有constructor,和原型prototype

- 3.箭头函数没有arguments,用reset代替

- 4.不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

ES5中的this是在函数运行时候定义的 (跟在哪没有关系,执行环境有关系)

ES6中的箭头函数this是在代码解释的时候已经定义好了(跟在哪环境有关系)

6. this情况详解

eg1:自执行函数中的this(自执行函数)

 什么是自执行函数? 声明完毕立即执行
 格式如下:
  ;(function(){}());
  ;(function(){})();
  ;~function(){}()
  ;!function(){}()
  
;(function(){
    console.log(this); // this==> Window
}());

const tools = function(){
    console.log(this); // this==> Window
}();

const jQuery = function() {
    var jQuery = function(select, context) {
        
    };
     this.jQuery = this.$ = jQuery; // ==>> window.jQuery = window.$ = jQuery;
}();

eg2:函数执行返回函数中的this(函数执行前面没有点,非严格模式下是window,严格模式下是undefined,有点的话,点前面是什么,this就是什么)

    var x = 1;
    var fn = function() {
        var x = 100;
        return function() {
            console.log(this.x);  // this ==> Window
        };
    };
    fn()(); // ==> 1
    

eg3:对象中的this

    var x  =1;
    var obj = {
        x: 100,
        fn() {
            console.log(this.x); //this ==> obj
        },
        getX(){
            return function() {
                console.log(this.x);  // this ==> 
            }
        }
    };
    obj.fn(); //==> 100
    obj.getX()(); //==> 1 函数执行返回一个匿名函数,没有执行主体,默认是window
    
    eg2:
        function foo() {
            console.log( this.a );
        }

        var a = 2;
        foo();  //  2

eg4:普通函数执行的两种情况(前面有没有点<.>) (隐式绑定)

    var x = 1;
    var fn = function() {
        console.log(this.x); // this ==> Window   this==>> obj
    };
    
    var obj = {
        name: 100,
        fn:fn,   //*** ===>> 隐式绑定
        getX(){
            return function() {
                return fn;
            }
        }
    };
    
    fn(); // ==> 1
    obj.fn(); // ==> 100
    obj.getX()()(); // ==> 1
    

eg5: 给DOM元素绑定事件中的this

    var fn = function() {
        console.log(this); // this ==>> Window
    };
    var oDiv = document.getElementById('div1');
    
    oDiv.onclick = function() {
        console.log(this);  // this ==>> oDiv
        fn();
    };
    

eg6: call/apply中的this(强行该变this指向),严格模式下是undefined

    fn.call/apply(this的代替, params);
    
    var x  =1;
    var obj = {
        x: 100,
        fn() {
            console.log(this.x); //this ==> obj
        },
        getX(){
            return function() {
                console.log(this.x);  // this ==> 
            }
        }
    };
    obj.fn.call(obj);
    obj.getX.apply(obj)()();
    
    用途:
      数组快速求最值问题
      Array.prototype.getMax = function() {
        return  Math.max.apply(null, this);
      };
      Array.prototype.getMin = function() {
        return  Math.min.apply(null, this);
      };
    
    

eg7: bind中的this

 var oSpan = document.getElementById('span1');
  待续
  oDiv.onclick = function() {
  	csonole.log(this);
  }.bind(oSpan);
  

eg8:定时器和超时器中的this(setInterval/setTimeout)

   ==>>eg1:
   setTimeout(function(){
       console.log(this); // this==> Window
   }, 1000);
   
   ==>>eg2:
   var x = 1;
    setInterval(function(){
        var x = 100;
       console.log(this.x); //this==> Window   1
   }, 1000);
   
  ==>>eg3: 这里出了问题,this是window,所以我们常常 var _this = this;
  oDiv.onclick = function() {
    setTimeout(fucntion(){
        this.innerHTML = '嘿嘿~~~';
    }, 1000);  
  };
   
   解决办法: 
    1) 存储当前this
    2) ES6箭头函数
   oDiv.onclick = function() {
    //==>ES5存储this解决
    var _this = this;
    setTimeout(fucntion(){
        _this.innerHTML = '嘿嘿~~~';
    }, 1000);  
    
    //==>ES6箭头函数解决
    setTimeout(() =>{
         this.innerHTML = '嘿嘿~~~';
    });
  };
   

eg9: 回调函数中的this(callback) (***)

    什么是回调函数: 当一件事情做完去做另一件事情
    回调函数的演进:
     --- callbapck
     --- promise
     --- Generator
     --- async awit
     
    var x = 1;
    function fn(callback) {
        var x = 100;
        setTimeout(function(){
            callback(x);
            callback(this.x);
        }, 500);
    }
    
    fn(function(val){
       console.log(val);   ??多少呢
    });

eg10: 构造函数中的this(new Class) ==>>实例

   function Person(name, age) {
       this.name = name;
       this.age = age;
   }
   Person.prototype.getName = function() {
       console.log(this.name);
   };
   Person.getAge = function() {
       console.log(this.age);  
   };

   // ***==>>不使用new的情况, 他就是普通函数
     1. 函数执行
     2. 形参赋值
     3. 预解释
     4. 代码从上到下执行
     5.执行完毕,返回值
     6.看外面有接收没有,没有内存释放,有了占用内存,不释放,需要手动释放
     
     var person1 = Person('常连海', 26);
     查看person1是什么?  
     console.dir(person1); //==> undefined 因为函数没有return,默认返回undefined
     
     //一下俊报错 undefined
     person1.name;
     person1.age;
     person1.getAge;
     
    //***==>> 使用new的情况,角色变量,成了一个类,有原型,私有属性等等
    1.函数执行
    2.浏览器默认创建一个这个类的实例(this)
    3.代码从上到下执行, this.xxx = xxx; 给这个实例挂属性和方法
    4.return this; 返回这个实例,
    5.看外面有接收没有,没有内存释放,有了占用内存,不释放,需要手动释放
    注:
        1)当使用类的时候,不传参数可以去掉括号
        2)一般类名首字母大写,区分
        3)不能手动加return,基本数据类型不印象,引用数据类型会把实例覆盖了(funciton/object)
    var person = new Person('clh', 25);
    
    console.dir(person);
    person.name;
    person.age;
    person instanceof Person; 
    
    person.getName();
    Person.getX();
    
    
    

eg11: ES6中箭头函数中的this(ES6箭头函数中是没有this,他的this是上级作用域里面的this,作用链问题)
==> ES6中引入了箭头函数,箭头函数使用操作符=>定义。箭头函数不使用上面4种this绑定规则,而是根据外层作用域来决定this:

    ==>> 1.箭头函数没有this (上级作用域里面的this)
    ==>> 2.箭头函数没有arguments对象 (reset参数代替)
    eg1:
        ;(() => {})(
            console.log(this); // this ==> Window
        );
        
    eg2:
        var name = 'Jon';
        var obj = {
            name: 'LiHua',
            getName:()=> {
                console.log(this.name);
            }
        };
        obj.getName();
        obj.getName.call(obj);
        
        
    eg3:
        oDiv.onclick = function() {
          setTimeout(()=>{
              this.innerHTML = 'hellow world';
          });  
        };

eg12.箭头函数

  let name = 'vue';
  let obj = {
      name: 'es6',
      showName1: ()=>{
        console.log(this.name);   
      },
      showName2() {
         console.log(this.name);   
      },
      showName3() {
          setTimeout(() =>{
            console.log(this.name); 
          });
      },
      
      showName4: function(){
          return () => {
            console.log(this.name);   
          }
      }
  };
  
  obj.showName1();      // ==>  ''
  obj.showName2();     //==> es6
  obj.showName3();    //==> es6
  obj.showName4()(); // ==> es6

7. 面试提关于this的总结

eg1: 基础

    var name = 1;
   function a() {
       var name = 2;
       console.log(this.name);
       console.log('inner' + this);
   }

   a();
   console.log('outer' + this);

eg2: 加深

 var name = "windowsName";
    var a = {
        name: "Cherry",
        fn: function () {
            console.log(this.name); // Cherry
        }
    }
    a.fn();
    window.a.fn();

eg3. 引出函数

   var name = "windowsName";
   var a = {
       name: null,
       // name: "Cherry",
       fn: function () {
           console.log(this.name); // windowsName
       }
   }
   var f = a.fn;
   f();

eg4. 内部this

  	var name = "windowsName";
    function fn() {
        var name = 'Cherry';
        innerFunction();

        function innerFunction() {
            console.log(this.name); // windowsName
        }
    }
    fn()

eg5. 箭头函数

    var name = "windowsName";
    var a = {
        name: "Cherry",
        func1: function () {
            console.log(this.name)
        },
        func2: function () {
            
            setTimeout(() => {
                this.func1()
            }, 100);
        }
    };
    a.func2() // Cherry

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值