this:执行上下文,this一般存在于函数中,表示当前函数的执行上下文,如果函数没有执行,那么this没有内容,只有函数在执行后this才有绑定。
this执行的位置
- 默认执行:this指向window,严格模式指向undefined
非严格模式下
function fn(){
console.log(this); // window
}
fn();
``
严格模式下
function fn(){
"use strict";
console.log(this); //undefined
}
fn();
- 通过对象执行(通过上下文对象执行,隐式执行):obj.fn():当前的执行对象
下面案例中的this,如果fn直接执行时,this的执行是调用它的fn(),但是创建了一个对象obj,在obj中有一个对象b,通过对象obj.b()执行该函数,那么此时的this就是执行它的直接父级obj对象,所以此时的this的输出就是下面显示的结果。
function fn(){
console.log(typeof this); //object
console.log(this);
var a = 10;
var obj = {
a:20,
b:fn
}
obj.b();
- 显式执行(通过函数的方法bind执行):指定的是谁,就是谁
找回隐式丢失的this,其实就是使用显式执行,强行绑定
通过bind方法强行将this执行window。关于bind方法将在下面详细介绍。
function fn(){
console.log(this);
}
var f = fn.bind(window);
f();
-
使用构造函数执行(通过new执行)
在构造函数或者构造函数原型对象中 this 指向构造函数的实例这里通过构造函数的方式,利用new关键字创建了一个对象实例,将这个this指向这个对象a,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象a中会有user,因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。
function Fn(){
this.user = "小张";
}
var a = new Fn();
console.log(typeof a); //object
console.log(a.user); //小张
注:当this碰到return时
来看看几个例子
function fn()
{
this.user = "小张";
return {};
}
var a = new fn();
console.log(a.user); //undefined
function fn()
{
this.user = "小张";
return 1;
}
var a = new fn();
console.log(a.user); // 小张
function fn()
{
this.user = "小张";
return undefined;
}
var a = new fn;
console.log(a.user); //小张
function fn()
{
this.user = "小张";
return undefined;
}
var a = new fn;
console.log(a); //fn {user: "小张"}
function fn()
{
this.user ="小张";
return null;
}
var a = new fn;
console.log(a.user); //小张
那么这几个例子表示什么意思呢?
如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。
bind()、call()和apply()的关系
-
apply()
使用 apply, 你可以继承其他对象的方法:
在 JavaScript 严格模式下,如果 apply() 方法的第一个参数不是对象,则它将成为被调用函数的所有者(对象)。在“非严格”模式下,它成为全局对象。
注意这里apply()的第一个参数是null,在非严格模式下,第一个参数为null或者undefined时会自动替换为指向全局对象,apply()的第二个参数为数组或类数组。 -
call()
call()是apply()的一颗语法糖,作用和apply()一样,同样可实现继承,唯一的区别就在于call()接收的是参数列表,而apply()则接收参数数组。 -
bind()
bind()的作用与call()和apply()一样,都是可以改变函数运行时上下文,区别是call()和apply()在调用函数之后会立即执行,而bind()方法调用并改变函数运行时上下文后,返回一个新的函数,供我们需要时再调用。
var name="小王",age=17;
var obj={
name:"小张",
objAge:this.age,
myFun:function(fm,t){
console.log(this.name+"年龄"+this.age,"来自"+fm+"去往"+t);
}
};
var db={
name:"小红",
age:36
};
obj.myFun.call(db,"上海","淮南");
obj.myFun.apply(db,["上海","淮南"]);
obj.myFun.bind(db,"上海","淮南")();
obj.myFun.bind(db,["上海","淮南"])();
从上面四个结果不难看出:
call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数差别就来了:
call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面 obj.myFun.call(db,‘成都’, … ,‘string’ )。
apply 的所有参数都必须放在一个数组里面传进去 obj.myFun.apply(db,[‘成都’, …, ‘string’ ])。
bind 除了返回是函数以外,它 的参数和 call 一样。
当然,三者的参数不限定是 string 类型,允许是各种类型,包括函数 、 object 等等!
如何选用
如果不需要关心具体有多少参数被传入函数,选用apply();
如果确定函数可接收多少个参数,并且想一目了然表达形参和实参的对应关系,用call();
如果我们想要将来再调用方法,不需立即得到函数返回结果,则使用bind();
总结
call()、apply()和bind()都是用来改变函数执行时的上下文,可借助它们实现继承;
call()和apply()唯一区别是参数不一样,call()是apply()的语法糖;
bind()是返回一个新函数,供以后调用,而apply()和call()是立即调用。