webVueBlog/mini-vue

1.手写call和apply

webVueBlog opened this issue · 0 comments

call的场景是什么呢?每次写一个api,肯定得先知道他的用途才可以。

一句话介绍call:call()方法在使用 一个指定的this值 和 “若干个”指定的参数值 的前提下调用某个函数或方法。

var foo = {
 value: 'dada'
};

function bar() {
 console.log(this.value);
};

bar.call(foo); // dada;
bar(foo); // undefined;

注意两点:

  1. call改变了this的指向,指向到foo
  2. bar函数执行了

模拟一下:

思路:

  1. 将函数设为对象的属性
  2. 执行该函数
  3. 删除该函数
// call()手写
Function.prototype.myCall = function(context) {
 // 判断参数context 如果不存在 则为window;
 context = context || window;

 // 赋值函数 this
 context.func = this;

 // 获取参数
 let args = [...arguments].slice(1);

 // 获取结果
 let result = context.func(...args);

 // 删除属性
 delete context.func;

 // 返回结果
 return result;
}
// 手写apply
Function.prototype.myApply = function(context) {
 context = context || window;
 context.func = this;

 let result
 if(arguments[1]) {
  result = context.func(...arguments[1]);
 } else {
  result = context.func();
 }
 
 delete context.func;
 return result;
}
// 手写apply
Function.prototype.myApply = function(context, args) {
 context = context || window;
 context.func = this;

 let result = null;
 if(args.length === 0) {
  result = context.func();
 } else {
  result = context.func(...args);
 }

 delete context.func;
 return result;
}

call的实现:

Function.prototype.myCall = function(context, ...arguments) {
 context = context || window; // call不传值默认为window
 context.func = this;
 const result = context.func(...arguments);
 delete context.func;
 return result;
};

apply的实现:

Function.prototype.myApply = function(context, ...arguments) {
 context = context || window;
 context.func = this;
 arguments = arguments || [];
 let result = context.func(...arguments);
 delete context.fn;
 return result;
}

call和apply的使用

  1. 函数原型上的方法
  2. call,apply第一个参数都是上下文 改变this指向
  3. call第二个参数开始,接受数组展开项目
  4. apply第二个参数开始,接受一个数组
  5. 返回值:返回 调用函数的返回值
interface ThisArg {
 fn: Function
}

declare global {
 interface Winodw {
  fn: Function
 }
}

function Call(thisArg: ThisArg, ...args: any[]) {
 const context = thisArg || window
 context.fn = this
 const result = thisArg.fn(...args)
 delete thisArg.fn
 return result
}

function Apply(thisArg: ThisArg, args: any[]) {
 const context = thisArg || window
 context.fn = this

 let result
 
 if(!args.length) {
  result = context.fn()
 } else {
  result = contextfn(...args)
 }
 
 delete thisArg.fn
 return result
}

实现**,通过 object 中函数 可以改变 this 的指向

const obj = {
 value: 'dada',
 func: function() {
  console.log(this.value);
 }
}
obj.func(); // dada

默认值:

Function.prototype.myCall = function(context = window, ...args) {
 const fnKey = Symbol('fn');
 context[fnKey] = this;
 const result = context[fnKey](...args);
 delete context[fnKey];
 return result;
}
Function.prototype.myApply = function(context = window, args=[]) {
 const fnKey = Symbol('fn');
 context[fnKey] = this;
 const result = context[fnKey](...args);
 delete context[fnKey];
 return result;
}

简写版本的call和apply手写 💯

Function.prototype.myCall = function(context) {
 const context = Object(context) || window;
 context.fn = this;
 let args = [];
 for(let i = 1, len = arguments.length; i < len; i++) {
  args.push('arguments[' + i + ']');
 }
 var result = eval('context.fn(' + args + ')‘);
 delete context.fn;
 return result;
}
Function.prototype.myApply = function(context, arr) {
 const const = Object(context) || window;
 context.fn = this;
 let result;
 if(!arr) {
  result = context.fn();
 } else {
  let args = [];
  for(let i = 0, len = arr.length; i < len; i++) {
   args.push('arr[' + i + ']');
  }
  result = eval('context.fn(' + args + ')');
 }
 delete context.fn;
 return result;
}