揭秘this、call、apply和bind

1.this

1.1 this 到底是什么?

this 就是 call 方法传递的 第一个参数
接下来给出转换公式:

  • fn(x) <=> fn.call( undefined , x)
    严格模式(‘use strict’) 下this 就是的 undefined,非严格模式下,浏览器会默认把undefined 变成 window

  • a.b.c. fn(x) <=> a.b.c. fn.call(a.b.c, x)
    this 就是 a.b.c

1.2 this 题目分析
1.2.1 严格模式与非严格模式下的 this
var f1 = function (){
	'use strict'   // 使用严格模式
	console.log(this)
}
f1()  //  undefined,不是对象; f1()等价于f1.call(undefinded)
f1.call(null) // null,不是对象
f1.call(5201314) // 5201314, 不是对象
f1.call(true) // true, 不是对象
f1.call(x) // 报错,x 未定义
---------------------------------------------------------------
var f1 = function (){
	console.log(this)
}
f1()  //  window,对象; f1()等价于f1.call(undefinded)
f1.call(null) // window,对象
f1.call(5201314) // 5201314, number对象
f1.call(true) // true, boolean对象
f1.call(x) // 报错,x 未定义
1.2.2 青铜段位的this
var a = 1
    var obj1 = {
      a:2,
      fn:function(){
        console.log(this.a)
      }
    }
obj1.fn() //2   obj1.fn.call(obj1),this就是obj1
1.2.3 白银段位的this
var obj = {
  foo: function(){
    console.log(this)
  }
}
var bar = obj.foo
obj.foo() // 转换为 obj.foo.call(obj),this 就是 obj
bar()   // bar.call() => bar.call(undefined), 结果是 window 对象

function fn2(){}
function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]()  //   [ƒ, ƒ], this 就是 arr, 相当于arr.0.call(arr) 
1.2.4 黄金段位的this
button.onclick = function f1(){
	console.log(this)
}  // 看文档,搜索 MDN onclick,文档说给处理器的 this 是触发事件的元素,这里是button

button.addEventListener('click', function(){
	console.log(this)
}) // 看文档,搜索 MDN addEventListener,this是该元素的引用,这里是button

$('ul').on('click', 'li',  function(){
	console.log(this)
}) // 看文档,搜索jQuery on,当jQuery的调用处理程序时,
//this关键字指向的是当前正在执行事件的元素,这里就是 'li'
1.2.5 铂金段位的this
button.onclick = function(){
  function fn(){
    console.log(this);  // 竟然是 window, 蛋疼
  } 
  fn();  // 其实就是这个函数的执行,等价于 fn.call(undefined),this 就是undefined
};
button.onclick = function(){
  var _this = this;  // this 是 button
  function fn(){
    console.log(_this);  // _this 是botton ,将失去的 this 找回了 
  }
  fn();
};

// 也可以用下面的写法
button.onclick = function(){
  var fn = function(){
    console.log(this); //call 传递的this 值
  }.call(this); // button
};

var obj={}
obj.fn=function(){
	console.log(this) // obj {fn: function} 
	! function(){
		console.log(this) //  window
	}() // 记住一个结论,匿名函数的执行具有全局性,所以传入的是undefined, 所以this是window

}
obj.fn()
1.2.6 钻石段位的this
var obj={
	fn:function(){
		setTimeout(function(){
			console.log(this);
		},100);
	}
}
obj.fn();//window
// 记住一个结论:
// this出现在全局函数setTimeout()中,在setTimeout的延迟函数(非箭头函数)内,this指向 window

var obj={
	fn:function(){
		console.log(this)  // obj
		setTimeout(() => {
			console.log(this);  // 就是外面的 this: obj
		});
	}
}
obj.fn();  // 箭头函数中的 this 就是外面的this,这句话很重要
1.2.7 最强王者的this
function X(){
    return object = {
        name: 'object',
        options: null,
        f1(x){
            this.options = x   // 第2步:这个x是第一步传递的options,this是第一步的call的
            this.f2()  //第一个参数 x(外面的x),它是由x = X()决定, 就是X()的返回值,object
        },
        f2(){
            this.options.f2.call(this) // 第3步:第一个this 是object, 第二个this 也是object
        }
    }
}

var options = {
    name: 'options',
    f1(){},
    f2(){
        console.log(this) // 第4步:这个this是第3步传进来的this, object
    }
}

var x = X()
x.f1(options) // object,第1步:改写 x.f1.call(x, options)

再也不想看到this了。。。

2. call、apply 、bind

2.1 三者异同

它们都是用来改变 this 的指向

  • call()和apply()功能相同,唯一不同的是传参的时候call第二个参数只能传递参数列表,而apply可以是列表也可以是arguments或数组
  • 使用call和apply会直接执行这个函数,而bind并不直接执行,而是将绑定好的this重新返回一个新函数,什么时候调用由你自己决定,bind的传参方式和call相同
function f(a, b) {
    console.log(this)
    console.log(a)
    console.log(b)
}

f() //window, undefined, undefined

/*call*/ 
f.call('a', 2, 3) //'a', 2, 3
f.call('a', 2)  //'a', 2, undefined
f.call() //window, undefined, undefined 

/*apply*/
f.apply('a', [2, 3]) //'a', 2, 3
f.apply('a', [2]) //'a', 2
f.apply() //window, undefined, undefined 

/*bind*/
nf = f.bind('a', 2, 3) //bind方法返回一个新函数
nf() // 'a', 2, 3 
nf = f.bind('a', 2)
nf() // 'a', 2,undefined
nf = f.bind('a')
nf() // 'a', undefined, undefined 
nf = f.bind()
nf() // window, undefined, undefined 
2.2 对于箭头函数
  • 箭头函数会捕获其所在上下文的 this 值,作为自己的 this 值
    扩展: 箭头函数和普通函数的区别
  • 箭头函数不能使用 new 命令,它作为匿名函数是不能成为构造函数的
  • 箭头函数没有 arguments 对象,但是可以用 Rest 参数代替
var fn = (...x)=>{    // ...x 即为rest参数
  console.log(x); 
}
fn(1, true, function(){})  // [1, true, ƒ]
  • 不可以使用 yield 命令, 因此箭头函数不能用作 Generator 函数
  • 通过 call() 或 apply() 方法调用时,只是传入了参数而已,对 this并没有什么影响
  • 箭头函数没有原型属性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值