秒懂 this(带你撸平this)
本文讲述只针对浏览器环境。
一:全局执行
console.log(this); // Window
可以看出在全局作用域中 this 指向当前的全局对象 Window。
二:函数中执行
1. 非严格模式中
function func () {
   console.log(this);
}
func();
// Window
2. 严格模式中
"use strict";
function func () {
   console.log(this);
}
func();
// undefined
三:作为对象的方法调用
当一个函数被当作一个对象的方法调用的时候,this 指向当前的对象 obj:
var obj = {
   name: 'kk',
   func: function () {
       console.log(this.name);
   }
}
obj.func();
// kk
如果把对象的方法赋值给一个变量,调用该方法时,this 指向 Window:
var obj = {
   name: 'kk',
   func: function () {
       console.log(this);
   }
}
var test = obj.func;
test();
// Window
四:作为一个构造函数使用
在 JS 中,为了实现类,我们需要定义一些构造函数,在调用一个构造函数的时候加上 new 这个关键字:
function Person (name) {
   this.name = name;
   console.log(this);
}
var p1 = new Person('kk');
// Person
此时,this 指向这个构造函数调用的时候实例化出来的对象。
当然了,构造函数其实也是一个函数,若将构造函数当做普通函数来调用,this 指向 Window:
function Person (name) {
   this.name = name;
   console.log(this);
}
var p2 = Person('MM');
// Window
五:在定时器中使用
setInterval(function () {
   console.log(this);
}, )
// Window
setTimeout(function () {
   console.log(this);
}, )
// Window
如果没有特殊指向(指向更改请看下方:怎么改变 this 的指向),setInterval 和setTimeout 的回调函数中 this 的指向都是 Window 。这是因为 JS 的定时器方法是定义在 Window 下的。
六:箭头函数
在全局环境中调用:
var func = () => {
   console.log(this);
}
func();
// Window
作为对象的一个函数调用:
var obj = {
   name: 'hh',
   func: function () {
      console.log(this);
   }
}
obj.func();
// obj
var obj = {
   name: 'hh',
   func: () => {
      console.log(this);
   }
}
obj.func();
// Window
不难发现,普通函数作为对象的一个函数被调用,this 指向 obj,箭头函数作为对象的一个函数被调用,this 指向 Window。
特殊情况:结合定时器调用:
var obj = {
   name: 'hh',
   func: function () {
       setTimeout(function () {
           console.log(this);
       }, )
   }
}
obj.func();
// Window
var obj = {
   name: 'hh',
   func: function () {
       setTimeout(() => {
           console.log(this);
       }, )
   }
}
obj.func();
// obj
若在对象的函数中,普通函数作为定时器延时执行的函数调用,this 指向 Window;箭头函数作为定时器延时执行的函数调用, this 指向定义时所在的对象,也就是 func 中的 this,即 obj。
箭头函数中 this 的值取决于该函数外部非箭头函数的 this 的值,且不能通过 call() 、 apply() 和 bind() 方法来改变 this 的值。
七:call、apply、bind
call:
fun.call(thisArg[, arg1[, arg2[, ...]]])
它会立即执行函数,第一个参数是指定执行函数中 this 的上下文,后面的参数是执行函数需要传入的参数。
apply:
fun.apply(thisArg, [argsArray])
它也会立即执行函数,第一个参数是指定执行函数中 this 的上下文,第二个参数是一个数组,是传给执行函数的参数(与 call 的区别)。
bind:
var foo = fun.bind(thisArg[, arg1[, arg2[, ...]]]);
它不会执行函数,而是返回一个新的函数,这个新的函数被指定了 this 的上下文,后面的参数是执行函数需要传入的参数。
我们来看个示例:
function Person(name, age) {
 this.name = name;
 this.age = age;
 console.log(this);
}
var obj = {
 name: 'kk',
 age:
};
Person.call(obj, 'mm', );
// obj,{name: "mm", age: 10}
Person.apply(obj, ['mm', ]);
// obj,{name: "mm", age: 10}
var p1 = Person.bind(obj, 'mm', )
var p2 = new p1();
// Person {name: "mm", age: 10}
在这个示例中,call、apply 和 bind 的 this 都指向了 obj,都能正常运行;call、apply 会立即执行函数,call 和 apply 的区别就在于传递的参数,call 接收多个参数列表,apply 接收一个包含多个参数的数组;bind 不是立即执行函数,它返回一个函数,需要执行 p2 才能返回结果,bind 接收多个参数列表。
应用:怎么改变 this 的指向
为什么讲这个模块呢,为了便于大家更加透彻的理解上面所讲述的 this 指向问题,以及更加彻底的理解 JS 函数中重要的三种方法:call、apply、bind 的使用;并且在实际的项目开发中,我们经常会遇到需要改变 this 指向的情况。
我们来看下都有哪些方法:
1. 使用 es6 的箭头函数
var name = "hh";
var obj = {
   name : "kk"
   func1: function () {
       console.log(this.name)
   },
   func2: function () {
       setTimeout(function () {
           this.func1()
       }, );
   }
};
obj.func2();
// Uncaught TypeError: this.func1 is not a function
这时会报错,因为 setTimeout 里函数的 this 指向 Window,而 Window 对象上是没有 func1 这个函数的。下面我们来修改成箭头函数:
var name = "hh";
var obj = {
   name : "kk",
   func1: function () {
       console.log(this.name)
   },
   func2: function () {
       setTimeout(() => {
           this.func1()
       }, );
   }
};
obj.func2();
// kk
这时候,没有报错,因为箭头函数的 this 的值取决于该函数外部非箭头函数的 this 的值,也就是 func2 的 this 的值, 即 obj。
2. 在函数内部使用 _this = this
var name = "hh";
var obj = {
   name : "kk",
   func1: function () {
       console.log(this.name)
   },
   func2: function () {
       let _this = this;
       setTimeout(function () {
           _this.func1()
       }, );
   }
};
obj.func2();
// kk
此时,func2 也能正常运行。在 func2 中,首先设置 var _this = this,这里的 this 是指向 func2 的对象 obj,为了防止在 func2 中的 setTimeout 被 window 调用而导致的在 setTimeout 中的 this 为 window。我们将 this (指向变量 obj) 赋值给一个变量 _this,这样,在 func2 中我们使用 _this 就是指向对象 obj 了。
3. 使用 call、apply、bind
call:
var name = "hh";
var obj = {
   name : "kk",
   func1: function () {
       console.log(this.name)
   },
   func2: function () {
       setTimeout(function () {
           this.func1()
       }.call(obj), );
   }
};
obj.func2();
// kk
apply:
var name = "hh";
var obj = {
   name : "kk",
   func1: function () {
       console.log(this.name)
   },
   func2: function () {
       setTimeout(function () {
           this.func1()
       }.apply(obj), );
   }
};
obj.func2();
// kk
bind:
var name = "hh";
var obj = {
   name : "kk",
   func1: function () {
       console.log(this.name)
   },
   func2: function () {
       setTimeout(function () {
           this.func1()
       }.bind(obj)(), );
   }
};
obj.func2();
// kk
call、apply、bind 都能改变 this 的上下文对象,所以也没有报错,可以正常执行。
具体原因可看上述第七点,call、apply、bind。
4. new 实例化一个对象
如上:第四点,作为一个构造函数使用
秒懂 this(带你撸平this)的更多相关文章
- 《Mybatis 手撸专栏》第1章:开篇介绍,我要带你撸 Mybatis 啦!
		
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 1. 为甚,撸Mybatis 我就知道,你会忍不住对它下手! 21年带着粉丝伙伴撸了一遍 Sp ...
 - CoordinatorLayout 自定义Behavior并不难,由简到难手把手带你撸三款!
		
先来看看最终的效果~~ 本文同步至博主的私人博客wing的地方酒馆 嗯..一个是头像上移的 另一个是模仿UC浏览器的. (PД`q.)你不是说!有三款的吗,怎么只有两款!!!! 不要急嘛... 说了从 ...
 - 手把手带你撸一把springsecurity框架源码中的认证流程
		
提springsecurity之前,不得不说一下另外一个轻量级的安全框架Shiro,在springboot未出世之前,Shiro可谓是颇有统一J2EE的安全领域的趋势. 有关shiro的技术点 1.s ...
 - 从头带你撸一个Springboot Starter
		
我们知道 SpringBoot 提供了很多的 Starter 用于引用各种封装好的功能: 名称 功能 spring-boot-starter-web 支持 Web 开发,包括 Tomcat 和 spr ...
 - 《Spring 手撸专栏》第 3 章:初显身手,运用设计模式,实现 Bean 的定义、注册、获取
		
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你是否能预见复杂内容的设计问题? 讲道理,无论产品功能是否复杂,都有很大一部分程序员 ...
 - 《Mybatis 手撸专栏》第7章:SQL执行器的定义和实现
		
作者:小傅哥 博客:https://bugstack.cn - <手写Mybatis系列> 一.前言 为什么,要读框架源码? 因为手里的业务工程代码太拉胯了!通常作为业务研发,所开发出来的 ...
 - [iOS UI进阶 - 2.3] 彩票Demo v1.3
		
A.需求 真机调试 "关于”模块 存储开关状态 打电话.发短信 应用评分 打开其他应用 cell 在iOS6 和 iOS7的适配 block的循环引用 屏幕适配 code source: ...
 - 在Android上仿百度贴吧客户端Loading图标小球
		
封面 前言 使用百度贴吧客户端的时候发发现加载的小动画挺有意思的,于是自己动手写写看.想学习自定义View以及自定义动画的小伙伴一定不要错过哦. 读者朋友需要有最基本的canvas绘图功底,比如画笔P ...
 - 炫酷:一句代码实现标题栏、导航栏滑动隐藏。ByeBurger库的使用和实现
		
本文已授权微信公众号:鸿洋(hongyangAndroid)原创首发. 其实上周五的时候已经发过一篇文章.基本实现了底部导航栏隐藏的效果.但是使用起来可能不是很实用.因为之前我实现的方式是继承了系统的 ...
 
随机推荐
- Fiddler修改图片显示
			
培训课讲修改请求值,记录一下操作步骤: 步骤如下: 1. 点击人人网图片另存为到桌面 2. 打开fiddler,找到图片发送的请求(单击图片的链接,点击右边面板的Inspectors.查看ImageV ...
 - java框架之Spring(3)-JDBC模板使用&事务管理
			
下面内容使用到的 jar 包下载 JDBC模板使用 入门 1.导包,如要导入 Spring 的基本开发包.数据库驱动包.Spring 提供的 JDBC 模板包,如下: 2.测试: @Test publ ...
 - 解决跨域问题-jsonp&cors
			
跨域的原因 浏览器的同源策略 同源策略是浏览器上为安全性考虑实施的非常重要的安全策略. 指的是从一个域上加载的脚本不允许访问另外一个域的文档属性. 举个例子:比如一个恶意网站的页面通过iframe嵌入 ...
 - OpenMVG学习笔记
			
OpenMVG 是一个不错的SFM开源算法库,可以实现基于多视图像的稀疏重建. OpenMVG SfM pipelines run as a 4 step process:包含四个基本过程 1. Im ...
 - generatorConfiguration详解
			
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration ...
 - Python requests库如何下载一个图片资源
			
原文地址https://blog.csdn.net/u011541946/article/details/77700074 前面一篇文章介绍了response对象的一些常用API,也已经提到,我们的重 ...
 - CDN和智能DNS原理和应用 (原)
			
CDN是什么? CDN的全称是Content Delivery Network,即内容分发网络. CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡.内容分发.调 ...
 - WxWidgets笔记
			
关于环境变量的配置:解压wxwidgets的压缩包之后要新建名为 WXWIN 的环境变量,变量的值为 解压得到的目录,不知为何要使用此环境变量 编译时使用的命令:mingw32-make -j1 -f ...
 - Practical Lessons from Predicting Clicks on Ads at Facebook
			
ABSTRACT 这篇paper中作者结合GBDT和LR,取得了很好的效果,比单个模型的效果高出3%.随后作者研究了对整体预测系统产生影响的几个因素,发现Feature(能挖掘出用户和广告的历史信息) ...
 - nodejs笔记之初识node
			
1.安装node; node -v //检测node是否安装成功 node可以做什么: 搭建服务器: 读写文件: 连接数据库: 爬虫: node的模块系统: 原生模块(如http,fs); 自定义模 ...