# 类
# 事件发射器
设计一个 EventEmitter 类。这个接口与 Node.js 或 DOM 的 Event Target 接口相似,但有一些差异。EventEmitter 应该允许订阅事件和触发事件。
你的 EventEmitter 类应该有以下两个方法:
- subscribe - 这个方法接收两个参数:一个作为字符串的事件名和一个回调函数。当事件被触发时,这个回调函数将被调用。 一个事件应该能够有多个监听器。当触发带有多个回调函数的事件时,应按照订阅的顺序依次调用每个回调函数。应返回一个结果数组。你可以假设传递给 subscribe 的回调函数都不是引用相同的。 subscribe 方法还应返回一个对象,其中包含一个 unsubscribe 方法,使用户可以取消订阅。当调用 unsubscribe 方法时,回调函数应该从订阅列表中删除,并返回 undefined。
- emit - 这个方法接收两个参数:一个作为字符串的事件名和一个可选的参数数组,这些参数将传递给回调函数。如果没有订阅给定事件的回调函数,则返回一个空数组。否则,按照它们被订阅的顺序返回所有回调函数调用的结果数组。
# 示例 1:
输入:
actions = ["EventEmitter", "emit", "subscribe", "subscribe", "emit"],
values = [[], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent"]]
输出:
[[],["emitted",[]],["subscribed"],["subscribed"],["emitted",[5,6]]]
解释:
const emitter = new EventEmitter();
emitter.emit("firstEvent"); // [], 还没有订阅任何回调函数
emitter.subscribe("firstEvent", function cb1() { return 5; });
emitter.subscribe("firstEvent", function cb2() { return 6; });
emitter.emit("firstEvent"); // [5, 6], 返回 cb1 和 cb2 的输出
输入:
actions = [“EventEvent”,“emit”,“subscribe”,“subscribe”,“emit”]
,values = [[],[“firstEvent”,“function cb1(){ return 5; }"],[“firstEvent”,“function cb1(){ return 5; }"],[“firstEvent”]]
输出:
[[],[“emitted”,[]],[“subscribed”],[“subscribed”],[“emitted”,[5,6]解释说明:const emitter = new EventEmitter();
emitter.emit(“firstEvent”); // [],还没有订阅任何回调函数 emitter.subscribe(“first Event”,function cb1(){ return 5;
});
(“firstEvent”,function cb2(){ return 6; }); emitter.emit(“firstEvent”); // [5,6],返回 cb1 和 cb2 的输出
# 示例 2:
输入:
actions = ["EventEmitter", "subscribe", "emit", "emit"],
values = [[], ["firstEvent", "function cb1(...args) { return args.join(','); }"], ["firstEvent", [1,2,3]], ["
firstEvent", [3,4,6]]]
输出:
[[],["subscribed"],["emitted",["1,2,3"]],["emitted",["3,4,6"]]]
解释:
注意 emit 方法应该能够接受一个可选的参数数组。
const emitter = new EventEmitter();
emitter.subscribe("firstEvent, function cb1(...args) { return args.join(','); });
emitter.emit("firstEvent", [1, 2, 3]); // ["1,2,3"]
emitter.emit("firstEvent", [3, 4, 6]); // ["3,4,6"]
# 示例 3:
输入:
actions = ["EventEmitter", "subscribe", "emit", "unsubscribe", "emit"],
values = [[], ["firstEvent", "(...args) => args.join(',')"], ["firstEvent", [1,2,3]], [0], ["firstEvent", [4,5,6]]]
输出:[[],["subscribed"],["emitted",["1,2,3"]],["unsubscribed",0],["emitted",[]]]
解释:
const emitter = new EventEmitter();
const sub = emitter.subscribe("firstEvent", (...args) => args.join(','));
emitter.emit("firstEvent", [1, 2, 3]); // ["1,2,3"]
sub.unsubscribe(); // undefined
emitter.emit("firstEvent", [4, 5, 6]); // [], 没有订阅者
# 示例 4:
输入:
actions = ["EventEmitter", "subscribe", "subscribe", "unsubscribe", "emit"],
values = [[], ["firstEvent", "x => x + 1"], ["firstEvent", "x => x + 2"], [0], ["firstEvent", [5]]]
输出:[[],["subscribed"],["emitted",["1,2,3"]],["unsubscribed",0],["emitted",[7]]]
解释:
const emitter = new EventEmitter();
const sub1 = emitter.subscribe("firstEvent", x => x + 1);
const sub2 = emitter.subscribe("firstEvent", x => x + 2);
sub1.unsubscribe(); // undefined
emitter.emit("firstEvent", [5]); // [7]
# 包装数组
创建一个名为 ArrayWrapper 的类,它在其构造函数中接受一个整数数组作为参数。该类应具有以下两个特性:
- 当使用 + 运算符将两个该类的实例相加时,结果值为两个数组中所有元素的总和。
- 当在实例上调用 String() 函数时,它将返回一个由逗号分隔的括在方括号中的字符串。例如,[1,2,3] 。
# 示例 1:
输入:nums = [[1,2],[3,4]], operation = "Add"
输出:10
解释:
const obj1 = new ArrayWrapper([1,2]);
const obj2 = new ArrayWrapper([3,4]);
obj1 + obj2; // 10
# 示例 2:
输入:nums = [[23,98,42,70]], operation = "String"
输出:"[23,98,42,70]"
解释:
const obj = new ArrayWrapper([23,98,42,70]);
String(obj); // "[23,98,42,70]"
# 示例 3:
输入:nums = [[],[]], operation = "Add"
输出:0
解释:
const obj1 = new ArrayWrapper([]);
const obj2 = new ArrayWrapper([]);
obj1 + obj2; // 0
- 这个问题引入了 JavaScript 编程中一个有趣的方面:修改 JavaScript 的加法运算符(+)和 String() 函数的标准行为 ,以模仿其他编程语言中的行为。
- JavaScript 提供了特定的方法,具体来说是 valueOf() 和 toString(),它们影响对象与操作符的交互方式。这些方法是 JavaScript 的类型转换机制的一部分,可以在自定义对象中重写,以实现一定程度的操作符行为修改。
let obj = {
valueOf: function () {
return 5;
},
toString: function () {
return 'Hello';
}
};
console.log(obj + 2); // 7 - 由于 obj.valueOf()
console.log(String(obj)); // 'Hello' - 由于 obj.toString()
# String() 方法
JavaScript 中的 String() 函数是一个全局对象构造函数,用于将对象的字符串表示形式转换并返回。它可以用于将所有类型的 JavaScript 数据类型转换为字符串。例如,String(10) 会返回 '10',String(true) 会返回 'true'。
let num = 10;
let bool = true;
console.log(String(num)); // '10'
console.log(String(bool)); // 'true'
# toString() 方法
在 JavaScript 中,我们还可以通过在对象上提供自定义的 toString() 方法来修改 String() 的行为。
# valueOf() 方法
- JavaScript 中的 valueOf() 方法是一个内置函数,它返回指定对象的原始值。默认情况下,所有继承自 Object 的对象都继承了 valueOf() 方法。此方法可用于 Number、Boolean、Object、String 和 Date 对象。
- 当 JavaScript 尝试将对象转换为原始值(例如,在数学运算中),它首先在对象上调用 valueOf() 方法。如果 valueOf() 不返回原始值,JavaScript 将继续调用 toString() 方法。因此,通过覆盖 valueOf() 方法,你可以控制对象在数学运算中的行为,从而在一定程度上模拟操作符重载。
console.log({}.valueOf()) //{}
console.log(Number(1).valueOf()) //1
console.log("789".valueOf()) //789
console.log([].valueOf()) //[]
# 题解
class PackArray {
constructor(arr) {
this.arr = arr;
}
valueOf() {
return this.arr.reduce((a, b) => a + b, 0);
}
toString() {
return this.arr.join(",");
}
}
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const pack = new PackArray(arr1);
const pack2 = new PackArray(arr2);
console.log(pack + pack2)//21
console.log(pack.toString())//"1, 2, 3"