Object.assign给函数加属性后为何仍能正常调用原函数?
先看这段示例代码:
const crypto = require('crypto'); const fs = require('fs/promises'); const calculateHash = cache({ ttl: 5, size: 100 }, async file_path => { const buffer = await fs.readFile(file_path); return crypto.createHash('sha256').update(buffer).digest('base64'); }); const cache = (options, fn) => { return Object.assign(fn, { cache_size: () => { return 0; }, clear_cache: () => { // clear_cache is not implemented }, }); };
执行console.log(calculateHash())时,输出显示这个变量既是异步函数,又带有额外的方法属性:
[AsyncFunction (anonymous)] { cache_size: [Function: cache_size], clear_cache: [Function: clear_cache] }
而当通过异步方式调用calculateHash('./fileToCache.js')时,它又能正常执行原哈希计算逻辑并返回结果。
已知Object.assign(obj1, obj2)会合并对象属性,同名属性会被覆盖,这里的疑问是:通过Object.assign得到的结果包含原函数和新增方法,为何调用calculateHash()时会执行原函数而非其他属性?
解答
核心原因是JavaScript里的函数本身就是一种特殊的对象:函数是Function类型的实例,天生具备对象的特性——可以像普通对象一样添加自定义属性和方法。
当调用Object.assign(fn, { ... })时,本质是把cache_size、clear_cache这两个方法作为属性,直接挂载到了原函数fn这个对象身上,相当于给这个函数额外加了两个“附属功能”,但完全没有修改函数本身的执行逻辑。
当你调用calculateHash()时,JavaScript引擎识别到它的本质是一个函数,就会执行这个函数自身的代码逻辑(也就是你传入的那个异步哈希计算函数);而那些挂载在它身上的cache_size、clear_cache只是它的属性,只有当你显式调用calculateHash.cache_size()或者calculateHash.clear_cache()时,才会执行对应的逻辑。
简单总结:函数本身的执行逻辑是它的“本职工作”,挂载的额外属性是“附加功能”,两者互不干扰——调用函数本身就走本职逻辑,调用属性方法才走附加逻辑。
内容的提问来源于stack exchange,提问作者confusedWarrior

