JS难点:this 指向

菜园前端
• 阅读 492

原文链接:https://note.noxussj.top/?source=helloworld


this 指向分为两种情况,一种是普通函数中使用的 this,另外一种是箭头函数中的 this。

普通函数

this 指向调用者。

场景 1

function sayHi() {
    console.log(this)
}

sayHi() // window

这里的 this 指向 window,因为 sayHi 的调用者是 window,可是我没有看见有 window 啊,我们要知道 window 一般都是可以省略不写的,同等于 window.sayHi()。

场景 2

const person = {
    sayHi: function () {
        console.log(this)
    }
}

person.sayHi() // person

这里的 this 指向 person,sayHi 是谁调用了? 很明显一看就知道是 person 。

场景 3

const person = {
    sayHi: function () {
        console.log(this)
    }
}

const xiaoming = person.sayHi

xiaoming() // window

这里的 this 指向 window,首先是 person.sayHi 赋值给了 xiaoming,这个时候是还没调用的。那么 xiaoming 就是一个函数了,最后我们执行 window.xiaoming() ,调用者就是 window。

场景 4

class Person {
    constructor() {}

    sayHi() {
        console.log(this)
    }
}

const xiaoming = new Person()

xiaoming.age = 18

xiaoming.sayHi()

构造函数(类)中的 this 也是一样的,sayHi 的调用者是 xiaoming,所以 this 指向它。

场景 5

const div = document.querySelector('.content')

div.onclick = function () {
    console.log(this)
}

div.onclick() // 我们去页面点击元素,实际上就是执行的这行代码

dom 元素添加了点击事件,但是还没执行。当我们执行 div.onclick() 的时候,调用者就是 div ,所以 this 指向它。

箭头函数

这里就不用看谁是调用者了,而是看它定义时所在的环境(作用域)。箭头函数本身不存在 this,所以它的 this 指向上一层作用域所在的对象。

场景 1

const sayHi = () => {
    console.log(this)
}

sayHi() // window

sayHi 是一个箭头函数,本身没有 this,所以 sayHi 的 this 指向上一层作用域所在的对象,也就是 window。

场景 2

const person = {
    sayHi: () => {
        console.log(this)
    }
}

person.sayHi() // window

sayHi 的上层作用域就是全局作用域,所在的对象是 window,所以 this 指向 window。

场景 3

const person = {
    sayHi: function () {
        return {
            fn: () => {
                console.log(this)
            }
        }
    }
}

const xiaoming = person.sayHi()

xiaoming.fn() // person

this 在定义时是在 fn 函数作用域中,箭头函数本身不存在 this,所以它的 this 指向上一层作用域 sayHi 所在的对象 person,所以无论是谁调用了 fn ,this 始终指向 person。

改变 this 指向

通过 call() apply() bind() 可以改变 this 指向。

apply

const Person = {
    name: 'xiaoming'
}

function fn(age, sex) {
    console.log(this) // {name: 'xiaoming'}
}

fn.apply(Person, [18, '男'])

call

const Person = {
    name: 'xiaoming'
}

function fn(age, sex) {
    console.log(this) // {name: 'xiaoming'}
}

fn.call(Person, 18, '男')

bind

const Person = {
    name: 'xiaoming'
}

function fn(age, sex) {
    console.log(this) // {name: 'xiaoming'}
}

const ex = fn.bind(Person, 18, '男')

ex()

以上三者的传参方式和执行方式不同。

apply、call 的区别:接受参数的方式不一样。

bind:不立即执行。而 apply、call 立即执行。

点赞
收藏
评论区
推荐文章
巴拉米 巴拉米
3年前
bind、call、apply 区别?如何实现一个bind?
一、作用call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向那么什么情况下需要改变this的指向呢?下面举个例子var name"lucy";const obj{    name:"martin",    say:function (){        co
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
小嫌 小嫌
3年前
Javascript中的变量提升
定义JavaScript中奇怪的一点是你可以在变量和函数声明之前使用它们。就好像是变量声明和函数声明被提升了代码的顶部一样。sayHi()//Hithere!functionsayHi()console.log('Hithere!')name'JohnDoe'console.log(name)//JohnDoevarn
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
ES6箭头函数与普通函数的区别
箭头函数:letfun(){console.log('lala');}普通函数functionfun(){console.log('lalla');}箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一
Stella981 Stella981
3年前
JS 中的this指向问题和call、apply、bind的区别
this的指向问题一般情况下this对象指向调用函数的对象,全局环境中执行函数this对象指向window。functiona(){console.log(this);//输出函数a中的this对象}functionb(){};varc{name:"call"}
Wesley13 Wesley13
3年前
ES6 箭头函数
一、在es6中函数的定义和es5之间有明显区别。不需要关键字function来进行定义,使用来指向函数。不可以new也就是做构造函数以及没有arguments参数。箭头函数的this是在定义的时候确定指向这和es5不一样,es5是谁调用他,他就指向谁。1document.addEventListene
Wesley13 Wesley13
3年前
ES6新增的一些特性
1、let关键字,用来代替var的关键字,特点: 1、变量不允许被重复定义2、不会进行变量声明提升3、保留块级作用域中i的2、const定义常量,特点:1、常量值不允许被改变2、不会进行变量声明提升3、箭头函数  与普通函数的区别:1、书写上用代替了function         2、普通函数的this指向window而ES6
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_