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

来源:互联网 发布:linux重启命令 reboot 编辑:程序博客网 时间:2024/06/08 01:57

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" hereconsole.log(o.name);// also print "qwan" herevar p = new f2("bob");//will print "bob" hereconsole.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