JS 总结之关于 this 应该知道的几个点

开源君
• 阅读 1631

JS 总结之关于 this 应该知道的几个点

JS 中的 this 对每位前端工程师都不陌生,经常看到对象这里 this 那里 this,那什么是 this?答案就是上下文对象,即被调用函数所处的环境,也就是说,this 在函数内部指向了调用函数的对象。

通俗的讲,就是谁调用了函数

? 情况 1

this 指向 window

var name = 'xiaoming' // 思考,为什么不能用 let 或者 const ?
function foo () {
  console.log(this.name)
}
foo() // xiaoming

谁调用了这个函数,答案就是 window。这好理解,因为这里的变量和函数都是直接挂在 window 上的,等同于 window.foo()。需注意,严格模式下,this 为 undefined

? 情况 2

this 指向一个对象

var name = 'xiaoming'
var foo = {
  name: 'Jon',
  getName () {
    console.log(this.name)
  }
}
foo.getName() // Jon

谁调用了这个函数,答案是 foo 对象,所以打印了 Jon 而不是 xiaoming

var bar = foo.getName
bar() // xiaoming

如果赋值到另一个变量,就变成 window 调用,所以打印了 xiaoming

? 情况 3

this 指向了一个用 new 新生成的对象

function Person (name) {
  this.name = name
  this.getName = function () {
    console.log(this.name)
  }
}

var jser = new Person('Jon')
jser.getName() // Jon

这种方式成为 new 绑定,也叫做构造调用

JavaScript 中,new 的机制实际上和面向类的语言完全不同,构造函数只是一些使用 new 操作符时被调用的函数,它们并不会属于某个类,也不会实例化一个类。

实际上,除 ES6 的 Symbol()外,所有函数都可以用 new 来调用,所以并不存在所谓的构造函数,只有对于函数进行构造调用

使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作:

  1. 创建(或者说构造)一个全新的对象
  2. 这个新对象会被执行原型链接
  3. 这个新对象会绑定到函数调用的 this
  4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象

这个例子中,使用 new 来调用 Person(..) 时,我们会构造一个新对象(jser)并把它绑定到 Person(..) 调用中的 this 上。
或者可以这么想,谁调用了 getName ?就是 jser 调用了,所以 this 指向了 jser

? 情况 4

用 call,apply 和 bind 来修改 this 指向

? call / apply

call 和 apply 是以不同对象作为上下文对象来调用某个函数,举个例子:

var bar = {
  name: 'bar',
  getName () {
    console.log(this.name)
  }
}

var foo = {
  name: 'foo'
}

bar.getName.call(foo) // foo

看起来像是借用函数,对象 foo 借用了 bar 的函数 getName,所以我们判断一个对象类型,经常这么搞:

let foo = [1,2,3,4,5]
Object.prototype.toString.call(foo) // "[object Array]"

apply 和 call 的用法一样,不同点在于 call 用参数表给调用函数传参,而 apply 使用了数组

? bind

bind 可以永久性的修改函数中的 this 的指向,无论谁调用,this 指向都一样,并返回了完成绑定的函数,看例子:

var bar = {
  name: 'bar',
  getName () {
    console.log(this.name)
  }
}

var foo = {
  name: 'foo'
}

foo.func = bar.getName.bind(bar)
foo.func() // bar

这里的 func 不受 foo 影响,this 还是指向了 bar

var bar = {
  name: 'bar',
  getName () {
    console.log(this.name)
  }
}

func = bar.getName.bind(bar)
func() // bar

这里的 func 也不受 window 影响,this 还是指向了 bar

综合上述,bind 强制修改了 this,谁调用了函数 this 都不能被修改

? 忽略 this

如果你把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值再调用时会被忽略,实际应用的是默认绑定。

? 箭头函数

ES6 中介绍了一种无法使用这些规则的特殊函数类型:箭头函数,根据外层(函数或者全局)作用域来决定 this,箭头函数常用于回调函数

? 情况 1 中,为什么不能用 let 声明?

ES6 中,let 命令、const 命令、class 命令声明的全局变量,不属于顶层对象的属性,window 无法访问到。var 命令和 function 命令声明的全局变量,属于顶层对象的属性,window 能访问到。

所以 情况 1 中改为:

let name = 'xiaoming'
function foo () {
  console.log(this.name)
}
foo() // undefined

? 参考

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
4年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Stella981 Stella981
4年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Stella981 Stella981
4年前
JS 中的this指向问题和call、apply、bind的区别
this的指向问题一般情况下this对象指向调用函数的对象,全局环境中执行函数this对象指向window。functiona(){console.log(this);//输出函数a中的this对象}functionb(){};varc{name:"call"}
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
开源君
开源君
Lv1
数点山浮空,四面天垂水。
文章
3
粉丝
0
获赞
0