this是什么,取决于被呼叫的呼叫地点。

昨天有提到说,呼叫函式时候会传递隐含参数:arguments和this并讲解了arguments,今天我们就来探讨this吧!

什么是this

我们都会呼叫函式来使用,但有想过到底是从哪里呼叫到这个函式吗?

this通常被称作函式背景空间(function context),也就是说透过this我们可以知道到底是由谁呼叫这支函式(yjssqsdg)。我们无法在一开始定义它,只有函式呼叫时候才能确定。

函式的呼叫有四种方式:

作为函式呼叫

作为一个(物件)的方法呼叫

作为一个建构式函式呼叫

透过apply、call呼叫

apply、call我们会在下一篇中介绍,我们今天主要介绍上述三种呼叫方式。

作为函式呼叫

function funA(){

console.log(this);

}

funA();//Window

由于是在全局环境呼叫funA,所以这时候的this就会是window。

所以很多刚学习的人都会遇到这个问题:

function funA(){

this.count ++;

}

funA.count = 0;

funA();

console.log(funA.count);//0

明明已经声明funA.count = 0怎么会没有加到呢?这就是因为funA是被全局环境也就是window呼叫,所以this并不是你预期的funA。

那到底加了谁的count呢?你可以尝试印出window.count会发现是NaN,是因为你赋予window一个count属性且一开始没有给定初始值,

所以会变成undefined+ 1 = NaN。

或许你认为这样就可以解决问题:

function funA(val){

val.count ++;

}

var dart = {

count:0

};

funA(dart);

console.log(dart.count);//1

但这样你只是在逃避this这个问题而已!!

要透过this解决方案有两种,一个是等下提到的作为物件的方法;一个是明天会说的call及apply。

作为方法呼叫

函式可以透过写在物件里面去呼叫,这个呼叫方式称作作为方法(method),相信大家都知道,但你知道在这时候的this是什么吗?

var obj = {

funA:function(){

console.log(this);

console.log(this===obj);

}

}

obj.funA();

//{funA:ƒ}

//true

可以看到这时候的this是obj物件,也是是说我们是透过obj去呼叫的。

但是要注意一个小地方:

function funA(){

console.log(this);

console.log(this===obj);

}

var obj = {

a:funA

}

funA();

//Window

//false

虽然你认为我已经让obj参照funA了,但是当你直接执行funA时,还是由全局环境去呼叫,这也呼应了我们开头所说的「我们无法在一开始定义它,只有函式呼叫时候才能确定」。

我们可以利用作为方法呼叫来解决作为函式呼叫的问题:

function funA(){

this.count ++;

}

var obj = {

count:0,

sum:funA

};

obj.sum();

console.log(obj.count);//1

作为建构式呼叫

建构式的函式声明就跟任何函式一样,也可以用声明和表达来建立新物件。

要作为建构式函式来呼叫函式,必须要在函式呼叫前加上new:

function myConstructor(){

this.count = 0;

this.sum = function(){

return this.count ++

}

}

var a = new myConstructor();

a.sum();

console.log(a.count);

也许有人会觉得,这跟作为方法呼叫很像,那用物件去写就好何必这么麻烦还要学建构式,用奇怪的new去呼叫函式。

这边就来说明一下,使用new呼叫函式时,会发生什么事:

建立一个新物件。

此物件被当成this参数传递给建构式,因此成为建构式的函式背景空间(swrebar)。

回传新建立的物件。

如果我们今天需要两个相同的物件,如果用作为物件方法呼叫的话就必须建立两个不同的物件,否则会参照到同样的物件并修改。

但是建构式就不需要,因为每一个都是一个新的物件:

function myConstructor(){

this.count = 0;

this.sum = function(){

return this.count ++

}

}

var a = new myConstructor();

var b = new myConstructor();

a.sum();

console.log(b.count);//0

以上就是this的基本三种呼叫方式,若有错误及参考资料未附上劳请留言。

明天我们会介绍this的稍微进阶应用call及apply。

参考资料:

忍者JavaScript开发技巧探秘

你所不知道的JS - this

彻底理解js中this的指向,不必硬背。

学JS的心路历程 -函式(三)this的更多相关文章

  1. 学JS的心路历程-函式(二)arguments

    参数(argument)与函式参数(parameter) 在讨论函式时,很多人都会把这两个搞混,我自己也不例外. 虽然讲错别人也听得懂,但是我们还是要搞清楚这两个的定义到底是什么! 参数是当我们呼叫函 ...

  2. 学JS的心路历程-函式(六)其余参数及预设参数

    今天我们要来介绍ES6新增的其余参数及预设参数! 其余参数rest parameter …numbers可以让我们表示不确定数量的参数,并将其视为一个数组: function getVal(…numb ...

  3. 学JS的心路历程-函式(五)箭头函式

    箭头函式arrow function 为了能够以更简短的方式建立函式,ES6变推出了箭头函式. 用说明的可能会不太懂,我们先拿之前的数组排序例子来看: var arr = [2,1,6,12,3,77 ...

  4. 学JS的心路历程-函式(四)apply、call

    从上一篇可以知道,不同的函式呼叫会造成this的不同,但我们能不能在呼叫时候明确指定呢? 当然可以.会有这个想法是因为往往在执行某支函式时想要用回呼函式(mizumisushi),但发现this总是显 ...

  5. 学JS的心路历程-Promise(三)

    今天我们来说then一些特殊情况以及Promise.all()与Promise.race(). 我们都知道函式作为参数传入时,可以参照的方式传入,也能传入时执行拿回传值作使用: function us ...

  6. 学习JS的心路历程-函式(一)

    前几天有间单提到该如何声明函式及在Hositing中会发生什么事,但是函式的奥妙不仅于此. 身为一个使用JS的工程师,我们一定要熟悉函式到比恋人还熟! 这几天将会把函式逐一扒开跟各位一起探讨其中的奥妙 ...

  7. 学JS的心路历程-JS支持面向对象?(一)

    昨天在看Prototype看到JS支持面向对象,被前辈问到说那什么是面向对象?JS是面向对象语言吗? 便开始了一连串艰辛爬文过程,今天就来看一下两者有什么差异吧(rgwyjc)! 首先面向对象有三大特 ...

  8. 学JS的心路历程-物件与原型(三)

    昨天有说明到函式与建构式的原型,及指定建构式函式原型为另一个建构式函式,但其实这会造成复写constructor的问题. 复写constructor的问题(vmwork) 我们昨天有提到「建构式函式可 ...

  9. 学JS的心路历程-闭包closure

    闭包是是纯函式语言的一个特性,也是JS的一个关键性的特色,虽然不了解也能开发程序,但我们不是这种人对吧? 闭包不仅可以减少某些高阶功能的代码数量和复杂度,并且可以让我们做到原本无法做的复杂功能.听到这 ...

随机推荐

  1. 闭包 -> 函数的嵌套

    内层函数对外层函数中的变量的使用 好处: 1. 保护变量不被侵害 2. 让一个变量常驻内存 如何通过代码查看一个闭包 __closure__: 有东西就是闭包. 没东西就不是闭包 # 闭包的优点: # ...

  2. Tomcat 之session 持久化2

    通过前文 Tomcat 之session 持久化1 ,我们已经大概了解了这么个机制.但是我没能详细展开其底层的原理. 这篇文章,我想稍微深入一点点,再继续聊一聊其底层. Tomcat 之session ...

  3. linux常用命令以及快捷键

    find命令查找某些文件并将其拷贝到指定目录 [root@host lib]# find -name "*hbase*.jar" |xargs -i cp {}  /root/aa ...

  4. 原生JavaScript实现新手引导效果(第二个玩具)

    慕课地址https://www.imooc.com/video/169 预览效果: <!DOCTYPE html> <html> <head> <meta c ...

  5. electron 项目的搭建方式,借助 node 和 npm

    1,首先确定安装了 node 和 npm 2,创建一个文件夹,如 aa 3,CMD 命令进入到 aa,用 npm 命令初始化一个项目 4, npm -init 根据提示完成配置 5,安装 electr ...

  6. springMVC源码学习地址

    springmvc工作原理以及源码分析(基于spring3.1.0) 感谢作者  宏愿, 在此记录下,以便学习 SpringMVC源码分析(1):分析DispatcherServlet.doDispa ...

  7. oracle PL/SQL的介绍

    转自:http://blog.sina.com.cn/s/blog_4c302f060101i4o1.html 一 PL/SQL的介绍 1 PL/SQL是什么? PL/SQL(procedural l ...

  8. 在ls命令中使用通配符

    通配符比较简单.我们已经知道通配符常常是在shell终端中用来匹配文件名的,今天来看一下在ls命令中使用通配符的例子. 用法:ls [选项]... [文件]... ls本身也有很多的选项,我们今天不看 ...

  9. msimg32.lib不用为绝对路径发愁

    msimg32.lib不用为绝对路径发愁 以前是每个工程添加bcb绝对路径下的 D:\Program Files (x86)\Borland\CBuilder6\Lib\Psdk\msimg32.li ...

  10. DOS 格式化日期时间输出

    if "%date:~5,2%" lss "10" (set mm=0%date:~6,1%) else (set mm=%date:~5,2%)if &quo ...