关于js中this的处理情况汇总
-
给当前元素的某个时间行为绑定方法,当事件行为触发,方法被执行,方法中的this一般都是当前操作的元素 (排除IE6 - 8 中给予attachEvent进行的DOM2事件绑定,方法中的this是window)
document.body.onclick = function(){ console.log(this) // <body>...</body> } document.body.addEventListener('click', function(){ console.log(this) // <body>...</body> })
-
函数执行,看函数前面是否有点
.
,有点.
,点前面是谁this
就是谁,没有点.
,this
就是window
js
严格模式下,没有点.
,this
就是undefined
- 匿名函数(自执行函数/回调函数)一般
this
也是window
/undefined
,除非有特殊处理的 - 括号表达式中有特殊的处理
const fn = function(){ console.log(this) } let obj = { name: 'obj', fn: fn } fn(); // 根据第一条,没有点 this => window obj.fn() // 有点,点前面使obj, this => obj
严格模式下
"use strict" const fn = function(){ console.log(this) } let obj = { name: 'obj', fn: fn } fn(); // 根据严格模式下第一条,没有点 this => undefined obj.fn() // 有点,点前面使obj, this => obj
自执行函数
(function(){ console.log(this) // this => window })()
严格模式自执行函数
"use strict" (function(){ console.log(this) // this => undefined })()
回调函数
[1, 2].sort(function(a, b){ console.log(this) // this => window })
注意:下面的这个将会发生改变
[1].forEach(function(item, index){ console.log(this) // this => obj }, obj)
说明:看到这个结果并不符合我们上面的总结,这是因为
forEach
内部做了特殊的处理,传递的第二个参数是为了改变回调函数中的this
指向的括号表达式
let obj = { name: 'obj', fn: fn } function fn(){ console.log(this) } (obj.fn)() // this => obj
说明:括号表达式中只包含一项时与不加括号是没有任何区别的
let obj = { name: 'obj', fn: fn } function fn(){ console.log(this) } (10, 20, obj.fn)(); // this => window
说明:括号表达式中存在多项时,也只取最后一项,但是此时的
this
变为window
。可以理解为将括号表达式中的最后一项克隆一份,然后自执行。 -
构造函数执行
new xx
,函数体中的this是当前类的实例function Fn(){ this.x = 100; } Fn() // this => window let f = new Fn(); // this => f f.sum(); // this => f f.__proto__.sum(); // this => f.__proto__
说明:上面的例子并不适用直接粘贴复制,只是为了说明
-
ES6
中的箭头函数(或者基于{}形成的块级上下文)里面没有this
,如果代码中遇到this
也不是自己的,而是它上下文中的this
let obj = { name: 'obj', fn() { // this => obj setTimeout(function(){ console.log(this); // this => window (回调函数) this.name = 'joe'; // 这里改变的window.name }, 1000) } } obj.fn();
// 方法一 将 this指向obj时进行存储 let obj = { name: 'obj', fn() { // this => obj let that = this; setTimeout(function(){ that.name = 'joe' }, 1000) } } obj.fn(); // 方法二 使用箭头函数 let obj = { name: 'obj', fn() { // this => obj setTimeout(() => { // this => 用的使上级上下文中的this,也就是obj this.name = 'joe'; }, 1000) } } obj.fn();
-
我们可以基于
Function.prototype
上的call
/apply
/bind
方法强制改变 函数中的this指向- 对箭头函数没用,因为不存在
this
// 1 const fn = function fn(){ console.log(this.name) } window.name = 'joe'; let obj = { name: 'obj', } fn(); // 'joe' fn.call(obj) // 'obj' obj.fn() // Uncaught TypeError: obj.fn is not a function // 2 const fn = function fn(x, y){ this.total = x + y; console.log(this); return this; } window.name = 'joe'; let obj = { name: 'obj', } let res = fn.call(obj, 10, 20) // this => obj res => obj
分析call语法
函数
.call([context]
,params1
,params2
,...)
简单说明:把函数中的
this
指向[context]
,并把params1/params2...
作为实参传递给函数详细说明:
-
首先
fn
基于原型链__proto__
,找到Function.prototype.call
方法,并把call
方法执行 -
call
方法中的this
就是当前操作的实例fn
,传递给call
方法的第一个实参是改变fn
中的this
指向,剩余的实参都是未来要依次传递给fn
的参数信息 -
cal
l方法执行的过程中,实现了这样的处理:把fn
[call
中的this
]指向[context]
,并且把params1/params2...
作为实参传递给fn
,依次来达到最后的效果 -
最后接受
fn
的返回结果,作为返回值返给外部
结论
-
执行
fn.call(10, 20)
此时this
则为10
, 说明第一个参数传递的是什么则this
指向就是什么 -
执行
fn.call()
无参数时this
为window
,如果第一个参数是null
或者undefined
,在JavaScript
非严格模式下,最后fn
中的this
都是window
(严格模式下,不传this
是undefined
,传递null
、undefined
,this
也会改为对应的值)
apply
函数
.call([context]
,[params1
,params2
,...])
call
与apply
的唯一区别:执行函数的时候,需要传递给函数的参数信息,在最开始传递给call/apply
的时候,形式不一样-
call
需要把参数一个个传递给call
,call
方法内部再一个个传递给函数 -
apply
是需要把参数放在一个数组中传递给apply
,但是apply
内部也会帮我们把接受数组中的每一项一项一项的传递给函数
bind
call/apply
在执行的时候,都会立即把要操作的函数执行,并且改变它的this
指向bind
预先处理:执行bind
只是把函数中需要改变的this
等信息存储起来,但是此时函数并不会被执行,执行bind
会返回一个匿名函数,当后期执行匿名函数的时候,再去把之前需要执行的函数执行,并且改变this
为预设的值此时执行
fn.bind(obj, 10, 20)
,bind
执行但是fn
是不会执行的。let anonymous = fn.bind(obj, 10, 20); console.log(anonymous) // ƒ fn(x, y){ // this.total = x + y; // console.log(this); // return this; // }
说明:
anonymous
的值为一个函数,也就是说后期把返回的函数anonymous
在执行,在里面才会把fn执行,并且按照预设的信息改变this
等// 错误答案 请思考一下原因 // 1. setTimeout(fn, 1000); // 1000ms 后执行fn,但是this => window, x/y都是undefined // 2 setTimeout(fn.call(obj, 10, 20), 1000) // 因为设置定时器时,基于call方法,就已经把fn执行了,虽然this和参数都是我们想要的,但是并不是1s后执行。就是把fn的返回结果邦洞给定时器,1000 ms后执行的使返回结果 // 正确答案 // 1. setTimeout(function(){ fn.call(obj, 10, 20) }, 1000) // 2. setTimeout(fn.bind(obj, 10, 20), 1000)
- 对箭头函数没用,因为不存在
最后
biu biu biu ~ ❤️❤️❤️❤️ 点关注 ?? 不迷路 点个赞哦?
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!