JS 正确判断this指向,理解call/apply使用

this对象是在运行时,基于函数的执行环境绑定的。指向大致分为四种:
1)对象的方法调用,this = 该对象;
2)普通函数,this  = window;
3)构造器;
4)Function.prototype.call/apply

1、作为对象的方法调用

	var a = 2
	var obj = {
		a: 1,
		getValue: function(){
			console.log(this.a)
		},
		// 箭头函数 改变this指向 this = window
		getArrowValue: () => {
			console.log(this.a)
		}
	}
	// getValue方法是作为obj对象的属性被调用的,this = obj
	obj.getValue() // 1
	obj.getArrowValue() // 2
	// 属于普通函数调用,this = window
	var f1 = obj.getValue
	f1() // 2

如果对象中的方法返回一个匿名函数,涉及到闭包,情况就不一样了。

	var a = 2
	var obj = {
		a: 1,
		getValue: function(){
			return function(){
				console.log(this.a)
			}
		}
	}
	obj.getValue()() // 2
函数被调用时,会创建一个执行环境和相应的作用域链,得到两个变量:this、arguments。
内部函数在搜索这两个变量时,只会搜索到其活动对象为止。

解决这类问题,可以在匿名函数外定义一个变量,把this传给变量,

getValue: function(){
			const self = this
			return function(){
				console.log(self.a)
			}
		}

2、普通函数调用

上述 var f1 = obj.getValue;f1() 属于普通函数调用,this是指向全局对象的。

3、构造器调用

JS没有类,但是可以从构造器中创建对象,使用new运算符,返回对象,通常情况,构造器里的this是
指向返回的这个对象的。

但是,如果构造器显示的返回一个object类型的对象,返回结果会是该对象;

	const MyClass = function() {
		this.name = 'qwe';
		return {
			name: 'asd'
		}
	}
	const obj = new MyClass()
	console.log(obj.name) // asd

4、Function.prototype.call/apply调用

在一个对象的上下文中应用另一个对象的方法;
作用一样,都是动态的改变this的执行,并立即执行函数。是传入参数的形式不同,第一个参数都是指定函数体内this对象的指向。
(A对象调用B对象的方法)
 call是列表:B.call(A, args1,args2)
 apply是数组:B.apply(A, arguments)
	let obj1 = {
		name: 'qwe',
		getName: function() {
			return this.name
		}
	}
	const obj2 = {
		name: 'asd'
	}
	console.log(obj1.getName()) // qwe
	// this指向obj2
	console.log(obj1.getName.call(obj2)) // asd

A.apply(null,[1,2,3]) 第一个参数传null,非严格模式下,函数体内的this会指向全局对象(node:global,浏览器:window)

this.name = 'zxc'
	let obj1 = {
		name: 'qwe',
		getName: function() {
			return this.name
		}
	}
	console.log(obj1.getName()) // qwe
	console.log(obj1.getName.call(null)) // zxc

在这补充一下call和apply的用途

5、箭头函数this指向

箭头函数的this是在定义函数时绑定的,不是在执行过程中绑定的。

简单的说,函数在定义时,this就继承了定义函数的对象。
箭头函数是没有this的,没有构造函数,不能使用arguments

let obj={
    a:222,
    fn:function(){    
        setTimeout(()=>{console.log(this.a)});
    },
    fn1:function(){    
        setTimeout(function(){console.log(this.a)})
    }
};
obj.fn();//222
obj.fn1(); // undefined

fn1() 里的 this 指向 obj ,但传给 setTimeout 的是普通函数, this 指向是 window ,输出 undefined。
fn()传给 setTimeout 的是箭头函数,箭头函数没有 this ,向上层作用域查找到fn。fn的 this 指向 obj ,所以 setTimeout 里面的箭头函数的 this ,指向 obj输出 222 。

eg1:

在事件函数里,有一个内部函数func,在事件函数内部调用func,func体内的this会指向window,而不是我们想要的事件函数的this
(ps:参考了JS设计模式和小红书)

eg2

var name = "big window"
  function test(){
    var name = "this window"
    function fn(){
      console.log(this.name)
    }
    function fn1(){
      console.log(this.name)
    }
    var obj = {
      name: "this object",
      getName: function(fn){
        fn && fn() // 传参调用
        fn1() // 直接调用
        console.log(this.name)
        return function(){
          return this.name
        }
      }
    }
    console.log(obj.getName(fn)())
  }
  test() 
  // big window 
 big window
 this object
 big window
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值