JS中this的使用

**this 只有在执行的时候才能被确认,定义时无法确认。**函数执行时,this总是指向调用该函数的对象(即:判断this所在的函数属于谁)

1、作为对象属性执行

函数有所属对象,则指向所属对象

Var myObject = {
	value: 100
}
myObject.getValue = function () {
	console.log(this.value);
	console.log(this)
	return this.value;
}
console.log(myObject.getValue());

这里的getValue属于对象 myObject,所以this 就指向了 myObject,执行结果:
在这里插入图片描述

var name = '李四'
var person = {
	name: '张三',
	getName () {
		console.log(this.name); // 这个this是啥不知道,因为还没调用
	}
}

person.getName(); // 此时的this为person,作为对象属性执行,输出 张三

2、作为构造函数执行

使用构造器new 一个对象时,this就指向新对象:

function foo (name) {
	this.name = name // 此时的this === {}
}
var f = new foo('张三') // foo {name: "张三"}

3、作为普通函数执行

函数没有所属对象时,就指向全局对象(window或global)

var myObject = {
	value:100;
}
myObject.getValue = function () {
	var foo = function () {
		console.log(this.value);
		console.log(this)
	}
	foo();
	return this.value
}
console.log(myObject.getValue())

在这里,foo属于全局对象,所以foo函数打印的this.value为undefined。
在这里插入图片描述
setTimeout 和 setInterval 也属于全局对象的,所以这两个函数体内的this 是指全局的。

var myObject = {
	value: 100
}
myObject.getValue = function () {
	setTimeout(function () {
		console.log(this.value)
		console.log(this)
	}, 0)
	return this.value
}
console.log(myObject.getValue());

执行结果:

在这里插入图片描述
所以,如果要得到想要的结果,就要这样写:

var myObject = {
	value: 100
}
myObject.getValue = function () {
	let self = this
	setTimeout(function () {
		console.log(self.value)
		console.log(self)
	}, 0)
	return this.value
}
console.log(myObject.getValue());

执行结果如下:

在这里插入图片描述
es6 中箭头函数的妙用(this绑定的是定义时所在的作用域,而不是运行时所在的作用域;箭头函数其实没有自己的this,所以箭头函数内部的this就是外部的this),如下:

var myObject = {
	value: 100
}
myObject.getValue = function () {
	setTimeout(() => {
		console.log(this.value)
		console.log(this)
	}, 0)
	return this.value
}
console.log(myObject.getValue());

执行结果同上。

var name = '李四';
var person = {
	name: '张三',
	getName () {
		console.log(this.name)
	}
}
var per = person.getName();
per();
// 此时输出李四而不是张三,this已经是window了,在全局作用域中定义了name变量,自然输出全局的name
// 而不是person的name

4、setTimeout 中this的指向

function method() {
  alert(this.value);  // 输出 42  第二个this
}
 
function Foo() {
    this.value = 42;
    setTimeout(this.method, 500);  // 这里this指向window   第一个this
}
 
Foo();
var obj = {
  name: 'hutaoer',
  say: function() {
    var self = this;
    setTimeout(function(){
      alert(self);   // 输出 object ,指向obj
      alert(this);   // 第二个this,指向window,我心永恒,从未改变
      alert(self.name)  // 输出 hutaoer
    }, 0)
  }
}
 
obj.say();

一、setTimeout中的延迟执行代码中的this 永远 都指向window

二、setTimeout(this.method, time) 这种形式中的this,即上文中提到的第一个this,是根据上下文来判断的,默认为全局作用域,但不一定总是处于全局下,具体问题具体分析。

三、setTimeout(匿名函数, time)这种形式下,匿名函数中的变量也需要根据上下文来判断,具体问题具体分析。

5、call,apply,bind可以改变this的指向

var p1 = {
  name: '张三',
  getName(age, job) {
    console.log(this.name, age, job);
  }
};
var p2 = {
  name: '李四'
};
p1.getName.call(p2, 18, '前端工程师'); // 输出 李四18前端工程师
p1.getName.apply(p2, [18, '前端工程师']); // 输出 李四18前端工程师
p2.getName = p1.getName.bind(p2);
p2.getName(18, '前端工程师'); // 输出 李四18前端工程师

var myObject = {
	value: 100
}
var foo = function () {
	console.log(this)
	console.log(this.value)
	console.log('...........')
}
foo();
foo.apply(myObject)
foo.call(myObject)
var newFoo = foo.bind(myObject) // bind返回的是一个函数
newFoo();

foo 本来指向全局对象window,但是call,apply 和 bind 将this绑定到了myObject 上,所以,foo里面的this就指向了myObject。执行结果:
在这里插入图片描述
call、bind、apply区别:

call、bind、apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数的差别:
call 的参数是直接放进去的,第二第三第n个参数全都是逗号分隔,直接放到后面 obj.myFun.call(db, '好好', ...., 'string')
apply 的所有参数必须放在一个数组里面传进去 obj.myFun.apply(db, ['好好', ...., 'string'])
bind 除了返回的是函数外,它的参数和 call 一样。
三者的参数不限定是 string 类型,允许是各种类型,包括函数、object等。

记忆技巧

函数调用

JS(ES5)里有三种函数调用的形式:

func(p1, p2)
obj.child.method(p1, p2)
func.call(context, p1, p2)

记住,第三种调用形式才是正常调用形式,其他两种都是语法糖,可以等价的变为call 形式:

func(p1, p2) // 等价于
func.call(undefined, p1, p2)

obj.child.method(p1, p2) // 等价于
obj.child.method.call(obj, p1, p2)

至此,函数调用只有一种形式:我们称此为 [ 转换代码 ]

func.call(context, p1, p2)

这样,this就好解释了。
this就是 call 一个函数时传的 context。

function func () {
	console.log(this)
}
func()

用转换代码转一下

function func () {
	console.log(this)
}
func.call(undefined) // func.call()

所以this 就是undefined,但是浏览器有一条规则:
如果传的context是 null 或 undefined,那么window 对象就是默认的context(严格模式下默认context 是 undefined)

如果希望this 不是 window,

func.call(obj) // this -> obj

obj.child.method(p1, p2)

var obj = {
	foo: function() {
		console.log(this)
	}
}
obj.foo()

转换

obj.foo.call(obj)

所以,this 就是 obj。

实例:

var obj = {
	foo: function() {
		console.log(this)
	}
}
var bar = obj.foo()
obj.foo() // 转换 : obj.foo.call(obj) ,this 就是obj
bar() // 转换:bar.call() ,this 就是 window

[ ] 语法

function fn () {console.log(this)}
var arr = [fn, fn2]
arr[0]()

可以把 arr[0]() 想象成 arr.0(),后者语法错误,但是形式与转换代码里的 obj.child.method(p1, p2) 一致,所以

arr[0]()
假想成 arr.0()
转换 arr.0.call(arr)
所以 this 就是指 arr

箭头函数
实际上箭头函数没有 this,如果在箭头函数里发现了 this,就直接当作箭头函数外的 this 即可。箭头函数内外 this 就是同一个。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值