力扣 30 天 JavaScript 挑战 第38天 (第九题)学习了 语句表达式的区别 高级函数 promise async await 节流

开始答题

版本一:

js 复制代码
/**
 * @param {Function} fn
 * @return {Function}
 */
var once = function(fn) {
    let runCount=0
    return function(...args){
        runCount++
        runCount == 1 ? return fn(...args) :return undefined
       
    }
};

/**
 * let fn = (a,b,c) => (a + b + c)
 * let onceFn = once(fn)
 *
 * onceFn(1,2,3); // 6
 * onceFn(2,3,6); // returns undefined without calling fn
 */

报错

为ai为啥报错 ai说三木运算符? :后面只能写表达式不能写语句。return ?是语句。

语句与表达式的区别

语句是一个动作,不一定有事。表达式一定会得到一个值。

语句:

if (x > 10) { ... } // if 语句

while (true) { ... } // while 语句

return 5; // return 语句

var a = 1; // 变量声明语句

表达式:

3 + 4 // 表达式,结果是 7

x > 10 // 表达式,结果是 true 或 false

fn(1, 2) // 表达式,结果是函数返回值

a = 5 // 赋值表达式,结果是 5

即是表达式又是语句

a = 5; // 既是语句(赋值语句),又是表达式(返回 5)

第二版

js 复制代码
/**
 * @param {Function} fn
 * @return {Function}
 */
var once = function(fn) {
    let runCount=0
    return function(...args){
        runCount++
       return runCount == 1 ?  fn(...args) : undefined
       
    }
};

/**
 * let fn = (a,b,c) => (a + b + c)
 * let onceFn = once(fn)
 *
 * onceFn(1,2,3); // 6
 * onceFn(2,3,6); // returns undefined without calling fn
 */

提交通过了

看官方题解

知识点

  1. 高阶函数
    在 JavaScript(以及很多语言)里,如果一个函数满足下面任意条件之一,就叫高阶函数:
  • 函数作为参数传入(参数是函数)
  • 函数作为返回值返回(返回函数)

换句话说:操作函数的函数 → 就是高阶函数

  1. 异步操作 promise 与 async await
  • 它俩都是处理异步操作的,async 是promise的语法糖,通过async可以像处理同步那样处理异步。
  • Promise 的基本语法
js 复制代码
const p = new Promise((resolve, reject) => {
 // 做一些异步的事...
 // 成功时调用 resolve(值)
 // 失败时调用 reject(错误)
});

new Promise(...) 创建一个 Promise 对象

里面必须传一个函数,这个函数有两个参数:resolve 和 reject

resolve(value) → 表示成功,并把结果 value 传出去

reject(error) → 表示失败,并把错误传出去

then ,catch 注是 Promise 对象的方法

then作用是:当 Promise 完成后(resolve),执行的回调函数,then里面会自动接收resolve里面传入的参数。可以使用多个then把异步操作顺序串联,上一个 then 的返回值作为下一个 then 的输入

catch作用是:处理 Promise 失败(reject)或者 then 中抛出的异常。

  • 实例对比
js 复制代码
//promise
const p1 = new Promise(resolve => setTimeout(() => resolve("A"), 1000));

p1.then(console.log); // 1秒后输出 "A"
//async
const p1 = new Promise(resolve => setTimeout(() => resolve("A"), 1000));

async function run() {
  const result = await p1; // 等待 p1 完成,拿到值
  console.log(result);     // 输出 "A"
}

run();
  1. 在原函数外面再包一层函数来修改或扩展函数
  • 节流:限制执行频率
js 复制代码
function throttle(fn,delay){
  let lastTime =0 
  return function(...args){
    const now = Date.now()
    if(now - lastTime > delay){
      fn(args)
      lastTime = now
    }
  }
}
// 用法:搜索时 500ms 内只发一次请求
const search = (text) => console.log("查询数据库:", text);
const throttledSearch = throttle(search, 500);

// 模拟用户频繁输入
throttledSearch("a");
throttledSearch("ab");
throttledSearch("abc");
// 最终只会间隔 >= 500ms 时才真的调用一次 search
  • 时间限制:如果某一个函数执行了好久还没成功,给出失败提示。
js 复制代码
function withTimeout(fn, ms) {
  return function() {
    return Promise.race([
      fn(), // 原函数
      new Promise((_, reject) => setTimeout(() => reject("超时"), ms))
    ]);
  };
}

// 模拟一个耗时很长的异步任务
const longTask = () => new Promise(resolve => setTimeout(() => resolve("完成"), 3000));

const safeTask = withTimeout(longTask, 1000);

safeTask().then(console.log).catch(console.error); 
// 1 秒后报 "超时",不会卡住
  • 记忆化 (Memoization): 有些函数计算量大,但输入相同 → 结果其实一样。下次相同输入就直接返回缓存。
js 复制代码
function memoize(fn) {
  const cache = {};
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache[key] !== undefined) {
      return cache[key]; // 从缓存取结果
    }
    const result = fn(...args);
    cache[key] = result;
    return result;
  };
}

const slowSquare = (n) => {
  console.log("计算中...");
  return n * n;
};

const fastSquare = memoize(slowSquare);

console.log(fastSquare(5)); // "计算中..." 然后 25
console.log(fastSquare(5)); // 直接用缓存 → 25