相信大家在开发的过程中都会用到call,bind,apply。 所以在面试的过程中个三者基本都会被问到,手写原理。
谈谈你对call,bind,apply的理解?
遇到这个问题首先就要想到this。那么就看看你对this的理解吧。
MDN上是这么解释的: 与其他语言相比,函数的 this关键字在JavaScript中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别。
在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。ES5引入了bind方法来设置函数的this值,而不用考虑函数如何被调用的,ES2015 引入了支持this词法解析的箭头函数(它在闭合的执行环境内设置this的值)。
全局执行
//浏览器中
console.log(this)//这里打印出来的是window对象
//node中
console.log(this)//这里打印出来的是global
总结:在全局中执行的this指向当前的全局对象,浏览器中指向的是window对象,node中指向的是global
函数中执行
function fn(){
console.log(this)
}
fn()//window
//这里指向的是window对象,可以理解为window.fn()
可以看到在函数中执行的this指向是window,但是在严格模式下this的执行和非严格模式下的指向是不一样
'use strict'
function fn(){
console.log(this)
}
fn()//undefined
//可以看到严格模式下this的指向是undefined,所以在使用严格模式下,为了不对全局环境造成污染,可以把严格模式放在一个立即执行的函数中
(function (){
'use strict'
function fn(){
console.log(this)
}
fn()//undefined
})()
在对象中执行
当我们在对象中调用一个函数方法,this的指向又是什么呢?
let obj={
name:'dog',
fn:function(){
console.log(this)
}
}
obj.fn()//obj
//可以看到这里的指向是obj,在this指向没有被改变的情况下,谁调用函数函数中的this就指向谁
//======================当然还有一种形式的调用
let fun=function (){
console.log(this)
}
let obj={
name:'dog',
fn:fun
}
obj.fn()//obj
this关键字的一些坑
直接看代码吧
let obj={
name:'dog',
fn:function(){
console.log(this)//window
},
fn1:function(){
console.log(this)//obj
setTimeout(this.fn,0)
}
}
obj.fn1()
//fn1中直接打印的 this是obj对象,但是setTimeout中调用的fn打印的this是window
//解决这个setTimeout中this的指向可以用闭包解决
let obj={
name:'dog',
fn:function(){
console.log(this)
},
fn1:function(){
console.log(this)//obj
let _this=this
setTimeout(function(){
console.log(_this)//obj
console.log(this)//window
},0)
}
}
obj.fn1()
//严格模式下的setTimeout的坑
'use strict'
setTimeout(function(){
console.log(this) //这里的this指向的是window对象并非undefined
},0)
在构造函数中使用this
//构造函数中的this
function Person(name){
this.name=name
console.log(this)//person{name:'jone'}
}
let p=new Person('jone')
//非构造函数中的执行
function Person(name){
this.name=name
console.log(this)//window
}
let p=Person('jone')
下面我们就来说下bind、call、apply的区别
call 和 apply 的主要作用,是改变对象的执行上下文且立即执行。区别是传参的方式存在区别。
// call传参:
var obj={
name:'mingzi'
}
function showName(name,name1){
console.log('我的名字:'+name+'曾用名:'+name1)
}
showName.call(obj,'sjs','sjs1')//我的名字:sjs曾用名:sjs1
//apply传参:
var obj={
name:'mingzi'
}
function showName(name,name1){
console.log('我的名字:'+name+'曾用名:'+name1)
}
showName.apply(obj,['sjs','sjs1'])//我的名字:sjs曾用名:sjs1
bind 也可以改变对象的执行上下文,它与call和apply区别是:返回值是一个函数,并且需要调用一下才会执行,不会立即执行。
var cat={
name:'咪咪'
}
var dog={
name:'汪汪',
eat:function(y , n){
console.log(this.name + y + n +'骨头')
}
}
var show=dog.eat.bind(cat,'吃','不吃');
show()
三者相似之处
- 1、都可以改变函数this对象的指向
- 2、三者的第一个参数都是this要指向的对象
- 3、都可以利用后续的参数传参数
===后续有时间在说下原理。