JS手写-this绑定实现

在 JavaScript 中,bindcallapply 方法都可以用来改变函数的 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>

详细步骤

  1. 实现 myBind

    • 检查调用者是否为函数。
    • 获取上下文 context 和传入的参数 args
    • 返回一个新的函数 bound,在调用时使用 apply 方法设置 this 值并传递参数。
  2. 实现 myCall

    • 检查调用者是否为函数。
    • 获取上下文 context 和传入的参数 args
    • 将函数赋值给 context 的一个临时属性 fn,调用该属性并传递参数,然后删除该属性。
  3. 实现 myApply

    • 检查调用者是否为函数。
    • 获取上下文 context 和传入的参数数组 args
    • 将函数赋值给 context 的一个临时属性 fn,调用该属性并传递参数,然后删除该属性。

测试

  1. 使用 myBind

    • 创建一个绑定了 obj 上下文的新函数 greetBound,并调用它。
  2. 使用 myCall

    • 直接调用 greet 函数,并设置 objthis 值。
  3. 使用 myApply

    • 直接调用 greet 函数,并设置 objthis 值,参数以数组形式传递。
相关推荐
早點睡3904 分钟前
ReactNative项目OpenHarmony三方库集成实战:react-native-localize
javascript·react native·react.js
棋鬼王12 分钟前
Cesium(十) 动态修改白模颜色、白模渐变色、白模光圈特效、白模动态扫描光效、白模着色器
前端·javascript·vue.js·智慧城市·数字孪生·cesium
酉鬼女又兒14 分钟前
零基础快速入门前端蓝桥杯Web备考:BOM与定时器核心知识点详解(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·javascript·职场和发展·蓝桥杯
望眼欲穿的程序猿15 分钟前
MacOS自定义安装Rust
开发语言·macos·rust
ThridTianFuStreet小貂蝉15 分钟前
面试题1:请系统讲讲 Vue2 与 Vue3 的核心差异(响应式、API 设计、性能与编译器)。
前端·javascript·vue.js
wjs202419 分钟前
CSS 动画:深入浅出的探索与实践
开发语言
wjs202424 分钟前
二分搜索树
开发语言
沐知全栈开发29 分钟前
Memcached delete 命令详解
开发语言
lly20240630 分钟前
Lua 基本语法
开发语言
竹林81837 分钟前
在NFT项目中集成IPFS:从Pinata上传到前端展示的完整实战与踩坑
前端·javascript