Javascript中Function对象研究_01_Function()构造函数_实例方法_手写模拟实现_apply_bind_call_研究_[Symbol.hasInstance]()

JavaScript中Function对象研究_01_Function()构造函数_实例方法_手写模拟实现_apply、bind、call、研究_Symbol.hasInstance

在JavaScript中,Function对象是构建函数和实现高阶编程的重要组成部分。理解Function对象的工作原理,以及如何使用和模拟其方法,对于深入掌握JavaScript语言至关重要。本文将深入研究Function对象,包括Function()构造函数、实例方法,以及手写模拟实现applybindcall方法,并探讨[Symbol.hasInstance]()的作用和实现。

一、Function() 构造函数

1. 基础介绍

Function构造函数用于创建一个新的函数对象。直接使用Function构造函数创建函数并不常见,因为它会使代码难以维护,但理解其工作原理有助于更深入地了解JavaScript的函数机制。

2. 语法

new Function ([arg1[, arg2[, ...argN]],] functionBody)
  • arg1, arg2, … argN:用于函数的参数名称。每个参数都是一个字符串。
  • functionBody:一个字符串,表示函数的函数体。

3. 示例代码

示例1:创建一个简单的函数
const add = new Function('a', 'b', 'return a + b');

console.log(add(2, 3)); // 输出: 5
示例2:动态创建函数
const args = 'x, y';
const body = 'return x * y;';
const multiply = new Function(args, body);

console.log(multiply(4, 5)); // 输出: 20

4. 注意事项

  • 安全性:使用Function构造函数相当于使用eval(),会解析传入的字符串,有可能导致安全风险,建议避免使用。
  • 作用域:使用Function构造函数创建的函数在全局作用域中运行,无法访问创建它的上下文作用域。
const a = 10;

function createFunction() {
  const b = 20;
  return new Function('return a + b;');
}

const func = createFunction();

console.log(func()); // 报错:b 未定义

二、Function.prototype 实例方法

Function对象的原型上定义了一些方法,可以被所有函数实例使用。这些方法包括:

  • apply()
  • bind()
  • call()
  • [Symbol.hasInstance]

1. apply()

1.1 基础介绍

apply()方法调用一个函数,具有指定的this值和参数数组。

1.2 语法
func.apply(thisArg, [argsArray])
  • thisArg:调用函数时的this值。
  • argsArray:一个数组或类数组对象,包含调用函数时传入的参数。
1.3 示例代码
function greet(greeting, punctuation) {
  return `${greeting}, ${this.name}${punctuation}`;
}

const person = { name: 'Alice' };

console.log(greet.apply(person, ['Hello', '!'])); // 输出: Hello, Alice!

2. call()

2.1 基础介绍

call()方法调用一个函数,具有指定的this值和单独提供的参数列表。

2.2 语法
func.call(thisArg, arg1, arg2, ...)
2.3 示例代码
function introduce(age, city) {
  return `${this.name}, ${age} years old, from ${city}`;
}

const person = { name: 'Bob' };

console.log(introduce.call(person, 25, 'New York'));
// 输出: Bob, 25 years old, from New York

3. bind()

3.1 基础介绍

bind()方法创建一个新的函数,在调用时将this关键字设置为提供的值,在调用新函数时,给定的参数列表将置于实参之前。

3.2 语法
const boundFunction = func.bind(thisArg[, arg1[, arg2[, ...]]])
3.3 示例代码
function say(message) {
  return `${this.name} says: ${message}`;
}

const person = { name: 'Charlie' };

const sayFromCharlie = say.bind(person);

console.log(sayFromCharlie('Hello!')); // 输出: Charlie says: Hello!

三、手写模拟实现 apply、call、bind

为了深入理解applycallbind的工作原理,我们尝试手写模拟实现它们。

1. 模拟实现 apply()

Function.prototype.myApply = function (thisArg, argsArray) {
  // 如果thisArg为null或undefined,指向全局对象(浏览器中为window,严格模式下为undefined)
  thisArg = thisArg || globalThis;
  // 为thisArg创建一个独特的属性,避免覆盖原有属性
  const fnSymbol = Symbol();
  thisArg[fnSymbol] = this;
  // 执行函数
  const result = thisArg[fnSymbol](...argsArray);
  // 删除临时属性
  delete thisArg[fnSymbol];
  return result;
};
示例验证
function sum(a, b) {
  return a + b + this.c;
}

const obj = { c: 10 };

console.log(sum.myApply(obj, [2, 3])); // 输出: 15

2. 模拟实现 call()

Function.prototype.myCall = function (thisArg, ...args) {
  thisArg = thisArg || globalThis;
  const fnSymbol = Symbol();
  thisArg[fnSymbol] = this;
  const result = thisArg[fnSymbol](...args);
  delete thisArg[fnSymbol];
  return result;
};
示例验证
function multiply(a, b) {
  return a * b * this.d;
}

const obj = { d: 2 };

console.log(multiply.myCall(obj, 4, 5)); // 输出: 40

3. 模拟实现 bind()

Function.prototype.myBind = function (thisArg, ...args) {
  const self = this;
  return function (...innerArgs) {
    return self.apply(thisArg, args.concat(innerArgs));
  };
};
示例验证
function greet(greeting, punctuation) {
  return `${greeting}, ${this.name}${punctuation}`;
}

const person = { name: 'Dave' };

const greetDave = greet.myBind(person, 'Hi');

console.log(greetDave('!')); // 输出: Hi, Dave!

4. 注意事项

  • thisArgnullundefinedthis指向全局对象,但在严格模式下为undefined
  • 使用Symbol防止属性冲突:为了避免覆盖对象原有属性,使用Symbol创建独特的属性名。

四、Symbol.hasInstance 的研究

1. 基础介绍

Symbol.hasInstance是一个内置的Symbol,指向一个函数,当使用instanceof运算符时,会调用该函数。通过自定义Symbol.hasInstance,可以改变instanceof的行为。

2. 语法

class MyClass {
  static [Symbol.hasInstance](instance) {
    // 自定义逻辑
    return true or false;
  }
}

3. 示例代码

示例1:自定义instanceof行为
class EvenNumber {
  static [Symbol.hasInstance](obj) {
    return Number(obj) % 2 === 0;
  }
}

console.log(2 instanceof EvenNumber); // 输出: true
console.log(3 instanceof EvenNumber); // 输出: false
示例2:函数的[Symbol.hasInstance]
function Range(start, end) {
  this.start = start;
  this.end = end;
}

Range[Symbol.hasInstance] = function (obj) {
  return obj >= this.start && obj <= this.end;
};

const range = new Range(10, 20);

console.log(15 instanceof range); // 输出: true
console.log(25 instanceof range); // 输出: false

4. 实现原理

  • 当使用instanceof运算符时,JavaScript引擎会检查右操作数的Symbol.hasInstance方法。
  • 如果存在Symbol.hasInstance方法,则调用该方法,传入左操作数作为参数。
  • 返回值决定了instanceof表达式的结果。

5. 注意事项

  • 只能用于函数或类:因为只有函数和类才能拥有Symbol.hasInstance方法。
  • 影响instanceof行为:自定义Symbol.hasInstance会改变instanceof的默认行为,需谨慎使用。

学习收获

  • Function()构造函数:理解了如何使用Function构造函数动态创建函数,以及其安全和作用域的注意事项。
  • apply、call、bind:掌握了这三个方法的区别和用法,通过手写模拟实现,深入理解了它们的内部工作原理。
  • [Symbol.hasInstance]:了解了如何自定义instanceof运算符的行为,掌握了Symbol.hasInstance的使用方法。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

It'sMyGo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值