例子先行:
var myObject={
foo:"bar",
func:function(){
var self=this;
console.log("outerfunc:this.foo="+this.foo);
console.log("outerfunc:self.foo="+self.foo);
(function(){
console.log("innerfunc:this.foo="+this.foo);
console.log("innerfunc:self.foo="+self.foo);
}());
}
}
myObject.func();

输出结果为:

对于上面的结果,第一个和第二个我是不意外的,第三和第四个竟然不知道为什么,虽然之前总结了作用域和闭包,但是关于this的问题还是搞不清楚,所以准备写一篇总结来强化一下自己的这些基本概念。

一、函数调用的形式

就像孔乙己回字有四种写法,javascript中的函数调用同样也有四种方式,分别如下:

1.作为一个函数进行的调用

2.作为一个对象的方法进行的调用

3.作为构造器进行的调用

4.通过apply()、call()函数进行的调用

在进行C#或者java编程的时候,我们都知道如果函数在声明的时候有定义了参数,那么函数再被调用的时候,也要相应的传入参数,否则不能正确使用,javascript和上面一些高级语言不一样的是,它的参数数目可以和声明时候不一样,参数不够undefined代替,参数多了那么就会截断。

有趣的是:javascript中所有的函数调用都会传递两个隐式参数:arguments和this。

arguments 参数不是我想要详细说的,所以这个就不展开学习了,它的特点是有length属性、能够被遍历、有点像数组,但是却不是数组。

this 参数也挺有意思,在四种调用中,传入的this还不一样

二、函数调用过程中传入的this

Javascript中的this和C#、java中的还是有区别的,C#中this代表的意义可能是实例本身,而javascript只用函数作为方法的时候才和这个代表的意义差不多,其他三种可能会不一样,javascript中的this依赖于函数的调用,而C#等则是依赖于函数的声明,this也称为函数的上下文

1)作为函数进行调用

function sum(){
alert(this);
return1+2+3;
} alert(sum());

结果:

上面的代码就是最常用函数调用方式,这种方式就是作为函数进行的调用,从上图还可以看到函数内部的this参数就是全局的对象window对象。

2)作为对象的方法进行调用

var obj={
  name:"大橙子"
}; function sum(){
  alert(this);
  alert(this.name);
  return 1+2+3; } obj.func=sum;
obj.func();

结果:

和函数方式调用不同的是,这种调用方式传递的this参数就是这个对象本身,这就和C#当中一个方法所属的对象在该方法体内部可以用this形式进行引用差不多。

上面的代码也说明了这点,正因为this在sum中被当作了obj来使用,才能打印出name这个属性

3)作为构造器进行调用

对于构造器,要先理解javascript中的new操作是干嘛的.之前总结一篇关于原型的文章,里面的配图也提到了constructor这个东西,但是没有深入研究,正好这次把这部分补全。

先看如下的例子:

var person = function(){

this.name = "大橙子";

this.age = 26;

this.say = function(){

return "Hello!";

}

}

var p = new person();

console.log(p.name);

console.log(p.age);

console.log(p.say());

结果:

[Web浏览器] "大橙子"

[Web浏览器] "26"

[Web浏览器] "Hello!"

上面是一个简单的使用构造器进行实例化对象的例子,就像上次原型的文章中所画的图一样,这个过程也可以这样做:

这个过程就是用new创建一个实例的过程,new的过程是这样的:

(1)新建一个对象p=new Object();

(2)设置原型链p.__proto__=person.prototype;

(3)让person中的this指向p,执行person的函数体。

(4)判断person的返回值类型:

如果是值类型,就丢弃它,还是返回p。

如果是引用类型,就返回这个引用类型的对象,替换掉p。

对于(3)和(4)不是很好理解:

(3)的理解是:就像例子中的代码,我虽然在person中写了this,但是不调用person,我就不知道this是谁,所以new的第三步帮我做了这个,让this指向了p,执行此时执行person函数体的时候,就相当于使用p这个对象,this.name就好比p.name……

(4)理解:

①我这个例子的当中,person函数体内没有返回值,所以返回的是undefined,undefined是值类型,所以就舍弃了,返回p

②如果返回值写成了 return this。因为第三步this是p的引用,所以这样写也是返回的p

③如果是其他的引用类型,就用其他来代替p返回。

上面的过程也就是使用构造器的方式来调用函数。

4)使用apply()和call()来进行调用

上面的三种方式在进行使用的时候,可以说他们的this都是被固定化了的,window对象、调用对象,或者新创建的对象实例,但是如果想要自由指定函数的上下文,就要使用apply()或者call()函数。

例如:

function sum(){

var result = 0;

for(var n=0;n<arguments.length;n++){

result += arguments[n];

}

this.result = result;

}

var obj1 ={};

var obj2 ={};

sum.apply(obj1,[1,2,3]);

sum.call(obj2,4,5,6);

console.log(obj1.result);

console.log(obj2.result);

结果:

[Web浏览器] "6"

[Web浏览器] "15"

这个例子当作我们可以看到,作为sum函数的第一个参数的obj1和obj2,分别被当成了sum函数内的this上下文。

apply()和call()的区别在于,一个接受参数的数组,另一个是分离开的。

以后可以使用这样的方式,指定this上下文,比较灵活。

再看new操作
var p = new person( );
就相当于:
var p = {};
person.apply(p);
p.__proto__ = person.prototype;

总结:函数的调用以及它和this上下文的关系,可以简单描述为如下:

①作为函数调用,this相当于window

②作为对象的方法,this相当于对象

③作为构造器调用,this相当于实例化的对象

④apply()和call()调用,this可以进行指定。

回头再看看上面的例子:

调用函数方式是作为对象的方法,所以第一个和第二个输出的myObject的foo,也就是bar

第三个

(function(){
console.log("innerfunc:this.foo="+this.foo);
console.log("innerfunc:self.foo="+self.foo);
}());

关于这个为什么输出的是undefined,原因是this在这里是window对象的引用,为什么可以看看下面的连接

https://www.zhihu.com/question/21958425

第四个:

上面是一个自调用函数,我的理解是首先javascript的作用域是函数级别的,所以上面的自调用函数和外层function不是一个作用域,但是他们在一条链上,所以第四个self.foo的时候,因为自身的作用域内没有self这个对象,就向上找,上层有,于是就输出上层的self.foo也就是bar。

Javascript中函数调用和this的关系的更多相关文章

  1. JavaScript中__proto__与prototype的关系

    一.所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function) 1 2 3 4 5 6 7 8 9 Number.__proto__ ...

  2. javascript中的对象之间继承关系

    相信每个学习过其他语言的同学再去学习JavaScript时就会感觉到诸多的不适应,这真是一个颠覆我们以前的编程思想的一门语言,先不要说它的各种数据类型以及表达式的不同了,最让我们头疼,恐怕就是面向对象 ...

  3. JavaScript中__proto__与prototype的关系(转)

    一.所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function) 1 2 3 4 5 6 7 8 9 Number.__proto__ ...

  4. 转:JavaScript中函数与对象的关系

    来自:http://www.nowamagic.net/javascript/js_RelationOfFunctionAndObject.php 在ajax兴起以前,很多人写JavaScript可以 ...

  5. JavaScript中各种对象之间的关系

    上图: 此外,补充一下图中用到的概念: 1.内置(Build-in)对象与原生(Naitve)对象的区别在于:前者总是在引擎初始化阶段就被创建好的对象,是后者的一个子集:而后者包括了一些在运行过程中动 ...

  6. 理解JavaScript中BOM和DOM的关系

    JavaScript 有三部分构成,ECMAScript,DOM和BOM,根据宿主(浏览器)的不同,具体的表现形式也不尽相同,IE和其他的浏览器风格迥异.对象是JavaScript最重要的API,包含 ...

  7. JavaScript中typeof、toString、instanceof、constructor与in

    JavaScript 是一种弱类型或者说动态语言.这意味着你不用提前声明变量的类型,在程序运行过程中,类型会被自动确定. 这也意味着你可以使用同一个变量保存不同类型的数据. 最新的 ECMAScrip ...

  8. JavaScript中的逗号运算符

    JavaScript逗号运算符  阅读本文的前提,明确表达式.短语.运算符.运算数这几个概念. 所谓表达式,就是一个JavaScript的“短语”,JavaScript解释器可以计算它,从而生成一个值 ...

  9. 【JavaScript中typeof、toString、instanceof、constructor与in】

    JavaScript中typeof.toString.instanceof.constructor与in JavaScript 是一种弱类型或者说动态语言.这意味着你不用提前声明变量的类型,在程序运行 ...

随机推荐

  1. Web缓存基础:术语、HTTP报头和缓存策略

    简介 对于您的站点的访问者来说,智能化的内容缓存是提高用户体验最有效的方式之一.缓存,或者对之前的请求的临时存储,是HTTP协议实现中最核心的内容分发策略之一.分发路径中的组件均可以缓存内容来加速后续 ...

  2. A Tour of Go Exercise: HTTP Handlers

    Implement the following types and define ServeHTTP methods on them. Register them to handle specific ...

  3. python 偏函数

    functools.partial可以设置默认参数和关键字参数的默认值 Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function).要注意,这里的 ...

  4. hdoj 2098 分拆素数和

    分拆素数和 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  5. Emgu CV 高斯建模

    Codeprivate void button1_Click(object sender, EventArgs e) { Emgu.CV.Capture cap = new Capture(" ...

  6. 清空session的方法

    清空session的方法,常用来注销的时候清空所有的session. 方法一: Enumeration e=session.getAttributeNames(); while(e.hasMoreEl ...

  7. Android AndroidManifest 清单文件以及权限具体解释

    每一个Android应用都须要一个名为AndroidManifest.xml的程序清单文件,这个清单文件名称是固定的而且放在每一个Android应用的根文件夹下.它定义了该应用对于Android系统来 ...

  8. mysqldump when doing LOCK TABLES问题

    今天打出表结构和数据遇到问题. mysqldump -udbuser -p dbname > dbname.sql 保存信息为: when doing LOCK TABLES 解决方法: mys ...

  9. Cocos2d-x 3.x 资料整理

     cocos2d-x-3.0rc0新project的分辨率设置和控制台输出信息 http://kome2000.blog.51cto.com/969562/1379704 Cocos2d-x 3. ...

  10. PCL 点云数据操作 OpenCV遍历数据

    1.对于点云类型实例cloud,对其第i个点进行赋值操作,使用cloud.point[i].x 和 cloud.point[i].y 和cloud.point[i].z 分别对其XYZ坐标赋值. cl ...