this的指向
在js中的this的指向。经常说谁调用他就指向谁下面我们来分析下
var obj = {
fun: function () { console.log(this.a) },
a: 1
};
var fun = obj.fun;
var a= 2;
obj.fun() // 1
fun() // 2
由图片我们可以看出 虽然执行的是同一个函数但是结果却不同。造成这种情况的原因,就在于函数体内部使用了this,
obj.fun()执行的时候this指向的obj。所以输出的是1
直接调用foo()相当于window.fun() this指向的是window,所以输出的是2。但是实际上this指的是函数运行时所在的环境。对于obj.fun()来说,fun运行在obj环境,所以this指向obj;对于fun()来说,foo运行在全局环境,所以this指向全局环境。所以,两者的运行结果不一样。
有以上可得:
- this是在函数体内部 自动生成 的一个对象,只能在 函数体内部 使用。
- this就是函数运行时所在的 环境对象。
那么问题来了为什么会这样,函数的运行环境到底是怎么决定的?
js 在储存应用类型的时候储存的是有个地址。就好比
var obj = { a: 5 };
先在内存里面,生成一个对象{ a: 5 },然后把这个对象的内存地址赋值给变量obj。
变量obj中储存一个地址。后面如果要读取obj.a,引擎先从obj拿到内存地址,然后再从该地址读出原始的对象,返回它的a属性。
上面的的结构是很清晰的,问题在于属性的值可能是一个函数。就好比如
var obj = { foo: function () {} };
这时,引擎会将函数单独保存在内存中,然后再将函数的地址赋值给a。但是函数是一个独立的值,所以它可以在不同的环境(上下文)执行。就如同上面的 fun()可以在全局中执行也可以在其他环境中执行
当函数引用当前环境的其他变量。
就如同上面代码中的在全局中指向
fun()
上面代码中,函数体里面使用了变量a。该变量由运行环境提供。
由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。
但是有时候我们向this指向其他的执行环境就需要用到 call()、bind()、apply();
改变this指向的三中方法
call()、bind()、apply()都是js预定义的方法,可以挂载对象或某个属性,来改变函数内部的this指向,他们最大的区别就是传入参数的方式不太一样。
改变fn函数的this指向为obj对象。
let obj = {
name: "张三",
age: 13
}
function fn(height,weight) {
console.log(this);
console.log(`姓名:${this.name},年龄:${this.age},身高:${height},体重:${weight}`);
}
call()方法
call()参数:
- 重定义this指向为某个对象或属性。
- 传入的实参,可以传入多个,逗号隔开。例如:fn.call(obj,“180cm”,“50kg”);
fn.call(obj,"180cm","50kg");
apply()
- 重定义this指向为某个对象或属性。
- 传入的实参,是以数组的方式传入,数组内的每一个都对应着一个形参。例如:fn.apply(obj,[“180cm”,“50kg”]);
fn.apply(obj,["180cm","50kg"]);
达到的效果和call一样。
bind()
bind()方法绑定后会返回一个函数。 参数基本和call是一样的
bind()参数:
- 重定义this指向为某个对象或属性。
- 传入的实参,可以传入多个,逗号隔开。例如:fn.bind(obj,“180cm”,“50kg”);
var objfun = fn.bind(obj,"180cm","50kg");
objfun();
三种改变this指向的比较
相同点:
- call()、bind()、apply()都是重定向function中的this指向,并且都可以进行传递参数。
不同点:
- call() 传入的参数以逗号隔开,可以是任何类型。并且在call()的同时函数会执行。
- apply() 传入参数的时候必须是一个数组,数组内的每一个值都对应着一个形参,并且在apply()的同时函数会执行
- bind() 传入的参数以逗号隔开,可以是任何类型。在bind()的同时不会执行函数,但是会返回一个函数。
。