在 JavaScript 中,bind、call 和 apply 方法都可以用来改变函数的 this 指向。下面我们将分别实现这些方法的简单版本。
1. 实现 bind
bind 方法创建一个新的函数,在调用时设置 this 值,并返回这个新的函数。
            
            
              javascript
              
              
            
          
          Function.prototype.myBind = function (context) {
    if (typeof this !== 'function') {
        throw new TypeError('Not a function');
    }
    const fn = this;
    const args = Array.prototype.slice.call(arguments, 1);
    return function bound() {
        const boundArgs = Array.prototype.slice.call(arguments);
        return fn.apply(context, args.concat(boundArgs));
    };
};2. 实现 call
call 方法立即调用函数,并设置 this 值,同时传递参数列表。
            
            
              javascript
              
              
            
          
          Function.prototype.myCall = function (context) {
    if (typeof this !== 'function') {
        throw new TypeError('Not a function');
    }
    context = context || window;
    const args = Array.prototype.slice.call(arguments, 1);
    context.fn = this;
    const result = context.fn(...args);
    delete context.fn;
    return result;
};3. 实现 apply
apply 方法与 call 类似,但传递的参数是一个数组。
            
            
              javascript
              
              
            
          
          Function.prototype.myApply = function (context, args) {
    if (typeof this !== 'function') {
        throw new TypeError('Not a function');
    }
    context = context || window;
    args = args || [];
    context.fn = this;
    const result = context.fn(...args);
    delete context.fn;
    return result;
};示例代码
下面是一个完整的示例,展示了如何使用这些自定义的方法:
            
            
              html
              
              
            
          
          <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>自定义 bind, call, apply</title>
</head>
<body>
    <script type="text/javascript">
        Function.prototype.myBind = function (context) {
            if (typeof this !== 'function') {
                throw new TypeError('Not a function');
            }
            const fn = this;
            const args = Array.prototype.slice.call(arguments, 1);
            return function bound() {
                const boundArgs = Array.prototype.slice.call(arguments);
                return fn.apply(context, args.concat(boundArgs));
            };
        };
        Function.prototype.myCall = function (context) {
            if (typeof this !== 'function') {
                throw new TypeError('Not a function');
            }
            context = context || window;
            const args = Array.prototype.slice.call(arguments, 1);
            context.fn = this;
            const result = context.fn(...args);
            delete context.fn;
            return result;
        };
        Function.prototype.myApply = function (context, args) {
            if (typeof this !== 'function') {
                throw new TypeError('Not a function');
            }
            context = context || window;
            args = args || [];
            context.fn = this;
            const result = context.fn(...args);
            delete context.fn;
            return result;
        };
        // 测试对象
        const obj = {
            name: '牛客网'
        };
        // 测试函数
        function greet(message) {
            console.log(`${message}, ${this.name}`);
        }
        // 使用 myBind
        const greetBound = greet.myBind(obj, '欢迎来到');
        greetBound(); // 输出: 欢迎来到, 牛客网
        // 使用 myCall
        greet.myCall(obj, '欢迎来到'); // 输出: 欢迎来到, 牛客网
        // 使用 myApply
        greet.myApply(obj, ['欢迎来到']); // 输出: 欢迎来到, 牛客网
    </script>
</body>
</html>详细步骤
- 
实现 myBind:- 检查调用者是否为函数。
- 获取上下文 context和传入的参数args。
- 返回一个新的函数 bound,在调用时使用apply方法设置this值并传递参数。
 
- 
实现 myCall:- 检查调用者是否为函数。
- 获取上下文 context和传入的参数args。
- 将函数赋值给 context的一个临时属性fn,调用该属性并传递参数,然后删除该属性。
 
- 
实现 myApply:- 检查调用者是否为函数。
- 获取上下文 context和传入的参数数组args。
- 将函数赋值给 context的一个临时属性fn,调用该属性并传递参数,然后删除该属性。
 
测试
- 
使用 myBind:- 创建一个绑定了 obj上下文的新函数greetBound,并调用它。
 
- 创建一个绑定了 
- 
使用 myCall:- 直接调用 greet函数,并设置obj为this值。
 
- 直接调用 
- 
使用 myApply:- 直接调用 greet函数,并设置obj为this值,参数以数组形式传递。
 
- 直接调用