例子先行:
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. Block的引用循环问题 (ARC & non-ARC)

    2010年WWDC发布iOS4时Apple对Objective-C进行了一次重要的升级:支持Block.说到底这东西就是闭包,其他高级语音例如Java和C++已有支持,第一次使用Block感觉满简单好 ...

  2. Google maps library的使用

    公司的项目中用到了google地图API, 使用Google API开发就会用到Marker, 用来在google 地图上标注位置 但是google marker使用过程中也有个问题,就是如果在goo ...

  3. ECSHOP在线手册之布局参考图-首页 index.dwt

        A.logo替换 1,设置方法 后台商店设置里,上传logo就行,注意logo的名称必须是logo.gif 2,代码相关 page_header.lbi 中 <a href=" ...

  4. Android开发之有效获取状态栏(StatusBar)高度

    获取状态栏高度 一.传统方式:有时获取为0,解决方法看  二 1 2 3 4 代码 Rect frame = new Rect(); getWindow().getDecorView().getWin ...

  5. HDU4279(2012年天津网络赛---数论分析题)

    题目:Number 题意: 给出一个f(x),表示不大于x的正整数里,不整除x且跟x有大于1的公约数的数的个数.定义F(x),为不大于x的正整数里,满足f(x)的值为奇数的数的个数.题目就是求这个F( ...

  6. 通过VMName获取VM IP

    PS3.0下通过测试,PS2.0下没有 networkAdapters 这个属性: $vmname = "22012r2" $v = get-vm |where {$_.name ...

  7. PowerShell中的数学计算

    Double类型和float都属于浮点类型,精度不高.而Decimal属于高精度

  8. ThinkPHP3.1快速入门(12)自动验证

    自动验证是ThinkPHP模型层提供的一种数据验证方法,可以在使用create创建数据对象的时候自动进行数据验证. 验证规则 数据验证可以进行数据类型.业务规则.安全判断等方面的验证操作.数据验证有两 ...

  9. 【Android开发经验】使用Ant批量打包Android应用全然指南

    本文章由Socks完毕.博客地址:http://blog.csdn.net/zhaokaiqiang1992 转载请说明. 折腾了一下午.百度了一下午,最终实现了使用Ant对Android应用的批量打 ...

  10. iOS 10 升级后无法真机测试 Could not find Developer Disk Image

    ---2016年9月20日更新 iOS 升级到10之后,你会发现无法进行真机测试了.这种情况我在iOS 8.4 .9.3更新的时候也遇到过.原因是Xcode 的DeviceSupport里面缺少了iO ...