JavaScript学习随笔--函数执行上下文

JavaScript中的函数执行上下文

  • 函数上下文就是函数中的this
  • 函数中的this指向和函数的定义位置、执行位置无关
  • 函数中this的指向只取决于函数的调用方式

所有的JavaScript函数执行时都是有上下文的。那么,什么是函数的执行上下文呢?简单说来就是函数中this所指向的对象。我们来看下面这段代码:

function f1(){
    console.log(this.name);
}

这段代码最终会打印出什么来呢?也就是这里的this指向谁呢?在定义的时候我们并不知道,函数最终的调用方式决定this的指向。一般说来JavaScript里有4中调用函数的方式:
- 直接调用
- 作为对象的方法调用
- 通过函数对象的apply或者call方法调用
- 通过关键词new调用

以直接调用方式执行的函数上下文指向全局对象。一般情况下全局对象中并不存在一个name的属性,所以this.name的值是undefined。

function f1(){
    console.log(this.name);
}
f1();
//console should print "undefined"

作为对象方法调用的函数上下文指向对象本身。例如,我们在这里我们定义了一个对象o,o有一个属性name,还有一个方法f1,这个方法f1指向前面定义的全局函数f1。那么这里的this将指向对象o,this.name的值就是o.name的值,所以打印出来的是o.name的值。

function f1(){
    console.log(this.name);
}
var o ={
    name:"qwan",
    f1:f1
};
o.f1();
//console will print "qwan"

通过函数对象的apply或者call方法调用函数可以用apply的第一个参数显式指定上下文。在这里我们定义了两个对象o和p,都只包含一个name属性。我们可以看到,f1.apply(o)调用时this指向o,this.name的值就是o.name,参数换成p最后打印的就是p.name的值。

function f1(){
    console.log(this.name);
}
var o ={
    name:"qwan"
};
var p ={
    name:"bob"
};
f1.apply(o);
//console will print "qwan"
f1.apply(p);
//console will print "bob"

函数的最后一种调用方式是通过关键词new调用,通过new调用的函数就是我们通常说的构造函数,在调用之前会自动创建一个空对象,这个空对象就是函数的上下文,调用完后返回这个对象。

function f1(name){
    this.name = name;
    console.log(this.name);
}
var o = new f1("qwan");//will print "qwan" here
console.log(o.name);// also print "qwan" here
var p = new f2("bob");//will print "bob" here
console.log(p.name);//also print "bob" here

在这我们能清楚的看到函数不同的调用方式对函数上下文的影响。那么函数定义的位置会不会影响函数执行时的上下文呢?答案是否定的,JavaScript中函数的上下文只取决于函数的调用方式,与函数定义的位置无关。上面例子中使用的是全局域中定义的函数,我们还可以将函数定义在对象中。请看下面的例子:

var o ={
    name:"qwan",
    f:function(){console.log(this.name);}//函数定义成对象的方法
};
var p ={
    name:"bob"
};
o.f.apply(o);
//console will print "qwan"
o.f.apply(p);
//console will print "bob"

至此我们基本搞清楚了JavaScript中函数上下文的指向问题。总结一下,直接调用函数时其上下文是全局对象;作为对象方法调用时其上下文是对象本身;使用函数对象的apply或者call方法调用函数其上下文是apply或者call方法的第一个参数;通过new关键词调用的函数上下文是自动创建的一个空对象,调用完之后返回上下文对象。

接下来,我们来研究一个实例,代码如下:

function invoke(f){
    f();
}
var o ={
    name:"qwan",
    f:function(){console.log(this.name);}//函数定义成对象的方法
};
invoke(o.f);

在这个例子中最终打印出来的this.name的值会是什么呢? 应该是”undefined”,你答对了吗?因为在这里f是直接调用的,所以this指向全局对象。但是实际使用过程中,程序员的意图往往是希望f调用的时候使用的上下文是o,这又如何实现呢?请看下面的代码:

function invoke(f){
    f();
}
function hitch(o,f){
    return function(){
        return f.apply(o);
    };
}
var o ={
    name:"qwan",
    f:function(){console.log(this.name);}//函数定义成对象的方法
};
invoke(hitch(o,o.f));

hitch函数返回了一个函数,这个函数体里显式设置了函数o.f的执行上下文为o,所以最后打印的值是o.name。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值