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指向吗的更多相关文章

  1. javascript中几种this指向问题

    javascript中几种this指向问题   首先必须要说的是,this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象. (1).作为函数名调用   函数作为全局对象调用,this指向 ...

  2. JavaScript面向对象基础与this指向问题

      前  言           我们的程序语言经历了从"面向机器".到"面向过程".再到"面向对象"的一个过程.而JavaScript是一 ...

  3. 改变javascript函数内部this指针指向的三种方法

    在查了大量的资料后,我总结了下面的三条规则,这三条规则,已经可以解决目前我所遇到的所有问题.规则0:函数本身是一个特殊类型,大多数时候,可以认为是一个变量. function a() { alert( ...

  4. javaScript 真经 小感 this 指向

    编程世界只存在两种基本元素:一个是数据.一个是代码. (能写代码算入门,能处理复杂场景或者数据算合格,能不变应万变是不朽) 最流行的编程思想莫过于面向对象编程,因为面向对象编程思想把数据和代码结合成统 ...

  5. JavaScript严格模式下this指向

    一般认为:严格模式下this不允许指向全局对象.是函数体是否处于严格模式! 如:http://www.ruanyifeng.com/blog/2013/01/javascript_strict_mod ...

  6. JavaScript的this指针到底指向哪?

    编程过程中,着实十分困扰this的指向性,经过查阅一番资料,终于搞清楚了,在这里总结一下,全文分为以下三个部分: 什么是this指针? this指针指向哪里? 何时使用this? 一 什么是this指 ...

  7. JavaScript中函数的this指向!

    JavaScript的this的指向问题! 这是我自己敲的, 报错! <button>点击查看绑定事件的this指向!</button> <script> // 函 ...

  8. JavaScript中的this对象指向理解

    在JavaScript中,this不是固定不变的,它的指向取决于上下文环境,一般的,认为this指向使用它时所在的对象.主要有以下几类指向: 在方法中,this 表示该方法所属的对象. 如果单独使用, ...

  9. javascript中,对于this指向的浅见

    # this的指向在函数创建的时候确定不了.只有在执行的时候,才可以确定. ## 1 . 这里的this指向window window.fn(); 所以this.user是undefined func ...

随机推荐

  1. OldTrafford after 102 days

    THE RED GO MARCHING ON   One Team One Love Through the highs and the lows   One hundred and two long ...

  2. web3.js支持SimpleChain跨链调用

    SimpleChain的跨链协议已经对外开放很久了,很多应用也已经慢慢支持Simplechain的跨链.最近社区开发者web3.js中集成了Simplechain的跨链接口,开发者只需用npm安装包文 ...

  3. 「期望」「洛谷P1297」单选错位

    题目 题目描述 gx和lc去参加noip初赛,其中有一种题型叫单项选择题,顾名思义,只有一个选项是正确答案.试卷上共有n道单选题,第i道单选题有ai个选项,这ai个选项编号是1,2,3,-,ai,每个 ...

  4. hdu 4352 XHXJ's LIS 数位DP+最长上升子序列

    题目描述 #define xhxj (Xin Hang senior sister(学姐))If you do not know xhxj, then carefully reading the en ...

  5. CSS 的层叠上下文是什么

    层叠上下文是 HTML 中的一个三维的概念,每个层叠上下文中都有一套元素的层叠排列顺序.页面根元素天生具有层叠上下文,所以整个页面处于一个“层叠结界”中. 层叠上下文的创建: 页面根元素:html z ...

  6. Alink漫谈(十) :线性回归实现 之 数据预处理

    Alink漫谈(十) :线性回归实现 之 数据预处理 目录 Alink漫谈(十) :线性回归实现 之 数据预处理 0x00 摘要 0x01 概念 1.1 线性回归 1.2 优化模型 1.3 损失函数& ...

  7. JavaScript学习 Ⅰ

    一. JavaScript的使用 <script>标签 在HTML中,JavaScript代码必须位于<script>与</script>标签之间. 实例: < ...

  8. 数据可视化基础专题(十三):Matplotlib 基础(五)常用图表(三)环形图、热力图、直方图

    环形图 环形图其实是另一种饼图,使用的还是上面的 pie() 这个方法,这里只需要设置一下参数 wedgeprops 即可. 例子一: import matplotlib.pyplot as plt ...

  9. celery 基础教程(五):守护进程

    一 守护进程方式启动 https://blog.csdn.net/p571912102/article/details/82735052 文件目录如下 . ├── config.py ├── main ...

  10. Ethical Hacking - NETWORK PENETRATION TESTING(5)

    Deauthentication Attacks Theory This attack is used to disconnect any device from any network within ...