手写 apply 函数和call函数和bind函数

 apply&call

Function.prototype.myApply = function (context, args) {
// 不同点一:call函数需要把参数写成rest参数(...args)
//Function.prototype.myCall = function (context, ...args) {
    // 如果 context 为 null 或 undefined,则设置为 globalThis
    context = context || globalThis;

    // 创建一个唯一的属性名,防止覆盖原有属性
    const fnSymbol = Symbol();

    // 将当前函数(this)赋值给 context 对象的临时属性
    context[fnSymbol] = this;

    // 调用该函数并保存结果
    const result = context[fnSymbol](...(args || []));

    // 删除 context 中的临时属性
    delete context[fnSymbol];

    // 返回结果
    return result;
};

// 测试代码
function greet(greeting, punctuation) {
    return `${greeting}, ${this.name}${punctuation}`;
}

const person = {
    name: 'Alice'
};

// 使用 myApply
const result = greet.myApply(person, ['Hello', '!']);
// 不同点二:call函数需要把参数写成以,分割的形式而不是数组
//const result = greet.myCall(person, 'Hello', '!');

console.log(result); // 输出: "Hello, Alice!"

解释

  1. 设置上下文

    • context = context || globalThis;:确保如果传入的 contextnullundefined,则将其设置为全局对象 globalThis
  2. 创建唯一属性名

    • const fnSymbol = Symbol();:使用 Symbol 创建一个唯一的属性名,以防止覆盖 context 对象上的任何现有属性。
  3. 将函数绑定到上下文

    • context[fnSymbol] = this;:将当前函数(this)赋值给 context 对象的临时属性,使用唯一的符号属性名 fnSymbol
  4. 调用函数并传递参数

    • const result = context[fnSymbol](...(args || []));:使用展开运算符(...)来传递参数数组 args。如果 argsnullundefined,则使用空数组。
  5. 清理

    • delete context[fnSymbol];:删除添加到 context 对象的临时属性,避免对原始对象的污染。
  6. 返回结果

    • return result:返回调用函数的结果。

使用示例

以下是另一个使用 myApply 的示例:

function add(a, b) {
    return a + b;
}

const result = add.myApply(null, [5, 10]);
console.log(result); // 输出: 15

bind

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手写 bind 函数示例</title>
    <style>
        #content {
            height: 2000px;
            background: linear-gradient(to bottom, #ffefba, #ffffff);
        }
    </style>
</head>
<body>
    <div id="content">
        <h1>查看控制台以了解手写 bind 函数的输出</h1>
    </div>
    <script>
        Function.prototype.myBind = function (context, ...args) {
            // 保存 this,即调用 myBind 的函数
            const fn = this;

            // 返回一个新的函数
            const boundFunction = function (...newArgs) {
                // 检查新函数是否作为构造函数使用
                if (this instanceof boundFunction) {
                    // 如果是构造函数,则使用 this 作为上下文,并忽略传入的 context
                    return new fn(...args, ...newArgs);
                } else {
                    // 如果不是构造函数,则使用指定的 context
                    return fn.apply(context, [...args, ...newArgs]);
                }
            };

            // 将原型链连接到绑定的函数
            boundFunction.prototype = Object.create(fn.prototype);

            return boundFunction;
        };

        // 测试代码
        function Greet(greeting, punctuation) {
            this.name = 'Alice';
            this.message = `${greeting}, ${this.name}${punctuation}`;
        }

        const person = {
            name: 'Bob'
        };

        // 使用 myBind
        const BoundGreet = Greet.myBind(person, 'Hello');

        // 使用 new 操作符创建一个新的实例
        const instance = new BoundGreet('!');
        console.log(instance.message); // 输出: "Hello, Alice!"

        // 检查是否为实例
        console.log(instance instanceof Greet); // 输出: true

        console.log(person,'person') //  'jsCode.html:61 {name: 'Bob'} 'person''

    </script>
</body>
</html>

原型和原型链的理解

// 定义一个构造函数
function Animal(name) {
    this.name = name;
}

// 在原型上添加方法
Animal.prototype.speak = function() {
    console.log(`${this.name} makes a noise.`);
};

// 创建一个实例
const dog = new Animal('Dog');

dog.speak(); // 输出:Dog makes a noise.

console.log(dog.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
  1. dogAnimal 的一个实例。
  2. dog.__proto__ 指向 Animal.prototype
  3. Animal.prototype.__proto__ 指向 Object.prototype
  4. Object.prototype.__proto__ 指向 null,即原型链的终点。

通过这些关系,我们可以看到 dog 可以访问 Animal.prototype 上的 speak 方法,而如果 Animal.prototype 没有这个方法,它会继续查找 Object.prototype

总结

  • 原型(Prototype) 是一个对象,它被其他对象用来继承属性和方法。
  • 原型链(Prototype Chain) 是由对象及其原型组成的链,通过它可以实现属性和方法的继承。
  • 每个对象都有一个 __proto__ 属性,指向其构造函数的 prototype 对象。
  • 原型链的终点是 Object.prototype,它的 __proto__null
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值