JavaScript 你真的了解this指向吗
JavaScript 你真的了解this指向吗
前言
终于开始写this
指向了,相信这对很多JavaScript
的学习者来说是一个非常恐怖的环节,个人认为也算是JavaScript
中最难理解的一个知识点,this
非常的方便但是在你不熟悉它的情况下可能会出现很多坑。
本篇文章将带你充分了解this
指向,用最精炼简短的语句阐述不同情况下的this
指向。
详解this指向
window对象
window
是一个全局的对象,里面存了很多方法。
当我们使用var
进行变量命名时,变量名会存入到window
对象中,以及当我们使用标准函数定义方法时函数名也会存入window
对象中。
<script>
var username = "云崖";
function show(){
console.log("show...");
};
console.log(window.username); // 云崖
window.show(); // show...
</script>
全局环境
在全局环境中,this
的指向就是window
对象。
但是我们一般不这么用。
<script>
var username = "云崖";
function show(){
console.log("show...");
};
console.log(this.username); // 云崖
this.show(); // show...
// 依旧可以执行,代表全局环境下this就是window对象
// 如果你不相信,可以打印它看看。
console.log(this); // Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
</script>
普通函数
非严格模式下,普通函数中this
的指向为window
对象。
<script>
// "use strict"; // 在非严格模式下,普通函数中this的指向是window对象
function show() {
console.log("show...");
console.log(this); // window
};
show()
</script>
但是在严格模式下,普通函数中this
指向为undefined
。
<script>
"use strict"; // 在严格模式下,普通函数中this指向为undefined
function show() {
console.log("show...");
console.log(this); // undefined
};
show()
</script>
构造函数
当一个函数能被new
时,该函数被称之为构造函数。
一般构造函数中包含属性与方法,函数中的上下文指向到实例对象。
在构造函数中的this
一般指向为当前对象。对于其方法而言this
指向同样为当前对象。
你可以这么认为,在用
Function
定义类时,类中的方法指向当前类。这样是不是好理解多了?
<script>
"use strict";
function User(username) { // 在没有class语法出现之前,这种构造函数我们通常会将它当做类来看待。
this.username = username; // 可以称之为类属性
console.log(this); // User {username: "云崖"} 代表指向当前对象
this.show = function () { // 可以称之为类方法
console.log(this.username); // 云崖
console.log(this); // {username: "云崖", show: ƒ} 代表指向当前对象
}
}
let user = new User("云崖");
user.show();
</script>
对象字面量
在对象中的this
指向即为当前对象,同样的在对象中的函数(方法)this
指向也是当前对象本身。
这与构造函数如出一辙。
<script>
"use strict";
let obj = {
username:"云崖", // 最终的key都会转为String类型,但是Symbol类型不会转换。
show:function(){ // 这里也可以将show称作为方法,而username即为属性
console.log(this.username); // 云崖
console.log(this); // {username: "云崖", show: ƒ}
},
}
obj.show();
</script>
方法中的普通函数
首先聊方法中的普通函数之前,要先知道什么情况下的函数常被称之为方法。
结合本章前面介绍的内容,以下环境中的函数将被称之为方法:
在构造函数中的函数可以将其称之为方法
在对象中的字面量函数也可以将其称之为方法
那么,在方法中的普通函数即是这样的:
在构造函数中的函数中的函数可以称其为方法中的普通函数
在对象中的字面量函数中的函数也可以将其称为方法中的普通函数
有点绕哈,看代码你就懂了。
在方法中的普通函数的this
执行费严格模式下为window
对象,严格模式下为undefined
。
值得一提的是,对于大多数开发者而言,这么嵌套的情况很少使用。
<script>
"use strict";
function User(username) {
this.username = username;
this.show = function () { // 方法
console.log(this.username); // 云崖
console.log(this); // {username: "云崖", show: ƒ} 代表指向当前对象
function inner() { // 普通函数
console.log(this); // 严格模式:undefined,非严格模式:window
};
inner(); // 在方法中定义一个函数并调用
}
}
let user = new User("云崖");
user.show();
</script>
<script>
"use strict";
let obj = {
username:"云崖", // 最终的key都会转为String类型,但是Symbol类型不会转换。
show:function(){ // 方法
console.log(this.username); // 云崖
console.log(this); // {username: "云崖", show: ƒ}
function inner(){ // 普通函数
console.log(this); // 严格模式:undefined,非严格模式:window
};
inner(); // 在方法中定义一个函数并调用
},
}
obj.show();
</script>
方法中的普通函数改变this指向
那么,怎么改变方法中普通函数的this
指向呢?
非常简单。使用一个常量将方法的this
赋值并传递给其中的普通即可。
<script>
"use strict";
function User(username) {
this.username = username;
this.show = function () { // 方法
let self = this; // 这个this指向的当前对象,即User
function inner(self) { // 普通函数
console.log(self); // 在方法内的普通函数中使用self即可
};
inner(self); // 我们将self传递进去
}
}
let user = new User("云崖");
user.show();
</script>
<script>
"use strict";
let obj = {
username: "云崖", // 最终的key都会转为String类型,但是Symbol类型不会转换。
show: function () { // 方法
let self = this; // 这个this指向的当前对象,即obj
function inner(self) { // 普通函数
console.log(self); // 在方法内的普通函数中使用self即可
};
inner(self); // 在方法中定义一个函数并调用
},
}
obj.show();
</script>
方法中的箭头函数
箭头函数这玩意儿没有this
指向,你可以理解为它始终会与外层定义自己的函数共同使用一个this
,在大多数情况下是会如此,但是少部分情况会除外,比如在事件的回调函数中,这个在下面会有举例。
在方法中的箭头函数this
指向始终会与定义自己的函数共同使用一个this
。
<script>
"use strict";
function User(username) {
this.username = username;
this.show = function () { // 方法
console.log(this); // 指向 User
let inner = () => console.log(this); // 箭头函数,与定义自己的外层指向同一this,即User
inner(); // 在方法中定义一个函数并调用
}
}
let user = new User("云崖");
user.show();
</script>
事件普通函数
事件函数是指某一动作方式后所调用的回调函数,如果是普通函数那么this
指向即为事件源本身。
<script>
"use strict";
let div = document.querySelector("div");
div.onclick = function (event) {
console.log(event); // 事件
console.log(this); // div标签,即为事件源本身,DOM对象
}
</script>
事件箭头函数
事件的回调函数如果箭头函数,那么this
指向即为window
,一句话,向上找,看在哪个环境下定义了这个箭头函数。
所以我们尽量不要去用箭头函数作为事件的回调函数。
<script>
"use strict";
let div = document.querySelector("div");
// 由于是在全局定义的,所以此时的this即为window,如果是在方法中定义的事件箭头函数则this指向
// 就不是window了
div.onclick = event => {
console.log(event); // 事件
console.log(this); // Window
}
</script>
事件箭头函数获取事件源
如果想在事件箭头函数中获取事件源,那就不使用window
了。用event
参数中的一个叫target
的属性即可找到事件源。
<script>
"use strict";
let div = document.querySelector("div");
div.onclick = event => {
console.log(event.target); // 事件源DOM对象
console.log(this); // Window
}
</script>
改变this指向
call方法
通过call()
方法,让原本函数的this
发生改变,如下实例我们可以在user
函数中使用this
去给对象obj
进行添加属性。
参数1:新的
this
指向对象其他参数:函数中本来的传递值
特点:立即执行
<script>
"use strict";
function user(name,age) {
this.name = name;
this.age = age;
console.log(this);
};
let obj = {};
user.call(obj,"云崖",18);
console.log(obj.name); // 云崖
console.log(obj.age); //
</script>
apply方法
与call()
方法唯一不同的地方在于参数传递,其他都一样。
参数1:新的
this
指向对象参数2:函数中本来的传递值,请使用数组进行传递。
特点:立即执行
<script>
"use strict";
function user(name,age) {
this.name = name;
this.age = age;
console.log(this);
};
let obj = {};
user.apply(obj,["云崖",18]);
console.log(obj.name); // 云崖
console.log(obj.age); //
</script>
bind方法
该方法最大的特点是具有复制特性而非立即执行,对于函数的参数传递可以有多种。
但是我这里只介绍一种。
参数传递:使用
bind()
方法时传递一个this
指向即可特性:会返回一个新的函数。
<script>
"use strict";
function user(name,age) {
this.name = name;
this.age = age;
console.log(this);
};
let obj = {};
// 可以这么理解,使用bind()方法的第一步,告诉this指向谁,第二步,复制出新函数,第三步,新函数的this已经改变。其他地方与原函数相同。
let new_func = user.bind(obj); // obj传递进去,返回一个新函数,该新函数与user函数除了this指向不一样其他均相同。
new_func("云崖",18)
console.log(obj.name); // 云崖
console.log(obj.age); //
</script>
总结
window对象 | 当前对象 | 上级this指向 | 事件源DOM对象 | undefined | |
---|---|---|---|---|---|
全局环境(不在函数中) | √ | ||||
普通函数 | 非严格模式:√ | 严格模式:√ | |||
构造函数 | √ | ||||
对象 | √ | ||||
构造函数中的方法 | √ | ||||
对象中的字面量方法 | √ | ||||
构造函数中的方法中的普通函数 | 非严格模式:√ | 严格模式:√ | |||
对象中的字面量方法中的普通函数 | 非严格模式:√ | 严格模式:√ | |||
构造函数中的方法中的箭头函数 | √ | √ | |||
对象中的字面量方法中的箭头函数 | √ | √ | |||
事件普通函数 | √ | ||||
事件箭头函数 | 大概率是√,主要看上层的this指向 | √ |
后言
本人也是一名JavaScript
的初学者,很多地方可能阐述不到位描述不清楚欢迎留言。
最后我想吐槽的是,怎么啥都是对象啊!!很难区分啊!!实在不适应将{k1:v1,k2:v2}
的这种叫对象,真的太不习惯了!!!
JavaScript 你真的了解this指向吗的更多相关文章
- javascript中几种this指向问题
javascript中几种this指向问题 首先必须要说的是,this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象. (1).作为函数名调用 函数作为全局对象调用,this指向 ...
- JavaScript面向对象基础与this指向问题
前 言 我们的程序语言经历了从"面向机器".到"面向过程".再到"面向对象"的一个过程.而JavaScript是一 ...
- 改变javascript函数内部this指针指向的三种方法
在查了大量的资料后,我总结了下面的三条规则,这三条规则,已经可以解决目前我所遇到的所有问题.规则0:函数本身是一个特殊类型,大多数时候,可以认为是一个变量. function a() { alert( ...
- javaScript 真经 小感 this 指向
编程世界只存在两种基本元素:一个是数据.一个是代码. (能写代码算入门,能处理复杂场景或者数据算合格,能不变应万变是不朽) 最流行的编程思想莫过于面向对象编程,因为面向对象编程思想把数据和代码结合成统 ...
- JavaScript严格模式下this指向
一般认为:严格模式下this不允许指向全局对象.是函数体是否处于严格模式! 如:http://www.ruanyifeng.com/blog/2013/01/javascript_strict_mod ...
- JavaScript的this指针到底指向哪?
编程过程中,着实十分困扰this的指向性,经过查阅一番资料,终于搞清楚了,在这里总结一下,全文分为以下三个部分: 什么是this指针? this指针指向哪里? 何时使用this? 一 什么是this指 ...
- JavaScript中函数的this指向!
JavaScript的this的指向问题! 这是我自己敲的, 报错! <button>点击查看绑定事件的this指向!</button> <script> // 函 ...
- JavaScript中的this对象指向理解
在JavaScript中,this不是固定不变的,它的指向取决于上下文环境,一般的,认为this指向使用它时所在的对象.主要有以下几类指向: 在方法中,this 表示该方法所属的对象. 如果单独使用, ...
- javascript中,对于this指向的浅见
# this的指向在函数创建的时候确定不了.只有在执行的时候,才可以确定. ## 1 . 这里的this指向window window.fn(); 所以this.user是undefined func ...
随机推荐
- F5隐写工具使用
0x00 前言 今天在实验吧看到一个图片隐写的题目,用了stegslove和winHex分析一通发现并没有什么有效信息.看了评论区大佬的提示说用到了F5隐写工具,所以百度教程用了一下,发现确实解决 ...
- 使用IDEA创建Spring boot项目,继承mybaits。并进行简单的数据库查询操作
本文讲的是使用IEDA创建Spring boot项目,对于环境安装需要自行准备,如JDK1.8.Maven 3.3.IDEA编译器.Mysql5.7等需事前准备好. 1.创建Spring boot项目 ...
- java IO流 (四) 缓冲流的使用
1.缓冲流涉及到的类: * BufferedInputStream* BufferedOutputStream* BufferedReader* BufferedWriter 2.作用:作用:提供流的 ...
- 爬虫07 /scrapy图片爬取、中间件、selenium在scrapy中的应用、CrawlSpider、分布式、增量式
爬虫07 /scrapy图片爬取.中间件.selenium在scrapy中的应用.CrawlSpider.分布式.增量式 目录 爬虫07 /scrapy图片爬取.中间件.selenium在scrapy ...
- Reface.AppStarter 类型扫描 —— 获得系统中所有的实体类型
类型扫描 是 Reface.AppStarter 提供的最基本.最核心的功能. AutoConfig , ComponentScan 等功能都是基于该功能完成的. 每一个使用 Reface.AppSt ...
- 第十章:Android消息机制
Android的消息机制主要是指Handler的云心机制,Handler的运行需要底层的MessageQueue和Looper支持. Handler是Android消息机制的上层接口. 通过Handl ...
- Ethical Hacking - GAINING ACCESS(24)
CLIENT SIDE ATTACKS - Detecting Trojan manually or using a sandbox Analyzing trojans Check the prope ...
- 资深CIO介绍如何选型OA系统的?
OA办公系统成为企业管理的标配软件,在于可有效加强组织管理能力,提高员工协同效率,助力企业科学决策,合理分配企业资源,提升企业综合实力与市场竞争力.企业OA选型的经验总结来说也就是品牌.技术.产品.服 ...
- python pytest接口自动化框架搭建(一)
1.首先安装pytest pip install pytest 2.编写单测用例 在pytest框架中,有如下约束: 所有的单测文件名都需要满足test_*.py格式或*_test.py格式. 在单测 ...
- 深入浅出Java并发包—CountDownLauch原理分析 (转载)
转载地址:http://yhjhappy234.blog.163.com/blog/static/3163283220135875759265/ CountDownLauch是Java并发包中的一个同 ...