js中关于call源码的解析
call、apply、bind
三个方法都是改变函数中的 this 指向;只有是Function的实例才可以使用这三个方法。
首先函数中的this 不能放在等号的左边,不能直接被修改。否则会抛出异常。
这时就需要call、apply、bind这三个方法来改变this的指向。
function fn(){
this=100; //Uncaught SyntaxError: Invalid left-hand side in assignment
console.log(this);
}
fn()
call
单call的情况下:
- 让fn的属性名是call的属性值执行,但是fn没有call属性,所以需要通过**proto向原型查找,找到了Function原型中的call**,并且让call函数执行了。
- 当call执行时,改变了fn中的this,让这个this指向call方法第一个实参。(如果不传参或者传入null \ undefined,非严格模式下fn的this指向window)
- call中传入的第二个参数及之后的参数,都传给fn这个函数。
function fn(a,b,){
console.log(this);// [100,200]
console.log(a);// 10
console.log(b);// 11
}
fn.call([100,200],10,11)
一个参数多次调用call方法(二次及以上):
function fn1() {
console.log(1)
console.log(this)
}
function fn2() {
console.log(2)
console.log(this)
}
fn1.call(fn2) // 1 ƒ fn2(){}
fn1.call.call(fn2) // 2 window
我们封装一下call基本的源码:
- 单call
function fn1(a, b) {
console.log(this) // obj
console.log(a) // 11
console.log(b) // 12
}
let obj = { name: "newThis" }
Function.prototype.Mycall = function (obj, ...ary) {
obj = obj || window // 如果不传参数 就让其指向window
obj.$fn = this; // this就是fn1函数
var result = obj.$fn(...ary);
delete obj.$fn // 自己添加的属性,最后要清掉,避免影响使用
return result // 把函数的返回值return出去
}
fn1.Mycall(obj, 11, 12)
- 多call
function fn1() {
console.log(this)
}
function fn2() {
console.log(this)
}
Function.prototype.Mycall = function (arg) {
arg = arg || window // 如果不传参数 就让其指向window
arg.$fn = this; // this是fn1.Mycall ; fn1.Mycall就是在fn1中查找属性名为Mycall的属性值 就是Mycall这个方法本身
var result = obj.$fn(); //相当于fn2.Mycall() 在这把上文单call在走一边,因为没有传参所以fn2中的this指向window
delete arg.$fn // 自己添加的属性,最后要清掉,避免影响使用
return result // 把函数的返回值return出去
}
fn1.Mycall.Mycall(fn2) //暂不考虑传多个参数的情况
如有不对,欢迎指出问题所在,定当认真修改。
链接: 博客主页.