call apply bind

348 阅读1分钟
  • call call的特点
  1. 可以改变当前函数this的指向
  2. 让当前函数执行
function fn1(){
    console.log(this)
}
fn1.call()
结果是:window

如果传值

function fn1(){
    console.log(this,arguments)
}
fn1.call('jeffywin',1,2)
结果是:jeffywin,Arguments(2)[1,2]
function fn1() {
    console.log(1)
}

function fn2() {
    console.log(2)
}
//fn1的this指向fn2,并且让fn1执行
fn1.call(fn2)
结果是:1this指向fn2

原理类似于
Function.prototype.call = function(context) {
  this() //会让当前函数的this指向fn2,fn2执行 
}
fn1.call.call(fn2)
结果是:2
Function.prototype.callBind = function(context) {
    context = context ? Object(context) : window
    //context: hello 上下文
    //arguments ['hello',1,2]
    //this = fn1()
    //如果要让this='hello',fn1执行的时候,xxx.fn1() .前面是谁,this就指向谁,这里context上下文就是hello
    //所以让context转成对象,(字符串不能.fn1())再挂上fn1(),这样this就指向hello
    //eval('context.fn('+args+')')执行的时候,因为context.fn = fn1,所以context.fn()执行相当于fn1执行,this指向context,也就是hello
    context.fn = this //{}.fn = fn1  context.fn=fn1
    let args = []
    for(let i=1;i<arguments.length;i++) {
        args.push('arguments['+i+']')
    }
    //context.fn(arguments[1],arguments[2])
    //eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
    let r = eval('context.fn('+args+')')//实际就是执行 this( [args] )
    
    delete context.fn
    return r 
}
fn1.callBind('hello',1,2)

Function.prototype.ccall = function(context) {
    context = context ? Object(context) : window
    context.fn = this

    let args = [...arguments].slice(1) //[1,2]
    let r = context.fn(...args)
    delete context.fn
    return r  
}

function fn1(){
    console.log(this,arguments)
}
fn1.ccall('jeffywin',1,2)

//apply实现
Function.prototype.applyBind = function(context,args) {
    context = context ? Object(context) : window
    context.fn = this 
    if(!args) {
       return context.fn()
    }
    let r = eval('context.fn('+args+')')
    delete context.fn
    return r 
}

fn1.applyBind('hello',[1,2])

Function.prototype.myApply = function (context) {
    context = context ? Object(context) : window
    context.fn = this
    var result
    if (arguments[1]) {
      result = context.fn(...arguments[1])
    } else {
      result = context.fn()
    }
  
    delete context.fn
    return result
  }
  function fn1(){
    console.log(this,arguments)
}

//1) bind方法可以绑定this指向 绑定参数
//2) bind方法返回一个绑定后的函数 原理:高阶函数
//3) 如果绑定的函数被new了,当前函数的this就是当前的实例
//4) new 出来的结果可以找出原有类的原型
Function.prototype.bindMy = function (context) {
  let that = this;
  let bindArgs = Array.prototype.slice.call(arguments, 1);//['猫']
  //this:fn context:obj
  function Fn(){}
  function fBound() {
    let args = Array.prototype.slice.call(arguments)
    return that.apply(this instanceof fBound ? this : context, bindArgs.concat(args))
  }
  Fn.prototype = this.prototype
  fBound.prototype = new Fn()
  return fBound
}

Function.prototype.myBind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  const _this = this
  const args = [...arguments].slice(1)
  // 返回一个函数
  return function F() {
    // 因为返回了一个函数,我们可以 new F(),所以需要判断
    if (this instanceof F) {
      return new _this(...args, ...arguments)
    }
    return _this.apply(context, args.concat(...arguments))
  }
}

Function.prototype.fakeBind = function (obj, ...args) {
  return (...rest) => this.call(obj, ...args, ...rest);
};

let obj = {
  name: 'jeffywin'
}

function fn(name, age) {
  console.log(this.name + '养了一只' + name + age + '岁了')
}
fn.prototype.flag="哺乳类"
let bindFn = fn.bindMy(obj, '猫')
//bindFn(9)
let i = new bindFn(9)
console.log(i.flag)

//在计算机科学中,柯里化(Currying)是把接受多个参数的函
//数变换成接受一个单一参数(最初函数的第一个参数)的函数,
//并且返回接受余下的参数且返回结果的新函数的技术
var add = function(x) {
  return function(y) {
    return x + y;
  };
};

var increment = add(1);
var addTen = add(10);

increment(2);
// 3
addTen(2);
// 12

实现map循环

Array.prototype.newMap = function newMap(fn, context) {
    if (typeof fn !== "function") {
      throw new TypeError(`${fn} is not a function`);
    }
    //fn v=>v+1
    let arr = this;
    let temp = [];
    for (let i = 0; i < arr.length; i++) {
      // 迭代执行
      let result = fn.call(context, arr[i]);
      temp.push(result);
    }
    return temp;
  };