每一个函数(普通函数/构造函数/内置类)都是Function这个内置类的实例
所以函数. _proto === Function.prototype.函数可以直接调取 Functio 的方法_
//Function.prototype ==> function anonymous(){}
/*
call/ apply/ bind
原型上提供的三个属性和方法
每一个函数都可以调用这个方法执行
这些方法都可以改变函数的this指向
*/
function fn(){}
fn.call(); // fn函数基于原型链查找到Function.prototype上的call方法,并且执行(执行的是call方法:方法中的this是fn)
fn.call.call(); //fn.call本身就是Funcion.prototype上的call方法,也是一个函数,只要是函数就能用原型上的方法,所以可以继续调用call来执行
Function.prototype.call = function $1(){
//...
}
fn.call =>$1;
fn.call() =>$1() this:fn;
//实例.方法()都是找到原型上的内置方法,让内置方法执行(只不过执行的时候做了一些事情,就会对实例产生改变,而这也这些内置方法的作用)内置方法的this一般都是当前操作的实例
call方法
语法:函数.call([context],[params],….)
函数基于原型链找到Function.prototype.call方法,并且把它执行,在call方法执行的时候完成了一些功能
- 让当前函数执行
- 把函数中的this指向改为第一个传递给call的实参
- 把传递给call其余的实参当做参数传递给当前函数
如果执行call一个实参都没有传递,非严格模式下是让函数中的this执行window,严格模式下指向undefined
window.name = 'WINDOW';
let obj = { name: 'obj' }
let fn = function (n,m) {
console.log(this.name); //WINDOW
}
// console.log(obj.fn()); // obj中并没有fn这个属性
// 需要:想让fn执行的时候,方法fn中的this指向obj ,可此时obj并没有属性,
// obj.fn = fn; 我们可以手动添加
// delete obj.fn 执行完后还需要删除这个属性,非常麻烦
fn.call(obj); //fnthis指向obj,如果不传参默认执行window 严格模式为undefined
fn.call(obj,10,20) // this: obj ,n =10, m=20
fn.call(10,20); // this:10 n = 20, m undefined
fn.call(null);// this: window,严格模式下null(第一个参数传递,是null/undefined/不传。非严格模式下传递的是谁,this执行谁,不穿this就是undefined_
用原生JavaScript实现函数内置call方法
~function () {
/*
call:改变函数中的this指向
*/
function call(context) {
contest = context||window;
// this:sum,也就是当前操作的这个函数的实例
let args = [],
result;
for (let i = 1; i < arguments.length; i++) { //除第一个参数外剩余传递的信息值
args.push(arguments[i]);
}
context.$fn = this; //我们给context对象设置一个fn的方法,将sum方法= fn方法,就达到了sum的this指向了context的效果
// 用result接收函数的结果
result = context.$fn(...args); // 展开运算符es6语法,把数组每一项传递给函数
delete context.$fn;
return result
}
// 扩展到内置类的原型上
Function.prototype.call = call; //把内置的call也给干没了;正常来写我们定义的call需要加前缀 mycall
}()
let obj = {
name: 'obj'
}
function sum(n, m) {
console.log(this);
return n + m;
}
let total = sum.call(obj, 1, 2);
console.log(total);