标签函数 --<Javascript 学习笔记 12>

186 阅读1分钟

Javascript 学习笔记 12

ECMAScript 2015 发布了一个函数的扩展,可以使用模板字符串调用函数,与括号调用有所不同。

function solve(str, ...args) {
    const { log } = console;
    log(str);
    log(args);
}

solve`Hello ${1}`; // 函数名后不空格,虽然会好看一点,但是不符合规范

/* 输出
    [ 'Hello ', '' ]
    [ 1 ]
*/

所以是啥意思呢?通俗的解释,就是普通字符串会被传到第一个参数,其他在 ${} 中的内容,则会依次传入后面的参数。

那么肯定会有人奇怪第一个输出的第二个元素是空字符串,如果我再写一段代码你就懂了:

function solve(str, ...args) {
    const { log } = console;
    log(str);
    log(args);
}

solve`${0} Hello ${1}`; // 函数名后不空格,虽然会好看一点,但是不符合规范

/* 输出
    [ '', ' Hello ', '' ]
    [ 0, 1 ]
*/

也就是说它会以 ${xxx} 为分隔符分段,所以 ${xxx} 前后都是有内容的,即使是字符串的开头或结尾,与 String.prototype.split 行为一致。

所以标签函数是为了让参数更加语义化,既保证可读性,也保证实用性,我们可以利用此特性来实现一个 i18n 函数:

function i18n(str, name, age) {
    return `我叫 ${name} ,今年 ${age} 岁了`;
    // or String.raw({raw: str}, name, age);
}

i18n`My name is ${'Jack'},i am ${10} years old`;
// 我叫 Jack ,今年 10 岁了

可以看出,它还有类似词法分析器的功能,所以我们可以根据它来实现一门语言,我就写个例子来实现新的数组操作符:

function discriminate(operator) {
    const [x, y] = operator.map(item => item.trim());

    // x is a operator
    if (x && !y) {
        if (x == '++')
            return 'unshift';

        else if (x == '--')
            return 'shift';
    } else if (!x && y) {
        if (y == '++')
            return 'push';

        else if (y == '--')
            return 'pop';
    } else {
        return operator;
    }
}

function convert(items) {
    if (Array.isArray(items)) {
        return items;
    }

    return [items];
}

function parser(operator, arr, items) {
    items = convert(items);
    operator = discriminate(operator);

    switch (operator) {
        case 'push':
            arr.push(...items);
            break;
        case 'unshift':
            arr.unshift(...items);
            break;
        case 'pop':
            arr.pop();
            break;
        case 'shift':
            arr.shift();
            break;
        case 'exec':
            eval();
    }
}

const arr = [1, 2];
parser` ${arr} ++ ${[3, 4]} `;
parser` -- ${arr} `;
parser` ${arr} -- `;
console.log(arr); // [ 2, 3 ]