Call Apply Bind 以及this的讲解
对于上述三个方法,我们分为三步来讲
1.复习this指针
2.怎么改变this
3.原理是什么
**
一. 复习this指针
**
先来几道题目,来熟悉下this
(1)下面的代码输出的内容是?
var uName = '张三';
function a() {
var uName = "李四";
console.log(this.uName);
console.log(this);
}
a();
这道题很明显,this.name 并没有具体的调用者,所以默认为 window,这里就要总结一个知识点,
就是 this指针指向的是调用他的对象
输出结果为
张三
window
(2)那我再稍微改变一下
var uName = '张三';
var a = {
uName: '李四',
fun: function (){
console.log(this.uName);
}
}
a.fun();
window.a.fun()
根据之前总结的知识点,谁调用,指向谁,这里执行的是 a.fun(),是 a 调用,所以指向 a中的内容;
而 window.a.fun() 虽然看上去有些怪,但是本质上是没有变的,依然是 a 调用,不管前面有几个调用者,
指针指向的是最后一个调用者
输出结果为
李四
李四
(3)输出的结果是什么?
var uName = '张三';
var obj = {
uName: '李四',
fun: function (){
console.log(this.uName);
}
}
var obj2 = obj.fun;
obj2();
这段代码的意思是,把这个函数给到一个变量身上,而这个函数并没有立即执行,随后再通过这个变量去执行(也叫地址引用),根据之前总结的结果,这里并没有出现调用者,this默认指向window
输出的结果为
张三
(4)最后一题
var name = '张三';
function fun() {
var uName= '李四';
fuck();
function fuck() {
console.log('执行了',this.uName);
}
}
fn();
很显然,不管是外部的 fn(),还是里面的 fuck(),我们只要清楚,它到底有没有调用者,有么?都没有,所以答案就很清楚了
输出的结果为
张三
**
二.如何改变指针
**
1.使用箭头函数(这个最简单干脆,我反正挺爱用)
这里我就不费篇幅去解释什么是箭头函数了,建议大家去MDN看看,这里留个链接
MDN 关于箭头函数的解释
话不多说,直接上代码!!!
var name = 'A';
var a = {
name: 'B',
fun1: function (){
console.log(this.name)
},
fun2: function (){
setTimeout(function (){
this.fun1()
},2000)
}
}
a.fun2();
这段代码您先甭着急跟着写,你不觉得放在上面很有问题么,fun2中的this指向的是哪?是window,既然都指向window了,那我写this.fun1(),那我上哪去找fun1?直接就找不到,所以,我们下面就使用箭头函数来解决这个问题,上代码
var name = 'A';
var a = {
name: 'B',
fun1: function (){
console.log(this.name)
},
fun2: function (){
setTimeout(() => {
this.fun1()
},2000)
}
}
a.fun2();
现在可以放心的复制这段代码了,这次一执行,有结果了,this指向的是 a。
2.闭包
闭包也算是面试中,比较有戏份的角色了,既然要用,那就要了解什么是闭包
这里依旧是不再这里废话,建议大家多自己动动手,这里就直接给网址
MDN 关于闭包的描述
上代码
var name = 'A';
var a = {
name: 'B',
fun1: function (){
console.log(this.name);
},
fun2: function (){
//通过变量把外边的指针保存进来,也叫闭包
var _this = this;
setTimeout(function (){
_this.fun1();
},1000);
}
}
a.fun2();
那既然用箭头函数或者闭包就能解决的问题,为何还要用call 和 apply? 因为它们可以动态的改变,比起箭头函数和闭包更为灵活,call、bind、apply都是重定义this的
为了方便理解,这里还是用代码来解释
var name = 'A',
age = 20;
var obj = {
name: 'B',
fun: function (){
console.log(this.name + '/' + this.age)
}
}
var stu = {
name: 'C',
age: 25
}
obj.fun.call(stu);
obj.fun.apply(stu);
obj.fun.bind(stu)();
在实际敲的时候,发现只有bind()方法是需要在后面加()才可以执行,也就是说bind()方法返回的是个函数,需要调用才能执行
不仅在调用上有区别,在三者传参的方式上也是有差异的,这里也是直接上代码来加深理解
var name = 'A',
age = 20;
var obj = {
name: 'B',
fun: function (industry,skill){
console.log('我叫' + this.name + '今年' + this.age + '岁,从事' +
industry + '行业,熟悉' + skill + '技术!')
}
}
var stu = {
name: 'C',
age: 25
}
obj.fun.call(stu,'计算机','React');
obj.fun.apply(stu,['计算机','VUE']);
obj.fun.bind(stu,'计算机','TypeScript')();
obj.fun.bind(stu,['计算机','Nodejs'])();
通过代码,很容易就看出者三者的区别,call()的参数是直接传递的,apply()的参数需要放在数组里面,bind()则同时拥有两种传参方式,除了返回的是个函数。
总结:
共同点:
1.这三个方法都是Function原型上面的方法,都是针对函数而言的
2.三种方法都是用于改变函数内部this指向的,再严谨点,都是在改变函数执行时=时候的内部this指向
3.都能接收多个参数,第一个参数就是改变后this的指向,后面是可选参数
不同点:
1.apply() 和 call()调用时,会立即返回函数执行结果,它们的this会指向第一个参数,apply()的第二个参数是一个数组,call()的第二个或之的参数都是数组元素
2.bind()方法不会立即调用,而是返回一个新的函数,也叫绑定函函数,其内部的this指向为它传入时的第一个参数,而传入bind()之后的参数作为原函数的参数来调用原函数
以上都是个人在自学是,查阅和观看其他大佬,以及文档之后浅显的总结出来的,其中涉及的一些底层原理,我本人也不是很清楚,我也在虚心的学习中,而发布文章也是为了记录自己的学习心得,望大佬们对其中的错误和不足提出宝贵意见(狗头.jpg)