kongmingLatern / daily_plan

Record Your daily plan
1 stars 0 forks source link

2023-01-14 #10

Open kongmingLatern opened 1 year ago

kongmingLatern commented 1 year ago

2023-01-14

1. 你学习了哪些知识?

2. 学习过程中是否有存在的问题?

关于如何写每日任务:

如何写每日任务

kongmingLatern commented 1 year ago

1. Babel 插件小案例

要求:

给每个 console 前面插入文件名以及行列号,方便之后定位到指定代码

1.1 整体思路

![[Pasted image 20230114122408.png]]

函数调用表达式的 AST 是 CallExpression。

CallExrpession 节点有两个属性,callee 和 arguments,分别对应调用的函数名和参数, 所以我们要判断当 callee 是 console.xx 时,在 arguments 的数组中中插入一个 AST 节点。

![[Pasted image 20230114122842.png]] 1.2 整体框架

const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;

const sourceCode = `console.log(1);`;

const ast = parser.parse(sourceCode, {
  sourceType: 'unambiguous'
});

traverse(ast, {
    CallExpression(path, state) {

    }
});

const { code, map } = generate(ast);
console.log(code);

要转化的代码

const sourceCode = `
    console.log(1);

    function func() {
        console.info(2);
    }

    export default class Clazz {
        say() {
            console.debug(3);
        }
        render() {
            return <div>{console.error(4)}</div>
        }
    }
`;

修改结构

const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const types = require('@babel/types');

const ast = parser.parse(sourceCode, {
    sourceType: 'unambiguous',
    plugins: ['jsx']
});

traverse(ast, {
    CallExpression (path, state) {
        if ( types.isMemberExpression(path.node.callee) 
            && path.node.callee.object.name === 'console' 
            && ['log', 'info', 'error', 'debug'].includes(path.node.callee.property.name) 
           ) {
            const { line, column } = path.node.loc.start;
            path.node.arguments.unshift(types.stringLiteral(`filename: (${line}, ${column})`))
        }
    }
});

修改上述代码实现

const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const types = require('@babel/types');

const ast = parser.parse(sourceCode, {
    // sourceType 用来告诉编辑器是使用 mjs 还是 cjs
    // unambiguous 让编译器自行推断
    sourceType: 'unambiguous',
    plugins: ['jsx']
});

const targetCalleeName = ['log', 'info', 'error', 'debug'].map(item => `console.${item}`);

traverse(ast, {
    // 函数调用表达式的 AST 是 CallExpression。
    CallExpression(path, state) {
        const calleeName = generate(path.node.callee).code;

        if (targetCalleeName.includes(calleeName)) {
            const { line, column } = path.node.loc.start;
            path.node.arguments.unshift(types.stringLiteral(`filename: (${line}, ${column})`))
        }
    }
});

最终代码:

const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const types = require('@babel/types');
const template = require('@babel/template').default;

const ast = parser.parse(sourceCode, {
    sourceType: 'unambiguous',
    plugins: ['jsx']
});

const targetCalleeName = ['log', 'info', 'error', 'debug'].map(item => `console.${item}`);

traverse(ast, {
    CallExpression(path, state) {
        if (path.node.isNew) {
            return;
        }
        const calleeName = generate(path.node.callee).code;
         if (targetCalleeName.includes(calleeName)) {
            const { line, column } = path.node.loc.start;

            const newNode = template.expression(`console.log("filename: (${line}, ${column})")`)();
            newNode.isNew = true;

            if (path.findParent(path => path.isJSXElement())) {
                path.replaceWith(types.arrayExpression([newNode, path.node]))
                path.skip();
            } else {
                path.insertBefore(newNode);
            }
        }
    }
});

API 参考:

1. babelParser.parse(code, [options])

2. babelParser.traverse(parent, [options])

parent 指定要遍历的 AST 节点, opts 指定 visitor 函数。 babel 会在遍历 parent 对应的 AST 时调用相应的 visitor 函数。

3. function generate(ast, opts, code: string): {code, map}

第一个参数是要打印的 AST。 第二个参数是 options,指定打印的一些细节,比如通过 comments 指定是否包含注释,通过 minified 指定是否包含空白字符。 第三个参数当多个文件合并打印的时候需要用到,这部分直接看文档即可,基本用不到。 options 中常用的是 sourceMaps,开启了这个选项才会生成 sourcemap。

2. JS 高级

2.1 原型链

![[Pasted image 20230114191402.png]]

3. Rust

3.1 Vec.sort()

impl Solution {
    // 注意:这里的数组需要 mut 关键字,因为 sort 方法会破坏本身的数组
    pub fn get_least_numbers(mut arr: Vec<i32>, k: i32) -> Vec<i32> {
        arr.sort();
        // 数组切片,并把结果变成一个数组
        arr[..(k as usize)].to_vec()
    }
}

补充:

let a = [1, 2, 3, 4, 5];
// 切片
let slice = &a[1..3];
// 该数组切片的类型是 &[i32]
assert_eq!(slice, &[2, 3]);

3.2 Reverse

use std::cmp::Reverse;

let mut v = vec![1, 2, 3, 4, 5, 6];
v.sort_by_key(|&num| (num > 3, Reverse(num)));
assert_eq!(v, vec![3, 2, 1, 6, 5, 4]);

3.3 BinaryHeap

use std::collections::BinaryHeap;

// Type inference lets us omit an explicit type signature (which
// would be `BinaryHeap<i32>` in this example).
let mut heap = BinaryHeap::new();

// We can use peek to look at the next item in the heap. In this case,
// there's no items in there yet so we get None.
assert_eq!(heap.peek(), None);

// Let's add some scores...
heap.push(1);
heap.push(5);
heap.push(2);

// Now peek shows the most important item in the heap.
assert_eq!(heap.peek(), Some(&5));

// We can check the length of a heap.
assert_eq!(heap.len(), 3);

// We can iterate over the items in the heap, although they are returned in
// a random order.
for x in &heap {
    println!("{x}");
}

// If we instead pop these scores, they should come back in order.
assert_eq!(heap.pop(), Some(5));
assert_eq!(heap.pop(), Some(2));
assert_eq!(heap.pop(), Some(1));
assert_eq!(heap.pop(), None);

// We can clear the heap of any remaining items.
heap.clear();

// The heap should now be empty.
assert!(heap.is_empty())

4. TS 体操

type ToPrimitive<T extends Record<string, any>> = {
  [P in keyof T] :
    T[P] extends number
    ? number
    : T[P] extends string
      ? string
      : T[P] extends boolean
        ? boolean
        : T[P] extends Record<string ,any>
          ? ToPrimitive<T[P]>
          : never

// ====================Test Cases====================//
type PersonInfo = {
  name: 'Tom'
  age: 30
  married: false
  addr: {
    home: '123456'
    phone: '13111111111'
  }
  hobbies: ['sing', 'dance']
}

type ExpectedResult = {
  name: string
  age: number
  married: boolean
  addr: {
    home: string
    phone: string
  }
  hobbies: [string, string]
}