首先看数组中的一个方法:
Array.prototype.slice = function() {}
var ary = [12, 23, 34];
// ary.slice -> ary这个实例,通过原型链的查找机制,找到Array.prototype上的slice方法,此时是该函数的地址
// ary.slice(); -> 让找到的slice方法执行,在执行slice方法的过程中,才把ary数组进行截取
call方法的作用:
-> 首先让原型上的call方法执行,在执行call方法的时候,让fn方法中的this变为第一个参数值obj;然后再把fn这个函数执行。
var obj = {
name: 'derrick'
}
function fn() {
console.log(this);
}
fn(); // this -> window
fn.call(obj); // this -> obj
自己模拟内置的call方法,写一个myCall方法,深入探讨call方法执行的原理。
Function.prototype.myCall = function (context) {
// -> myCall方法中的this就是当前要操作和改变其this关键字的那个函数
// -> 1. 让fn中的this关键字变为context的值 -> obj
// -> 让this这个函数中的"this关键字"变为context
// var that = eval(this.toString().replace('this', context));
// -> 2. 让fn方法在执行
this();
}
fn.myCall(obj); // -> myCall方法中的this是fn
function sum() {
}
sum.myCall(obj); // -> myCall方法中this是sum
下面看一道面试题:
function fn1() {
console.log(1);
}
function fn2() {
console.log(2);
}
fn1.call(fn2); // -> 首先fn1通过原型链机制找到Function.prototype上的call方法,并且让call方法执行,
// -> 此时call这个方法中的this就是要操作fn1 -> 在call方法代码的执行过程中,首先fn1中的"this关键字"变为fn2,
// 再让fn1这个方法执行 -> 最终执行结果为 1
fn1.call.call(fn2); // -> fn1.call 首先fn1通过原型链机制找到Function.prototype上的call方法,
// 然后再让call方法通过原型再找到Function原型上的call(因为call本身的值也是一个函数,所以同样可以找到Function.prototype),在
// 第二次再找到call的时候,让方法执行,方法中的this是fn1.call, 首先让这个方法中的this变为fn2,然后再让fn1.call执行
// -> 输出结果为 2
再次分析:
function xxx(context) {
// 1. 让this这个函数中的"this关键字"变为context
// 2. 让this方法执行
this();
}
Function.prototype.myCall = xxx;
fn1.call.call(fn2);
// -> fn1.call -> xxx;
// -> xxx.call(fn2) -> 先让call方法执行,call中this是xxx,让xxx中的this变为fn2,
// 再让xxx执行 -> 2
fn1.call.call.call.call.call(fn2); // 2
Function.prototype.call(fn1); // Funciton.prototype是空函数,将其执行就是空函数执行,直接销毁
Function.prototype.call.call.call.call(fn1); // fn1() -> 1