MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

JavaScript公认符号的自定义实现

2022-10-031.2k 阅读

JavaScript 公认符号概述

在 JavaScript 的编程世界里,存在着一系列被广泛认可和使用的符号,这些符号如同语言的基石,构建起了丰富多彩的代码逻辑。从简单的算术运算符(如 +-*/),到逻辑运算符(&&||!),再到比较运算符(><===)等,它们都有着明确且既定的功能。这些公认符号是 JavaScript 语言规范的重要组成部分,开发人员在日常编码中频繁使用它们来实现各种功能,从基本的数值计算到复杂的条件判断和逻辑控制。

然而,在某些特定场景下,开发人员可能需要对这些公认符号进行自定义实现。这可能出于多种目的,比如在特定领域的编程(DSL,Domain - Specific Language)中,希望通过自定义符号来实现更简洁、直观的代码表达;或者在一些实验性的编程探索中,尝试以不同的方式来诠释符号的语义。

自定义算术运算符

自定义加法运算符

JavaScript 中默认的加法运算符 + 用于数字相加以及字符串拼接。假设我们想要实现一个自定义的加法运算符,它不仅能处理常规数字相加,还能对数组元素进行求和,并且在对象相加时能将对象的数值属性相加。

首先,我们可以通过创建一个函数来模拟加法运算符的行为。

function customAdd(a, b) {
    if (typeof a === 'number' && typeof b === 'number') {
        return a + b;
    } else if (Array.isArray(a) && Array.isArray(b)) {
        let sumA = a.reduce((acc, val) => acc + val, 0);
        let sumB = b.reduce((acc, val) => acc + val, 0);
        return sumA + sumB;
    } else if (typeof a === 'object' && typeof b === 'object') {
        let sumA = 0;
        let sumB = 0;
        for (let key in a) {
            if (!isNaN(parseFloat(a[key])) && isFinite(a[key])) {
                sumA += a[key];
            }
        }
        for (let key in b) {
            if (!isNaN(parseFloat(b[key])) && isFinite(b[key])) {
                sumB += b[key];
            }
        }
        return sumA + sumB;
    } else {
        throw new Error('Unsupported types for customAdd');
    }
}
// 使用示例
console.log(customAdd(2, 3)); // 输出 5
console.log(customAdd([1, 2], [3, 4])); // 输出 10
console.log(customAdd({a: 1}, {b: 2})); // 输出 3

在上述代码中,customAdd 函数首先判断传入参数的类型。如果都是数字,直接进行常规加法;如果都是数组,先对数组元素求和再相加;如果都是对象,则对对象中的数值属性求和后相加。

自定义乘法运算符

默认的乘法运算符 * 用于数字相乘。我们来实现一个自定义乘法运算符,它可以处理矩阵乘法(假设矩阵以二维数组形式表示),同时也能处理常规数字乘法。

function customMultiply(a, b) {
    if (typeof a === 'number' && typeof b === 'number') {
        return a * b;
    } else if (Array.isArray(a) && Array.isArray(b)) {
        if (a[0].length!== b.length) {
            throw new Error('矩阵维度不匹配,无法相乘');
        }
        let result = [];
        for (let i = 0; i < a.length; i++) {
            result[i] = [];
            for (let j = 0; j < b[0].length; j++) {
                let sum = 0;
                for (let k = 0; k < b.length; k++) {
                    sum += a[i][k] * b[k][j];
                }
                result[i][j] = sum;
            }
        }
        return result;
    } else {
        throw new Error('Unsupported types for customMultiply');
    }
}
// 使用示例
console.log(customMultiply(2, 3)); // 输出 6
let matrixA = [[1, 2], [3, 4]];
let matrixB = [[5, 6], [7, 8]];
console.log(customMultiply(matrixA, matrixB)); 
// 输出 [[19, 22], [43, 50]]

这里的 customMultiply 函数,当参数为数字时执行常规乘法。当参数为二维数组(矩阵)时,按照矩阵乘法规则进行计算。

自定义逻辑运算符

自定义逻辑与运算符

JavaScript 中的逻辑与运算符 && 用于逻辑判断,当所有操作数都为真时返回最后一个操作数,否则返回第一个假值操作数。我们来实现一个自定义的逻辑与运算符,它在执行逻辑与操作时,还能记录每个操作数的判断次数。

function customAnd(...args) {
    let count = {};
    for (let i = 0; i < args.length; i++) {
        if (!count[args[i]]) {
            count[args[i]] = 1;
        } else {
            count[args[i]]++;
        }
        if (!args[i]) {
            console.log('判断次数:', count);
            return args[i];
        }
    }
    console.log('判断次数:', count);
    return args[args.length - 1];
}
// 使用示例
console.log(customAnd(true, 1, false, 'test')); 
// 输出 false,同时打印判断次数: {true: 1, '1': 1, false: 1, 'test': 0}

customAnd 函数中,通过遍历参数,使用一个对象 count 记录每个操作数的判断次数。一旦遇到假值操作数,就返回该操作数并打印判断次数。如果所有操作数都为真值,则返回最后一个操作数并打印判断次数。

自定义逻辑或运算符

逻辑或运算符 || 在 JavaScript 中,只要有一个操作数为真就返回该操作数,否则返回最后一个假值操作数。我们自定义一个逻辑或运算符,它在执行逻辑或操作时,能返回每个操作数的真值情况。

function customOr(...args) {
    let result = {
        values: [],
        truthy: []
    };
    for (let i = 0; i < args.length; i++) {
        result.values.push(args[i]);
        result.truthy.push(Boolean(args[i]));
        if (args[i]) {
            return result;
        }
    }
    return result;
}
// 使用示例
let orResult = customOr(false, 0, 'test', true);
console.log(orResult); 
// 输出 {values: [false, 0, 'test', true], truthy: [false, false, true, true]}

customOr 函数中,通过遍历参数,将每个操作数及其真值情况分别记录在 result 对象的 valuestruthy 数组中。一旦遇到真值操作数,就返回 result 对象。

自定义比较运算符

自定义严格相等运算符

JavaScript 的严格相等运算符 === 用于判断两个值是否严格相等,包括类型和值。我们来实现一个自定义的严格相等运算符,它在判断时可以忽略特定类型的微小差异,比如在比较浮点数时可以设置一定的精度。

function customStrictEqual(a, b, epsilon = 0.0001) {
    if (typeof a!== typeof b) {
        return false;
    }
    if (typeof a === 'number') {
        return Math.abs(a - b) < epsilon;
    } else if (typeof a === 'object') {
        if (a === null && b === null) {
            return true;
        }
        if (Array.isArray(a) && Array.isArray(b)) {
            if (a.length!== b.length) {
                return false;
            }
            for (let i = 0; i < a.length; i++) {
                if (!customStrictEqual(a[i], b[i], epsilon)) {
                    return false;
                }
            }
            return true;
        } else {
            let keysA = Object.keys(a);
            let keysB = Object.keys(b);
            if (keysA.length!== keysB.length) {
                return false;
            }
            for (let key of keysA) {
                if (!customStrictEqual(a[key], b[key], epsilon)) {
                    return false;
                }
            }
            return true;
        }
    } else {
        return a === b;
    }
}
// 使用示例
console.log(customStrictEqual(1.00005, 1.0001)); // 输出 true
console.log(customStrictEqual([1, 2], [1, 2])); // 输出 true
console.log(customStrictEqual({a: 1}, {a: 1})); // 输出 true

customStrictEqual 函数中,首先判断类型是否相同。对于数字类型,通过设置精度 epsilon 来比较。对于对象类型,分别处理数组和普通对象的情况,递归调用自身进行比较。

自定义大于运算符

默认的大于运算符 > 用于比较两个数值的大小。我们实现一个自定义大于运算符,它可以对复杂数据结构进行比较,比如对包含数值属性的对象进行比较。

function customGreaterThan(a, b) {
    if (typeof a === 'number' && typeof b === 'number') {
        return a > b;
    } else if (typeof a === 'object' && typeof b === 'object') {
        let sumA = 0;
        let sumB = 0;
        for (let key in a) {
            if (!isNaN(parseFloat(a[key])) && isFinite(a[key])) {
                sumA += a[key];
            }
        }
        for (let key in b) {
            if (!isNaN(parseFloat(b[key])) && isFinite(b[key])) {
                sumB += b[key];
            }
        }
        return sumA > sumB;
    } else {
        throw new Error('Unsupported types for customGreaterThan');
    }
}
// 使用示例
console.log(customGreaterThan(5, 3)); // 输出 true
console.log(customGreaterThan({a: 3, b: 2}, {c: 1})); // 输出 true

这里的 customGreaterThan 函数,当参数为数字时进行常规比较。当参数为对象时,对对象中的数值属性求和后进行比较。

自定义位运算符

自定义按位与运算符

JavaScript 的按位与运算符 & 用于对两个数字的二进制表示进行按位与操作。我们来实现一个自定义的按位与运算符,它可以处理更复杂的数据结构,比如对包含二进制数据的数组进行按位与操作。

function customBitwiseAnd(a, b) {
    if (typeof a === 'number' && typeof b === 'number') {
        return a & b;
    } else if (Array.isArray(a) && Array.isArray(b)) {
        if (a.length!== b.length) {
            throw new Error('数组长度不匹配');
        }
        let result = [];
        for (let i = 0; i < a.length; i++) {
            result.push(a[i] & b[i]);
        }
        return result;
    } else {
        throw new Error('Unsupported types for customBitwiseAnd');
    }
}
// 使用示例
console.log(customBitwiseAnd(5, 3)); // 输出 1
console.log(customBitwiseAnd([5, 7], [3, 6])); // 输出 [1, 6]

customBitwiseAnd 函数中,当参数为数字时执行常规按位与操作。当参数为数组时,对数组对应位置的元素进行按位与操作,并返回结果数组。

自定义按位或运算符

按位或运算符 | 在 JavaScript 中用于对两个数字的二进制表示进行按位或操作。我们自定义一个按位或运算符,它在处理数组时,能将数组中的所有元素进行按位或操作后返回结果。

function customBitwiseOr(a, b) {
    if (typeof a === 'number' && typeof b === 'number') {
        return a | b;
    } else if (Array.isArray(a)) {
        let result = a[0];
        for (let i = 1; i < a.length; i++) {
            result |= a[i];
        }
        return result;
    } else if (Array.isArray(b)) {
        let result = b[0];
        for (let i = 1; i < b.length; i++) {
            result |= b[i];
        }
        return result;
    } else {
        throw new Error('Unsupported types for customBitwiseOr');
    }
}
// 使用示例
console.log(customBitwiseOr(5, 3)); // 输出 7
console.log(customBitwiseOr([5, 7, 3])); // 输出 7

customBitwiseOr 函数中,当参数为数字时执行常规按位或操作。当参数为数组时,对数组元素依次进行按位或操作并返回最终结果。

自定义赋值运算符

自定义复合加法赋值运算符

JavaScript 的复合加法赋值运算符 += 用于将右侧操作数加到左侧操作数并赋值给左侧操作数。我们来实现一个自定义的复合加法赋值运算符,它可以处理对象的数值属性相加。

function customAddAssign(target, value) {
    if (typeof target === 'number') {
        target += value;
        return target;
    } else if (typeof target === 'object') {
        for (let key in target) {
            if (!isNaN(parseFloat(target[key])) && isFinite(target[key])) {
                target[key] += value;
            }
        }
        return target;
    } else {
        throw new Error('Unsupported types for customAddAssign');
    }
}
// 使用示例
let num = 5;
num = customAddAssign(num, 3);
console.log(num); // 输出 8
let obj = {a: 2};
obj = customAddAssign(obj, 1);
console.log(obj); // 输出 {a: 3}

customAddAssign 函数中,当 target 为数字时执行常规的复合加法赋值操作。当 target 为对象时,对对象中的数值属性执行复合加法赋值操作。

自定义复合乘法赋值运算符

复合乘法赋值运算符 *= 在 JavaScript 中用于将右侧操作数乘以左侧操作数并赋值给左侧操作数。我们自定义一个复合乘法赋值运算符,它可以处理矩阵与数字的复合乘法。

function customMultiplyAssign(target, value) {
    if (typeof target === 'number') {
        target *= value;
        return target;
    } else if (Array.isArray(target)) {
        for (let i = 0; i < target.length; i++) {
            for (let j = 0; j < target[0].length; j++) {
                target[i][j] *= value;
            }
        }
        return target;
    } else {
        throw new Error('Unsupported types for customMultiplyAssign');
    }
}
// 使用示例
let num = 5;
num = customMultiplyAssign(num, 3);
console.log(num); // 输出 15
let matrix = [[1, 2], [3, 4]];
matrix = customMultiplyAssign(matrix, 2);
console.log(matrix); 
// 输出 [[2, 4], [6, 8]]

customMultiplyAssign 函数中,当 target 为数字时执行常规的复合乘法赋值操作。当 target 为矩阵(二维数组)时,将矩阵的每个元素乘以 value 并返回修改后的矩阵。

自定义其他运算符

自定义三元运算符

JavaScript 的三元运算符 condition? value1 : value2 根据条件 condition 的真假返回 value1value2。我们来实现一个自定义三元运算符,它在返回值之前可以执行一些额外的操作,比如记录日志。

function customTernary(condition, value1, value2, logFunction) {
    if (condition) {
        if (typeof logFunction === 'function') {
            logFunction('选择了 value1');
        }
        return value1;
    } else {
        if (typeof logFunction === 'function') {
            logFunction('选择了 value2');
        }
        return value2;
    }
}
// 使用示例
function logMessage(message) {
    console.log(message);
}
let result = customTernary(2 > 1, '大于', '小于', logMessage);
console.log(result); 
// 输出 '选择了 value1',然后输出 '大于'

customTernary 函数中,根据 condition 的值返回 value1value2,并且在返回前如果提供了 logFunction,则执行该函数记录日志。

自定义逗号运算符

逗号运算符 , 在 JavaScript 中用于依次计算表达式,并返回最后一个表达式的值。我们自定义一个逗号运算符,它可以对数组元素进行一些自定义操作后返回最后一个元素。

function customComma(...args) {
    let result;
    for (let i = 0; i < args.length; i++) {
        if (Array.isArray(args[i])) {
            args[i] = args[i].map((val) => val * 2);
        }
        result = args[i];
    }
    return result;
}
// 使用示例
let commaResult = customComma([1, 2], 3, 4);
console.log(commaResult); 
// 输出 4,同时 [1, 2] 被修改为 [2, 4]

customComma 函数中,遍历 args,如果元素是数组,则对数组元素进行乘以 2 的操作,最后返回最后一个元素。

通过对这些 JavaScript 公认符号的自定义实现,我们不仅深入了解了 JavaScript 语言的底层机制,还能根据具体的业务需求灵活扩展语言的功能,为开发更强大、更灵活的应用程序提供了可能。在实际应用中,需要谨慎使用自定义符号,确保代码的可读性和可维护性,避免过度复杂的自定义导致代码难以理解和调试。同时,也要注意与现有 JavaScript 规范和其他开发人员的习惯保持一定的兼容性,以便团队协作和项目的长期发展。