this 在 JavaScript 开发中占有相当重要的地位,不过很多人对this这个东西都感觉到琢磨不透。要真正理解JavaScript的函数机制,就非常有必要搞清楚this到底是怎么回事。

函数调用方式不同,this 含义也跟着不同。JavaScript语言中有七种调用函数方式:
 
第一种:调用方法
var obj = {
    method: function() { alert(this === obj); }
}
obj.method();
上面这行obj.method()显然method是作为方法被调用,这种情况下,函数体中的this绑定的就是method的宿主对象,也就是obj。
从这种调用方式我们得出第一定律:
第一定律:以方法方式调用函数,this则绑定宿主对象。

第二种:调用全局函数
var method = function(){alert(this === window);}
method();
上面这个函数是个全局函数。我们知道,全局变量或函数都相当于window对象的属性。也就是说,上面这句实际上等同于下面这句:
window.method = function(){alert(this === window);}
window.method();
既然这样,那么这里 this 绑定到 window 对象就显而易见,很容易理解了。相当于方法调用模式的一个特例,并不违背第一定律。

第三种:全局函数内调用内部函数

var m_ext = function() {
    alert(this === window);
    var m_inner = function() {
        alert(this === window);
    }
    m_inner();
}
m_ext();
执行上面这段代码,你会惊讶的发现,两个布尔表达式的值都是真。也就是说子函数孙函数,只要是以函数的方式调用,this 就铁了心绑定 window 对象了。从这种调用方式我们得出第二定律:
第二定律:不论子函数孙函数,只要是以函数的方式调用,this 就铁了心绑定 window 对象。

第四种:方法内调用内部函数

var obj = {};
obj.method = function() {
    alert(this === obj);
    var m_inner = function() {
        alert(this === window);
    }
    m_inner();
}
obj.method();
执行上面这段代码,第一个this绑定到obj你不奇怪,第二个this绑定到window其实也不奇怪。它仍然遵守第二定律,也就是不论子函数孙函数,只要是以函数的方式调用,this 就铁了心绑定 window 对象。

第五种:作为构造函数调用

function Person(name, age){
    this.name = name;
    this.age = age;
}
var john = new Person('John', 38);
alert(JSON.stringify(john));
你会说,哇,这很眼熟。生成某个类的新对象啊。Javascript就是这么另类,函数确实可以这么调。
这次弹出的是这样一个字符串:{"name":"John","age":38}。哇,这次我明明没在函数定义里写return 语句,它却主动返回了一个对象给我。没错,即便你在函数定义里return某个东西,它也不会理你。(注意:如果你return一个function就会有惊喜,不信你试试看)。从这种调用方式我们得出第三定律:
第三定律:如果在一个函数本身没有返回值,在其前面加上 new 调用,就会创建一个连接到该函数 prototype 属性的新对象,再把 this 绑定到该对象,然后执行该函数,最后返回该对象。如果该函数有返回值,且返回值为字符串/数字/布尔值等简单对象的话,该返回值会被丢弃。但如果该函数的返回值为对象,函数或者数组等复杂对象的话,该函数则会返回该返回值,抛弃this绑定的对象。据我测试,如果返回值是一个函数时,该函数会返回undefined。我暂时还不知道为什么会这样。

第六种:用函数对象的apply方法调用

var my_concat = function(stra, strb){
    alert(this);
    return stra + '' + strb;
}
var param = ['hello', ' world']
alert(my_concat.apply('bullshit', param));

你一定注意了,在这里 this 绑定的是apply方法的第一个参数 'bullshit'。从这里我们得出第四定律:
第四定律:用方法的apply/call方法调用方法时,this 则被绑定到apply/call方法的第一个参数。
想谁就是谁,嗯,吴妈也行。JavaScript的程序员们好幸福哦。

第七种:用函数对象的call方法调用
var my_concat = function(stra, strb){
    alert(this);
    return stra + '' + strb;
}
alert(my_concat.call('bullshit', 'hello',' world'));

对啦,你或许会多问一句,apply 的第二个参数有什么规定?call方法和apply又有什么不同?嗯 ,真是勤学好问,我就再啰嗦一下说说apply和call:

apply 和 call 的区别:

apply要求第二个参数必须是数组。否则就会报 TypeError: second argument to Function.prototype.apply must be an array. 而call则没这么严格啦,第二个参数要什么类型?随意啦,还可以有第三个第四个第五个第六个....啦。

我想我说的够清楚了。感谢《JavaScript The Good Parts》和《JavaScript Definitive Guide》,要不然我也弄不明白呢!

JavaScript中七种函数调用方式及对应 this 的含义的更多相关文章

  1. JavaScript中七种数据类型·中·一

    Standing on Shoulders of Giants; 说到JavaScript里的类型很容易就让人想起 42和"42",分别是string型和number型,但是他们可 ...

  2. JavaScript中四种不同的属性检测方式比较

    JavaScript中四种不同的属性检测方式比较 1. 用in方法 var o = {x:1}; "x" in o; //true "y" in o; //fa ...

  3. JavaScript中定义类的方式详解

    本文实例讲述了JavaScript中定义类的方式.分享给大家供大家参考,具体如下: Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的exte ...

  4. 【转】SVG与HTML、JavaScript的三种调用方式

    原文:https://www.cnblogs.com/guohu/p/5085045.html SVG与HTML.JavaScript的三种调用方式 一.在HTMl中访问SVG的DOM 1 2 3 4 ...

  5. JavaScript中两种类型的全局对象/函数【转】

    Snandy Stop, thinking is the essence of progress. JavaScript中两种类型的全局对象/函数 这里所说的JavaScript指浏览器环境中的包括宿 ...

  6. javascript中几种this指向问题

    javascript中几种this指向问题   首先必须要说的是,this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象. (1).作为函数名调用   函数作为全局对象调用,this指向 ...

  7. c++ --> c++中四种类型转换方式

    c++中四种类型转换方式   c风格转换的格式很简单(TYPE)EXPRESSION,但是c风格的类型转换有不少缺点, 1)它可以在任意类型之间转换,比如你可以把一个指向const对象的指针转换成指向 ...

  8. [js]javascript中4种异步

    javascript中4种异步: 1.ajax 2.定时器 3.事件绑定 4,回调 定时器 //顺序执行 /* var s = 0; for (var i = 0; i < 10000; i++ ...

  9. JavaScript的3种继承方式

    JavaScript的继承方式有多种,这里列举3种,分别是原型继承.类继承以及混合继承. 1.原型继承 优点:既继承了父类的模板,又继承了父类的原型对象: 缺点:不是子类实例传参,而是需要通过父类实例 ...

随机推荐

  1. 第一次写Makefile文件

    test.c文件内容 #include <stdio.h> int main(int argc, char const *argv[]) { printf("hahahah\n& ...

  2. xHtml+css学习笔记

    第一节 xHTML规范 *文档方面 -必须定义文档类型(DTD)和名字控件 *标签方面 -所有标签均要小写.关闭.合理嵌套.ID不能重复 -标签属性药有值,属性值要加印号且不能为空 -图片一定要加上a ...

  3. SDUT 2352 Run Length Encoding

    点我看题目 题意 :将给定的字符串编码,编码的规则根据两条,1.如果字符串里有连续相等的字符,就变为两个字符,一个是这些连续相同的字符的个数,另一个是这个字符,但是如果数量超过了9个,那就输出9再输出 ...

  4. 【HDU 5370】 Tree Maker(卡特兰数+dp)

    Tree Maker Problem Description Tree Lover loves trees crazily. One day he invents an interesting gam ...

  5. 只看Delphi自带的WnAPI帮助似乎不够

    比如,MessageBox在Delphi自带帮助的参数说明中,对其第四个参数的MB_类型说明只有最常见的6种类型,这么多年搞得我天经地义的以为MessageBox就是这么简单.今天看了一位前辈写的老代 ...

  6. TDBGrideh表头自动排序设置

    自动显示标题行的升降排序标志符(▽降序△升序)并做相应排序DBGridEh组件可以在标题行单元格中显示小三角形升.降排序标志符图片,在运行时可点击标题行,图片自动切换并做相应排序. 具体属性设置如下: ...

  7. $response->decoded_content; 和$response->content; 乱码问题

    centos6.5:/root/podinns/lib#cat t1.pl use LWP::UserAgent; use HTTP::Date qw(time2iso str2time time2i ...

  8. 匿名hash

    [root@oadb test]# cat a1.pl use Data::Dumper; my @a=qw/1 3 5 7 9/; push @b ,{@a}; print Dumper(@b); ...

  9. 转:二十七、Java图形化界面设计——容器(JFrame)

    转:http://blog.csdn.net/liujun13579/article/details/7756729 二十七.Java图形化界面设计——容器(JFrame) 程序是为了方便用户使用的, ...

  10. React入门1

    React教程 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <t ...