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. C# 基于内容电影推荐项目(一)

    从今天起,我将制作一个电影推荐项目,在此写下博客,记录每天的成果. 其实,从我发布 C# 爬取猫眼电影数据 这篇博客后, 我就已经开始制作电影推荐项目了,今天写下这篇博客,也是因为项目进度已经完成50 ...

  2. MongoDB 逻辑还原工具mongorestore

    mongorestore是官方提供用来还原导入由mongodump导出生成的二进制备份文件的工具,通常与mongodump配合使用,关于mongodump工具的使用可以参考另一篇博文:MongoDB ...

  3. 【题解】p1809 过河问题

    原题传送门 题目分析 现有n个人在东岸,要过河去西岸.开始东岸有一艘船,船最多可承载2人,过河时间以耗时最长的人所需时间为准. 给定n个人的过河时间a,求所有人从东岸到西岸所需的最短时间. 当\(n= ...

  4. 深入理解JVM(③)学习Java的内存模型

    前言 Java内存模型(Java Memory Model)用来屏蔽各种硬件和操作系统的内存访问差异,这使得Java能够变得非常灵活而不用考虑各系统间的兼容性等问题.定义Java内存模型并非一件容易的 ...

  5. MYSQL 之 JDBC(八):增删改查(六)ReflectionUtils

    这里在网上找了一份ReflectionUtils package com.litian.jdbc; /** * @author: Li Tian * @contact: litian_cup@163. ...

  6. MYSQL 之 JDBC(二): 数据库连接(二)通过DriverManager获取数据库连接

    通过DriverManager获取数据库连接 修改一下配置文件 driver=com.mysql.cj.jdbc.Driver jdbcUrl=jdbc:mysql://localhost:3306/ ...

  7. SQLAlchemy03 /外键、连表关系

    SQLAlchemy03 /外键.连表关系 目录 SQLAlchemy03 /外键.连表关系 1.外键 2.ORM关系以及一对多 3.一对一的关系 4.多对多的关系 5.ORM层面的删除数据 6.OR ...

  8. Python面向对象01 /面向对象初识、面向对象结构、类、self、实例化对象

    Python面向对象01 /面向对象初识.面向对象结构.类.self.实例化对象 目录 Python面向对象01 /面向对象初识.面向对象结构.类.self.实例化对象 1. 面向对象初识 2. 面向 ...

  9. 网课神器之obs-studio的安装使用

    obs-studio 首先,下载obs-studio安装文件,然后点击安装. 建议安装完后直接跳过配置,然后进入文件-设置-通用-系统托盘-勾选"总是最小化到系统托盘,而不是任务栏" ...

  10. Apache 阿帕奇 配置运行环境

    阿帕奇 Apache 是一个很常用的服务器环境. 安装阿帕奇后,需要对配置文件进行修改,才能使用. https.conf是阿帕奇的配置文件,地址在 阿帕奇的安装目录\conf\httpd.conf 默 ...