学JS的心路历程 -函式(三)this
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的更多相关文章
- 学JS的心路历程-函式(二)arguments
参数(argument)与函式参数(parameter) 在讨论函式时,很多人都会把这两个搞混,我自己也不例外. 虽然讲错别人也听得懂,但是我们还是要搞清楚这两个的定义到底是什么! 参数是当我们呼叫函 ...
- 学JS的心路历程-函式(六)其余参数及预设参数
今天我们要来介绍ES6新增的其余参数及预设参数! 其余参数rest parameter …numbers可以让我们表示不确定数量的参数,并将其视为一个数组: function getVal(…numb ...
- 学JS的心路历程-函式(五)箭头函式
箭头函式arrow function 为了能够以更简短的方式建立函式,ES6变推出了箭头函式. 用说明的可能会不太懂,我们先拿之前的数组排序例子来看: var arr = [2,1,6,12,3,77 ...
- 学JS的心路历程-函式(四)apply、call
从上一篇可以知道,不同的函式呼叫会造成this的不同,但我们能不能在呼叫时候明确指定呢? 当然可以.会有这个想法是因为往往在执行某支函式时想要用回呼函式(mizumisushi),但发现this总是显 ...
- 学JS的心路历程-Promise(三)
今天我们来说then一些特殊情况以及Promise.all()与Promise.race(). 我们都知道函式作为参数传入时,可以参照的方式传入,也能传入时执行拿回传值作使用: function us ...
- 学习JS的心路历程-函式(一)
前几天有间单提到该如何声明函式及在Hositing中会发生什么事,但是函式的奥妙不仅于此. 身为一个使用JS的工程师,我们一定要熟悉函式到比恋人还熟! 这几天将会把函式逐一扒开跟各位一起探讨其中的奥妙 ...
- 学JS的心路历程-JS支持面向对象?(一)
昨天在看Prototype看到JS支持面向对象,被前辈问到说那什么是面向对象?JS是面向对象语言吗? 便开始了一连串艰辛爬文过程,今天就来看一下两者有什么差异吧(rgwyjc)! 首先面向对象有三大特 ...
- 学JS的心路历程-物件与原型(三)
昨天有说明到函式与建构式的原型,及指定建构式函式原型为另一个建构式函式,但其实这会造成复写constructor的问题. 复写constructor的问题(vmwork) 我们昨天有提到「建构式函式可 ...
- 学JS的心路历程-闭包closure
闭包是是纯函式语言的一个特性,也是JS的一个关键性的特色,虽然不了解也能开发程序,但我们不是这种人对吧? 闭包不仅可以减少某些高阶功能的代码数量和复杂度,并且可以让我们做到原本无法做的复杂功能.听到这 ...
随机推荐
- tomcat安全加固和规范
tomcat是一个开源Web服务器,基于Tomcat的Web运行效率高,可以在一般的硬件平台上流畅运行,因此,颇受Web站长的青睐.不过,在默认配置下其存在一定的安全隐患,可被恶意攻击.以下是一些安全 ...
- Solr使用in语法查询
Solr可以用AND.|| 布尔操作符 表示查询的并且, 用OR.&& 布尔操作符 表示或者 用NOT.!.-(排除操作符不能单独与项使用构成查询)表示非 如果要用在查询的时候使用 ...
- TableStore:创建SyncClient+getRow读取一行数据
1.通过控制台或者客户端,在TableStore中新建了实例owlforest,在实例详情中获取到实例访问地址endPoint 2.新建表user,确定主键为userid(Interger)类型,因为 ...
- asp.net 中日期的格式化显示的方法
在Asp.net 中经常使用日期,在不同的场合,对日期的显示方式有不同的要求,为此,自己总结了一些日期格式化的方式,仅供学习参考使用: C#格式化日期时间 DateTime dt = DateTime ...
- 【Jmeter自学】Jmeter作用域(五)
.Jmeter作用域 .Jmeter参数化 .Jmeter的集合点 .jmeter之关联 1.Jmeter作用域 问题: 每个元件作用域 层次结构确认 每个元件执行顺序 配置元件 前置 定时器 Sam ...
- Structs 2 session 学习
后台获取 值类型 request.getSession().setAttribute("username", user.getUserName()); 对象类型 reque ...
- 20165205 2017-2018-2 《Java程序设计》 第二周学习总结
20165205 2017-2018-2 <Java程序设计>第一周学习总结 教材学习内容总结 学习第二章知识(标识符,关键字,数据类型,输入.输出数据和数组) 学习第三章知识(运算符,基 ...
- SQL Server Url Decode函数
)) ) AS BEGIN ), ), ) SET @count = Len(@url) SET @urlReturn = '' WHILE (@i <= @count) BEGIN ) IF ...
- [多线程]线程基础(对象锁、class锁、同步、异步)
synchronized.volatile.ReentrantLock.concurrent 线程安全:当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法) ...
- Win7平台下配置Sublime Text2 的C++编译环境
Sublime Text 是一个跨平台的编辑器,之前在 Mac 上成功配置了 C++ 在 Sublime Text 的编译环境,接下来介绍下载 windows 平台下的环境配置. 1. 首先判断机器上 ...