详解js中的this以及call、apply、bind

详解js中的this以及call、apply、bind

关于this指向的五种情况全局上下文中的this
全局上下文中this指向window,这种情况较为简单
this === window复制代码事件绑定方法中的this
给元素的某个事件行为绑定方法,当事件行为触发,方法执行,方法中的this指向当前元素本身。
let body = document.body;body.οnclick=function(){ console.log(this) // body}复制代码
再看一个例子:
let body = document.body;function func(){ console.log(this) // this指向window}body.οnclick=function(){ console.log(this) // body func()}复制代码
特殊情况:在IE6-8中,基于attachEvent实现的DOM2事件绑定,事件触发,方法中的this指向window
body.attachEvent(“onclick”, function(){ console.log(this) // window})复制代码普通函数执行中的this
函数执行(包含自执行函数执行、普通函数执行、对象成员访问调取方法执行等),只需要看函数执行的时候方法名前面是否有.,有的话,.前边是谁this就是谁,没有的话this指向window(严格模式下是undefined)
1、自执行函数执行
(function(){ console.log(this) // window,开启严格模式的话是undefined})()let obj = { f: (function(){ console.log(this) // window return function(){} })()}obj.f()复制代码
2、普通函数执行
function func(){ console.log(this) // this指向window}func()复制代码
3、对象成员访问调取方法执行
function func(){ console.log(this) // this指向调用它的对象obj}let obj = { f:func}obj.f()复制代码构造函数中this指向
构造函数体中的this是当前类的实例
function Fun(){ console.log(this) // this指向f}let f = new Fun()复制代码箭头函数中this指向
箭头函数中没有this,它的this是继承自己所在上下文中的this
let obj = { fun: function(){ console.log(this) // this指向调用它的对象 }, arrowFun: ()=>{ console.log(this) // 箭头函数中没有this,继承所在上下文中的this }}console.log(obj.fun()) // objconsole.log(obj.arrowFun()) // window复制代码
强制改变this也不行
obj.sum.call(obj) // this还是指向window复制代码强制改变this指向:call、apply、bind
每个函数都是Function这个类的实例。在Function的prototype(原型)上有三个方法:call、apply、bind,可以用来改变this指向。那么这三个方法有什么区别呢?
let obj = { name: “obj”}function func(x,y){ console.log(this,x,y)}复制代码
call:** [function].call([context],param1,param2,…)
call方法执行的时候会把[function]执行,并且把函数中的this指向为[context],并且把param1,param2等参数分别传递给函数。
func.call(obj,1,2) // obj 1 2复制代码
第一个参数不传或者传递的是null/undefined,非严格模式下this指向的是window,严格模式下传递的是谁就是谁
apply: [function].apply([context],[param1,param2,…])
和call基本一样,只不过传递给函数的参数需要以数组的形式传递给apply。apply内部会再把数组一项项的传递给[function],所以其结果和call是一样的。
func.apply(obj,[1,2]) // obj 1 2复制代码
bind: [function].bind([context],param1,param2,…)
语法上call类似,但是作用和call/apply都不一样。
call/apply都是会立即执行当前函数,并且改变函数中的this指向。bind不会立即执行当前函数,只是预先把函数中的this指向[context],把params这些参数预先存储起来。在调用的时候才会去执行。
func.bind(obj,1,2) // 此时func并没有执行func() // obj 1 2复制代码
假如现在有这样一个需求:把func函数绑定给body的click事件,要求当触发body的click事件后,执行func,同时让func中的this指向obj。
body.οnclick=func.bind(obj)复制代码
但是bind方法是不兼容ie6-8的,那么不用bind我们怎么实现呢?
body.οnclick=function(){ func.call(obj)}复制代码
使用call我们也可以实现同样的效果
call、apply、bind的简单实现
上文我们了解了call、apply、bind的使用以及他们之间的区别,下面我们来简单实现一下:
call方法:
Function.prototype.myCall = function(target, …args) { // this 为调用 myCall 的函数 const func = this; // call方法只能用于function if (typeof this !== “function”) { throw new TypeError(“not a function”) } // 在没有传值的情况下this指向window let context = target || window // 使function的this指向context context.fn = func // 将值分别传递给fn let result = context.fn(…args) return result};// 验证一下let obj = { name: “lp” }function foo(x,y) { console.log(this.name, x, y)}foo.myCall(obj, 21, 30) // lp 21 30复制代码
apply方法:
apply与call的唯一区别在于:apply仅接受两个参数,第二个参数是一个数组
Function.prototype.myApply = function(target, args) { // this 为调用 myApply 的函数 const func = this; // call方法只能用于function if (typeof this !== “function”) { throw new TypeError(“not a function”) } // 参数必须为数组 if(!Array.isArray(args)){ throw new TypeError(“not a Array”) } // 在没有传值的情况下this指向window let context = target || window // 使function的this指向context context.fn = func // 将值分别传递给fn let result = context.fn(…args) return result};复制代码
bind方法:bind和call的唯一区别在于,bind返回一个函数,不会立即执行。我们可以在call的基础上实现bind方法。
Function.prototype.myBind = function(context,…params){ // 默认不传的话指向window // this为调用 myBind 的函数 const func = this; if (typeof this !== “function”) { throw new TypeError(“not a function”) } return () => { // 这里使用箭头函数,保持this指向与bind中this指向一致 this.myCall(context,…params) }}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值