Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

js中call和apply的模拟实现 #28

Open
2018212632 opened this issue Oct 22, 2020 · 0 comments
Open

js中call和apply的模拟实现 #28

2018212632 opened this issue Oct 22, 2020 · 0 comments
Labels

Comments

@2018212632
Copy link
Owner

js中call和apply的模拟实现

call

call()方法,函数A调用call()方法,传递一个this指向的函数或方法,从而改变函数A的this指向

var foo =  {
    value : 1
}

function bar() {
    console.log(this.value)
}
bar.call(foo) // 1

发生了什么:

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

call的模拟

模拟的步骤可以为:

  1. 将函数设为对象的属性
  2. 执行该函数
  3. 删除这个属性

一些需要考虑的边界情况:

  1. 如果call2()中调用的函数有多个参数,arguments = [foo, arg1, arg2, ...args],提出需要执行的参数args = [arg1, arg2, ...args];
  2. 如果call2()中传入null,那么此时this指向window
  3. 函数是有return的情况的,返回一个执行完的结果即可
Function.prototype.call2 = function(context) {
    context = context || window
    // this是调用call2的函数,也就是需要执行的函数bar
    context.fn = this

    const args = []
    for(let i=1; i<arguments.length; i++) {
        args.push(arguments[i])
    }

    const result = context.fn(...args)

    delete context.fn

    return result
}

var value = 1

var foo = {
    value: 2
}

function bar(age, name) {
    console.log(this.value)
    return {
        age: age,
        name: name,
        value: this.value
    }
}

bar.call2(null) // 1

bar.call2(foo, 20, 'tom')
// Object = {
//    age: 20
//    name: "tom"
//    value: 2
//}

apply的模拟实现

apply与call实现本质没有太大区别,唯一区别在于传参时apply可以传类数组对象

Function.prototype.apply2 = function(context) {
    context = context || window
    // this是调用call2的函数,也就是需要执行的函数bar
    context.fn = this
    
    var result
    if(arguments.length==1) {
        result = context.fn()
    } else{
        // apply接收一个参数数组
        const args = arguments[1]
        const result = context.fn(...args)
    }

    delete context.fn
    return result
}

apply的常见应用

将一个数组添加到另一个数组

var arr1 = [1,2,3]
var arr2 = [4,5,6]

arr1.push.apply(arr1, arr2)
console.log(arr1) // [1, 2, 3, 4, 5, 6]

获取数组最大或最小值

/* 找出数组中最大/小的数字 */
var numbers = [5, 6, 2, 3, 7];

var max = Math.max.apply(null, numbers); 
var min = Math.min.apply(null, numbers);

如果数组长度大于参数限制,会出现预期不对。可以将数组分块来循环使用该方法:

function minOfArray(arr) {
  var min = Infinity; // 无穷大
  var QUANTUM = 32768; // 参数上限长度

  for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
    var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
    min = Math.min(submin, min);
  }

  return min;
}

var min = minOfArray([5, 6, 2, 3, 7]);
@2018212632 2018212632 added the js label Oct 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant