this
如何确定this,其实就是知道当前函数执行主体是谁,如果是对象来调用,this就是调用的对象。
let zhangsan={
name:'张三',
getName(){
console.log(this.name)
}
}
zhangsan.getName();
this是zhangsan
如果没有对象调用,直接执行:
let getName=zhangsan.getName;
getName()
没有对象调用分两种情况:
非严格模式下,主体是window,global;
严格模式下是undefined
其实this的确定就一条规则,谁调用就是谁。
如果事件绑定的时候,this就是绑定的元素。
let dom={
addEventListener(type,callback){
dom["on"+type]=callback
},
trigger(type){
dom.onclick()
}
}
dom.addEventListener('click',function(){
console.log(this === dom) //true
})
dom.trigger('click')
call apply bind:
apply,call,bind,都是用来重定向this这个对象的。
先看一下apply,call,bind的用法:
不传参时:
var name="小王",age=17;
var obj={
name:"小张",
objAge:this.age,
myFun:function(){
console.log(this.name+"年龄"+this.age);
}
}
var db={
name:"德玛",
age:99
}
obj.myFun.call(db);//德玛年龄99
obj.myFun.apply(db);//德玛年龄99
obj.myFun.bind(db)();//德玛年龄99
传参的时候:
var name="小王",age=17;
var obj={
name:'小张',
objAge:this.age,
myFun:function(fm,t){
console.log(this.name+'年龄'+this.age,'来自'+fm+'去往'+t);
}
}
var db={
name:'德玛',
age:99
}
obj.myFun.call(db,'成都','上海');//德玛年龄99,来自成都去往上海
obj.myFun.apply(db,['成都','上海']);//德玛年龄99,来自成都去往上海
obj.myFun.bind(db,'成都','上海')();//德玛年龄99,来自成都去往上海
obj.myFun.bind('db',['成都','上海'])();//德玛年龄99,来自成都,上海去往undefined
解析:
call、bind、apply三个函数的第一个参数都是this的指向对象,
第二个参数差别:call的参数是直接放进去的,第二三n个参数都是用都会分隔,直接放到后obj.myFun.call(db,'成都', ... ,'string' );
apply的所有参数必须放在一个数组里面传进去,obj.myFun.apply(db,['成都', ..., 'string' ])
bind 除了返回是函数以外,它 的参数和 call 一样。
当然,三者的参数不限定是 string 类型,允许是各种类型,包括函数 、 object 等等!
手动封装call方法:
function getName(){
console.log(this.name)
}
let obj={name:'zhufeng'}
//自执行函数 修改this指向实现原理如下:
!(function(prototype){
function call2(context){
context.getName=this;//给对象临时赋值一个属性,赋值,this指的是getName
context.getName();//拿对象调用这个方法
delete context.getName;//删除对象属性
}
prototype.call2=call2
})(Function.prototype);
getName.call2(obj)
把call apply bind的封装融合到一起,手写代码:
//以obj作为调用方,或者说执行主体,调用getName方法
function getDefaultContext(context){
//如果context是null或者undefined,则context的this执行window
context=context||window
let type=typeof context
if(['number','string','boolean'].includes(type)){
context=new context.constructor(context)//可以通过constructor判断数据类型
console.log("1",context)
}
//context=Object(context)
console.log("context",context)
return context
}
!(function(prototype){自执行函数 修改this指向
function call2(context,...args){
context=getDefaultContext(context)
let symbol=Symbol('fn')
console.log("symbol",symbol)
context[symbol]=this给对象临时赋值一个属性,赋值,this指的是getName
context[symbol](...args);//getName(10,'家') //拿对象调用这个方法
delete context[symbol];//删除对象属性
}
function apply2(context,args){
context=getDefaultContext(context)
let symbol=Symbol('fn')
context[symbol]=this
context[symbol](...args)
delete context[symbol];
}
function bind2(context,...outerArgs){
return (...args)=>this.call2(context,...outerArgs,...args)
}
prototype.bind2=bind2
prototype.apply2=apply2
prototype.call2=call2
})(Function.prototype);
function getName(age,home){
console.log(this.name,age,home)
}
//let obj='zhufeng'
let obj={name:'zhufeng'}
getName.call2(obj,10,'家')
getName.apply2(obj,[10,'家'])
let bingGetName=getName.bind2(obj,10)
bingGetName('zhufeng')