call apply bind是用来改变this的指向的
先来说一下this吧
普通函数的this指向规律👇:
1、 事件绑定的函数中的this,是指向当前操作元素的。
var btn = document.getElementsById('btn')
btn.onclick = function(){
console.log(this)//=>this指的是当前操作的这个元素,也就是btn
}
2、 自执行函数中的this是指向 window的。
btn.onclick = (function(){
//赋予 onclick 的 该自执行函数的返回结果,也就是一个箭头函数
return ()=>{
console.log(this)//=>this是指向 window的
}
})();
3、 其他的函数执行中的this👉 看点 。
function fn(){
console.log(this);
}
var obj = {
a:fn,
b:12,
c:13
}
var ary = [4,5,fn];
var obj2 = {
q:12,
w:fn
}
fn(); //=> window fn obj.a ary[2] obj2.w 四者同一个地址
obj.a(); //=> obj 👈看点
ary[2](); //=> ary
obj2.w(); //=> obj2 👈看点
箭头函数中没有this,箭头函数中把this当作变量向上级作用域查找
call apply bind的用法
一看就懂call的一道题
function fn() {
console.log([...arguments])
console.log(this)
return 123;
}
var obj = {
a: 12,
b: 13,
qqq: 123,
f: fn
}
fn(1,2,3) //fn执行,this指向window,因为前面没点
obj.f(6,6,6); //obj.f执行 , this指向obj,因为前面有点
fn.call(obj,5,5,5); //将fn中的this原本的指向window改为obj,并且把5,5,5作为实参传进去
一看就懂apply的一道题
//还拿这道题为例
function fn() {
console.log([...arguments])
console.log(this)
return 123;
}
var obj = {
a: 12,
b: 13,
qqq: 123,
f: fn
}
fn.apply(obj.[5,5,5]) //第二个参数是个数组或者类数组的集合;虽然是以一个集合的形势传过去的;但是 fn 接收时还是散乱的接收的
一看就懂bind的一道题
//继续拿这道题为例
function fn() {
this.name = 123;
this.age = 234;
return 123;
}
var obj = {
a:12,
b:13
}
var f = fn.bind(obj,6,6,6,6);
// f执行 让 fn执行; 并且把 6,6,6,6传给fn;fn中的this 指向是 obj;
// 把 6,6,6,6 理解成 f 的默认参数;再给f传递参数的时候;会把传递的参数补在 默认参数的后边;
console.log(f)
call apply 都是让函数立即执行了, bind是返回了一个新函数,使用bind改变过this的指向之后,this不再改变
封装一个Call
call 是用来改变函数内部得this指向的 在Function的原型上
call可以让函数执行 并且可以改变函数执行时 内部的this指向 this执行了call的第一个实参 call后面的所有参数都被传给前面的函数当作实参
实现一个myCall
Function.prototype.myCall = function (context,...arg) {
// context 就是我们让this指向的哪个值, arg是要传给对应函数的实参
context = context || window //有传context的话this就指向context;没有传context得话this就指向window
var n = Symbol(); // Symbol是唯一值
context[n] = this; //确定this指向
let res = context[n](...arg);
delete context[n];
return res
}
封装一个myApply
myApply的目的跟call一样 区别在于第二个参数 第二个参数是一个数组或者类数组
类数组转数组
- [...xxx]
- Array.from(xxx) :from在Array类上面,Array的实例是调不到from的,from和prototype是兄弟关系
- [ ].slice.call(arguments,0)
- arguments. _ _proto _ _ =Array.protitype
实现一个myBind
Function.prototype.myApply = function(context,ary){
ary = ary || []
context = context || window
let n = Symbol()
context[n]=this
let arr = context[n](...ary)
delete context[n]
return arr
}
使用apply获取数组中的最大值
var ary = [234,53,2342,45,234,464,2,6,45];
Math.max.apply(Math,ary);// 利用了 apply 可以把集合散乱的传给前边的函数
//其他方法:
Math.max(...ary);
ary.sort((a,b)=>b-a)[0];
// 假设法
var max = ary[0]
ary.forEach((v, i) => {
if (v > max) {
max = v
}
})
封装一个myBind
var f = fn.bind(obj,1,2,3,4)bind的用法与call一样,只是bind返回一个新函数,新函数执行时 fn才会执行
fn中的this这时才被改成obj; f中的this 不会在发生任何改变了;再使用 call apply 也不好使;
call apply 都是让函数立即执行了;但是bind是返回了一个新函数;
实现一个myBind
Function.prototype.myBind = function(){
var _this = this;
return function(...ary){
return _this.apply(context,arg.concat(ary))
}
}