this指向全解析

定义

this实质上是函数内部的执行期的上下文指向

this只有在执行期才能明确指向,换言之,函数的执行条件的环境决定了this的指向

要点

普通函数的this指向window(非严格模式)

普通函数的this——严格模式下undefined

对象的函数中的this指向调用函数的对象实例

构造函数的this指向实例化对象

原型的this指向实例化对象

定时器中的this指向window

事件处理函数中的this指向触发事件的目标对象

普通函数的this——非严格模式下指向window

function test(){
	this.a = 1; // window.a = 1 相当于全局
	console.log(this);
	console.log(this.a);
}
test()
// 1

普通函数的this——严格模式下undefined

var a = 1;
function test(){
	'use strict';
	console.log(this);
	console.log(this.a);
}
test()
// error 严格模式下

对象方法中的this——指向调用函数的对象

var obj = {
	a: 1,
	test: function(){
		console.log(this);
		console.log(this.a)
	}
}
// {a: 1, test: f}
// 1
function(a){
	this.a = a;
	console.log(this.a);
	// return undefined
}
console.log(test(1).a) // undefined

不写返回值,相当于返回undefined

function test(a){
	this.a = a;
	console.log(this.a); // 1
	console.log(window.a); // 1
}
test(1)
// 普通函数中,this相当于window

构造函数中的this——指向调用该构造函数的实例

function Test(a){
	this.a = a;
	console.log(this.a)
	console.log(window.a)
}
var t1 = new Test(1)
// 1
// undefined 

原型的this——指向实例化对象

// 原型上的this依然指向实例化对象
function Test(a){
	this.a = a;
}
Test.prototype.sayHi = function(){
	console.log(this.a)
}
var test = new Test(1);
test.sayHi(); // 1

定时器函数setTimeout setInterval 中的this——指向window

如果没有特殊指向,setInterval和setTimeout的回调函数中this的指向都是window。
这是因为JS的定时器方法是定义在window下的。

1.在外部函数中将this存为一个变量,回调函数中使用该变量,而不是直接使用this

var name = 'window';
  var obj = {
      name: 'obj',
      fn: function () {
          var that = this;
          var timer = null;
          clearInterval(timer);
          timer = setInterval(function () {
              console.log(that.name);   //obj
         }, 1000)
     }
 }

2.箭头函数没有自己的this,用的是外面一层的this

var name = 'window';

var obj = { name: 'obj',
fn: function () {undefined
   var timer = null;
   clearInterval(timer);
   timer = setInterval( () => {
   undefined
   console.log(this.name);   //obj
}, 1000)
}
}

3.bind改变指向

 let time=setInterval(function () {
          this.second--; 
          if(this.second==0){
            location.replace("./login.html")
          }
}.bind(this),1000,1000)

事件处理函数中的this——指向绑定该函数的DOM元素

var btn = document.querySelector('#btn')
btn.onclick = function(){
	console.log(this);
	this.innerHTML = '加载中...';
	this.disabled = true;
	
	setTimeout(function(){
		console.log(this);
		this.innerHTML = '点击';
		this.disabled = false;
		// 出现问题,这里的this是window
		// 解决方式1:箭头函数没有自己的this,用的是外面一层的this
		// 解决方式2:bind
		// 解决方式3:在外面定义一个变量var a = this,把a传进去
	})
}
// <button id="btn">点击</button>

解决方式2

var btn = document.querySelector('#btn')
btn.onclick = function(){
	console.log(this);
	this.innerHTML = '加载中...';
	this.disabled = true;
	
    setTimeout(function(){
    console.log(this);
    this.innerHTML = '点击';
    this.disabled = true;
    }.bind(this), 2000) // bind的this指向的是绑定该事件处理函数的dom元素
}

补充bind函数用法

call/apply bind都可以用来改变this指向

call(context, arg1, arg2, arg3)
apply(context, [arg1, arg2, arg3])
bind(context, arg1, arg2, arg3)

区别是call/apply会立即执行,bind返回一个新的函数(this的指向改变)而不立即执行

var newFn = function test(a, b, c){
	this最开始指向window,但由于使用了bind,因此this指向context
}.bind(context)

模块中的this——指向

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button>点击</button>
  <script>
    ;(function () {
      function Test(a, b){
        // 构造函数中的this指向实例化对象
        this.oBtn = document.querySelector('button');
        this.a = a;
        this.b = b;
        this.init()
      }
      Test.prototype = {
        init: function(){
          // 原型中的this指向实例化对象
          this.bindEvent();
        },
        bindEvent: function(){
          this.oBtn.addEventListener('click', this.plus.bind(this), false) 
          // plus前面的this:事件处理函数中的this指向绑定该事件的DOM
          // bind里面的this:处在原型的作用域中,所以也指向实例化对象
          // 通过这种方式,click时能执行plus方法,否则会在oBtn下面找plus方法
        }, 
        plus: function(){
          console.log(this.a + this.b);
        }
      }
      window.Test = Test; // 将Test抛到全局
    })()
    new Test(1, 2)
  </script>
</body>
</html>

补充call/apply

function Test1(a, b){
	this.a = a;
	this.b = b;
	console.log(this.a, this.b)
}
function Test2(a, b, c, d){
	this.a = a;
	this.b = b;
	Test1.call(this, a, b); // call把Test1的this改成Test2的this
	this.c = c;
	this.d = d;
}
var test2 = new Test2(1, 2, 3, 4)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值