JavaScript 函数调用和this指针
函数调用和this指针
1. 全局环境的this指针
浏览器全局环境下this指向window对象
console.log(this);
//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
nodejs环境下this指向global对象
2. 函数中的this指针
2.1 全局环境下函数调用
非严格模式this指向window,严格模式除箭头函数外指向undefine
//a.js 非严格模式
function fun1(){console.log(this)}
fun1();//window
(function(){console.log(this)})() //window
var fun2 = ()=>{console.log(this)}
fun2();//window
//b.js 严格模式
'use strict';
function fun1(){console.log(this)}
fun1();//undefined
(function(){console.log(this)})() //undefined
var fun2 = ()=>{console.log(this)}
fun2();//window
2.2 作为对象方法调用
function作为对象属性时,this指针指向对象的实例
var obj1 = {
name: 'a',
func1:function(){console.log(this.name);}
}
obj1.func1();//a
//等同于
function func2(){console.log(this.name);}
var obj2 = {
name: 'b',
funRef:func2
}
obj2.funRef();
2.3 构造函数调用
构造函数调用时,this指针指向函数的实例(function也是对象的一种)
function func3(c){
this.c = c;
console.log(this.c);//c
console.log(this);//func3 {c: "c"}
}
var finst3 = new func3('c');
2.4 同步回调函数
同步回调函数中的this指针服从上面1-3点的规则
function callback()
{
console.log(this.d);//undefined
console.log(this);//window
}
function func4(cb){
cb.d = 'd';
cb();
}
func4(callback);
2.5 异步回调函数
关于JavaScript是单线程执行就不多提了,这里详细分析一下对于异步操作的回调函数中this的指向问题。
提到异步操作就不得不提Event Loop,其详细介绍可以参见阮一峰大神的这篇。
简单来说就是:
- 所有异步函数的执行被放在“任务队列”中由另外一个单独的线程执行。当异步操作有结果时,会通知主线程调用该异步操作的回调函数。
注意:这里就有问题了,当主线程调用异步操作的回调函数时,是以什么环境和作用域来执行的呢?
答案是: 以全局环境和执行回调函数时的作用域链来执行回调函数。
参考以下代码:
setTimeout(function(){
console.log(this);//1秒后输出window
}, 1000);
//再看
var asyncFun1 = {
propA:"a",
synFun:function() {
console.log(this.propA);
console.log(this);
},
asynFun: function(){setTimeout(this.synFun, 1000)}
}
asyncFun1.synFun();//输出依次是
//a
//{propA: "a", synFun: ƒ, asynFun: ƒ}
asyncFun1.asynFun();
//undefined
//window
//再再看
var asyncFun2={
propB:"b",
asynFun:function(){
var c = 'string c';
setTimeout(function(){
console.log(c);
},1000);
}
}
asyncFun2.asynFun();//输出'string c'
注意为什么会输出'string c': 虽然回调函数运行是在全局环境(this指向window),但是在其作用域链中是能够访问到变量c的。
常见的异步操作包括:
- setTimeout/setInterval
- XMLHTTPRequest
- jQuery AJAX(这里的this被处理过并不指向window)
- Fetch
- Promise
关于如何在异步操作的回调函数中使用正确的this指针,往下看。
3. 在异步函数回调中正确使用this指针
通过上面的分析我们知道在异步回调函数中this会指向window,那么我们需要怎么做才能让this指向我们指定的对象呢?
3.1 箭头函数与作用域链
3.1.1 箭头函数定义: (x,y)=>{return x+y;}
- 当参数只有一个时,小括号()可以省略: x=>{return x+1;}
- 当函数体只有一行语句并且该语句结果作为返回值时,{}花括号可以省略: x=>x+1;
var fun1 = (x)=>{return x + 1;}
var fun2 = x=>{return x+1;}
var fun3 = x=>x+1;
//返回值都是2
fun1(1);//2
fun2(1);//2
fun3(1);//2
3.1.2 箭头函数特性: 箭头函数体内没有自己的this指针
那么箭头函数体内的this指针将符合作用域链原则,指向作用域链上最近的this
function fun4() {
setTimeout(() => {
console.log(this.id);
}, 1000);
}
var id = 1;
fun4.call({ id: 2 });//输出为2
fun4();//输出为1
分析如下:
- 如果异步操作的回调函数是普通函数,则其this指向window对象。
- 但箭头函数体内没有this指针,则按作用域链原则,回调函数中的this指针应该为fun4的this指针。
- fun4作为普通函数,在全局环境调用时this指向window对象,所以 fun4();输出为1
- function.call作用在调用函数时,将新的对象替换原有对象。则意味着fun4.call时fun4体内的this指针将指向{ id: 2 },所以输出为2
3.2 闭包和作用域链
接下来看看闭包中的this指针问题
//a.js
function debounce(fn, delay) {
var timer = null;
return function() {
var context = this;
var args = arguments;
//定义context和args,通过作用域链达到保存this指针和arguments的作用
clearTimeout(timer);
timer = setTimeout(function() {
//用apply保证回调函数的this指针不会被异步函数重置为window
fn.apply(context, args);
}, delay);
}
}
//等同于
function debounce(fn, delay) {
var timer = null;
return function() {
clearTimeout(timer);
timer = setTimeout(()=>
{fn.apply(this, arguments) }, delay);
}
}
document.a1 = "2";
var obj1 = {
a1:"1",
fun1:function(){
console.log(this);
console.log(this.a1);
}
}
document.addEventListener('scroll', debounce(obj1.fun1, 2000));
//2秒后输出
//document
//2
//b.js
function debounce(fn, delay) {
var timer = null;
return function() {
clearTimeout(timer);
timer = setTimeout(()=> fn(), delay);
}
}
window.a1 = "3";
document.a1 = "2";
var obj1 = {
a1:"1",
fun1:function(){
console.log(this);
console.log(this.a1);
}
}
document.addEventListener('scroll', debounce(obj1.fun1, 2000));
//2秒后输出
//window
//3
3.3 Call,Apply,Bind
关于这三个函数的对比和作用网上介绍很多,其主要作用为:
使用that替换函数内部this的指针指向为that。
function.call(that, arg1, arg2);
function.apply(that, [arg1, arg2]);
function.bind(that);
//如下
var obj1 = {
a1:"1",
fun1:function(){console.log(this.a1)}
}
var obj2 = {
a1:"2"
}
obj1.fun1();//1
obj1.fun1.call(obj2);//2
var funBind = obj1.fun1.bind(obj2);
funBind();//2
JavaScript 函数调用和this指针的更多相关文章
- 深入认识JavaScript 中的this指针
深入认识JavaScript 中的this指针this指针是面向对象程序设计中的一项重要概念,它表示当前运行的对象.在实现对象的方法时,可以使用this指针来获得该对象自身的引用.和传统意义的面向对象 ...
- JavaScript函数调用规则
1. [代码][JavaScript]代码 JavaScript函数调用规则一 (1)全局函数调用:function makeArray( arg1, arg2 ){ return [t ...
- JavaScript函数调用
1. 调用一个函数将暂停当前函数的执行,传递控制权和参数给新函数. 2. 除了声明时定义的形参,每个函数都有两个附加的参数:this和arguments. 1. this在面向对象编程中很重要,它的值 ...
- 彻底理解javascript中的this指针
http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/ https://www.benn ...
- javascript函数调用的各种方法!!
在JavaScript中一共有下面4种调用方式: (1) 基本函数调用 (2)方法调用 (3)构造器调用 (4)通过call()和apply()进行调用 1. 基本函数调用 普通函数调用模式,如: J ...
- Javascript函数调用的四种模式
一 前言 Javascript一共有四种调用模式:方法调用模式.函数调用模式.构造器调用模式以及apply调用模式.调用模式不同,对应的隐藏参数this值也会不同. 二 方法调用模式 函数作为对象的属 ...
- 由javascript中的this指针所想到的
初次结识 this 指针,是在学 <<C++ Primer Plus>>这本书的时候(这本书勉强读了一二遍,之后转学 html+css+js了,不过这是后话). 依稀记得书中举 ...
- JavaScript 函数调用
JavaScript 函数有 4 种调用方式. 每种方式的不同方式在于 this 的初始化. this 关键字 一般而言,在Javascript中,this指向函数执行时的当前对象. 注意 this ...
- "大哥,割草机借我用一下,我修整一下草坪。" ---- 谈谈this与JavaScript函数调用的不解之缘
在写上一篇有关apply和call的博文时(闲聊JS中的apply和call),起初我还是担心大家理解起来比较困难,因为要理解apply调用方式的前提是,至少先理解在JavaScript中函数调用是什 ...
随机推荐
- golang对不同系统的编译
Golang 支持在一个平台下生成另一个平台可执行程序的交叉编译功能. Mac下编译 # mac编译linux执行文件 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go ...
- 微信小程序:POST请求data数据请求不到
最近开始开发小程序,遇到许多小问题,直奔主题. wx.request()是微信封装的ajax请求方法,也是小程序中ajax唯一的一个方法,被放在了API文档的第一个位置,的确使用率是最高的. 但是wx ...
- CSS效果:不怎么样的登录表单
HTML: <html lang="en"> <head> <meta charset="UTF-8"> <meta ...
- 运维ps语法---》ps、pstree、top、htop、nice、renice、kill、ulimit、w 和 who 和 whoami、pgrep、fg 和 bg、ipcs
Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信 ...
- (原创)Verilog三段式状态机
下面以上图一个简单的FSM说明三段式Verilog状态机范式: `timescale 1ns / 1ps module FSM( clk,rst_n, in1,in2, out1,out2, CS,N ...
- UML作业第三次:分析《书店图书销售管理系统》,绘制类图
一. 类图语法学习小结(类间关系的表示方法) 1.抽象类和接口 我们用关键字abstract或abstract class来定义抽象类(抽象类用斜体显示).也可以使用interface,annotat ...
- ZT 将sublime text的tab改为四个空格
打开Sublime Text3,选择菜单Preferences->Settings-User,打开用户配置文件(据本人理解,Settings-Default是不允许用户自己修改的~而Settin ...
- Python Django install Error
Exception:Traceback (most recent call last): File "/home/djangogirls/myvenv/lib/python3.6/site ...
- 三、后门的编写和 ShellCode 的提取
第三章.后门的编写和 ShellCode 的提取 (一)IP 和 Socket 编程初步 NOTES: 1.Windows 下网络通信编程的几种方式 第一种是基于 NetBIOS 的网络编程,这种方法 ...
- 转发: 探秘Java中的String、StringBuilder以及StringBuffer
原文地址 探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家 ...