js 如何深拷贝一个函数? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
px920906
V2EX    Javascript

js 如何深拷贝一个函数?

  •  1
     
  •   px920906 2020-02-22 11:37:18 +08:00 12271 次点击
    这是一个创建于 2057 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前几天一个面试中的问题,听到有点懵逼,因为从没听说过这种需求,这几天搜索了一通好像也没有明确的方案,自己能想到的是用 bind ? v 友有点子吗?

    33 条回复    2023-04-18 20:53:32 +08:00
    sherryqueen
        1
    sherryqueen  
       2020-02-22 11:41:42 +08:00
    拷贝一个函数?? 没了解过 占个座, 等楼下答复, 到时候来学习一下- -
    yuankui
        2
    yuankui  
       2020-02-22 11:48:19 +08:00
    附楼问一下:如何序列化和反序列化一个函数?
    qinfensky
        3
    qinfensky  
       2020-02-22 11:56:20 +08:00 via iPhone
    函数的作用域不是独立的吗?除了个 ththis 指向的坑有时候需要 bind,拷贝的意义是什么?费解
    lane1
        4
    lane1  
       2020-02-22 12:00:48 +08:00   1
    @yuankui
    ```Javascript
    const foo = x => x + 1

    eval(foo.toString())(1)
    ```
    afpro
        5
    afpro  
       2020-02-22 12:11:48 +08:00
    为啥要 copy 一个函数 莫非 Javascript 的函数是可变的?
    rabbbit
        6
    rabbbit  
       2020-02-22 12:13:32 +08:00
    https://stackoverflow.com/questions/1833588/Javascript-clone-a-function

    另外,怎么算函数? 普通函数 函数表达式 箭头函数 , typeof class 也返回 function 算不算函数?
    很好奇什么情况下才会需要这种功能.
    dartabe
        7
    dartabe  
       2020-02-22 12:25:25 +08:00
    从函数式编程的角度来看 Javascript 里面函数都尽量是纯函数 有一个就行了 其他地方都是他的引用啊

    求大神解释
    otakustay
        8
    otakustay  
       2020-02-22 12:30:19 +08:00
    不可能的,闭包是完全没办法克隆的
    zckevin
        9
    zckevin  
       2020-02-22 12:42:22 +08:00
    1. hook Javascript functions
    2. utilize/modify VM internals
    ila
        10
    ila  
       2020-02-22 12:42:33 +08:00 via Android
    eval 吗
    MzM2ODkx
        11
    MzM2ODkx  
       2020-02-22 13:33:03 +08:00
    笔记里的
    ```
    function cloneFunction(func) {
    const bodyReg = /(?<={)(.|\n)+(?=})/m
    const paramReg = /(?<=\().+(?=\)\s+{)/
    const funcString = func.toString()
    if (func.prototype) {
    const param = paramReg.exec(funcString)
    const body = bodyReg.exec(funcString)
    if (body) {
    if (param) {
    const paramArr = param[0].split(',')
    return new Function(...paramArr, body[0])
    } else {
    return new Function(body[0])
    }
    } else {
    return null
    }
    } else {
    return eval(funcString)
    }
    }
    ```
    gaobing
        12
    gaobing  
       2020-02-22 13:37:21 +08:00 via Android
    ctrl c,ctrl v,深拷贝
    fengbjhqs
        13
    fengbjhqs  
       2020-02-22 13:46:13 +08:00
    感觉写一个深拷贝的函数会比较现实,
    huanglexus
        14
    huanglexus  
       2020-02-22 13:49:20 +08:00
    不知道楼主是不是听错了,如果是真的话,问这种问题的人很明显连基本的编程语言常识都不懂
    Hilong
        15
    Hilong  
       2020-02-22 13:57:51 +08:00 via Android
    是不是如何实现深拷贝函数吧?
    px920906
        16
    px920906  
    OP
       2020-02-22 14:01:48 +08:00
    @huanglexus 我当时问了一句“深拷贝一个函数?”,说是的。。面试官水平应该没问题的,之前也问了许多正常的问题。不过后悔没追问他这种需求的场景
    @fengbjhqs 我也是这么想的
    @rabbbit 当时还真没想这么多
    dartabe
        17
    dartabe  
       2020-02-22 14:20:09 +08:00
    看了一下 好像上面的 eval(func.toString)是可以的
    rabbbit
        18
    rabbbit  
       2020-02-22 14:20:28 +08:00
    面试者的原话说的是什么,直接问的如何深拷贝函数吗.
    我猜可能是想问如何继承构造函数?
    leafdream
        19
    leafdream  
       2020-02-22 14:28:11 +08:00
    拷贝对象吧 拷贝个的函数
    tlday
        20
    tlday  
       2020-02-22 14:35:37 +08:00
    TL;DR:考虑这种情况:
    '''
    const inc = v => v+1;
    inc.vector = [1,2,3]; //或者用 Object.assign/Object.defineProperty
    inc.vector_add = function(num) { return this.vector.map(v => v + num) };
    inc.t = 1;
    inc.t.a = 3;
    '''
    要求拷贝 inc 函数或者拷贝 inc.vector_add 函数。



    正文:
    个人理解首应该问清楚是否同样拷贝 property。
    因为函数式编程语言中,函数是一等公民,本质上是个 function 对象,又因为 js 里对象的特殊性(兼具其他语言 map/dict 的特性),所以问题实际上分化成两个问题,是否需要拷贝 property。
    如果不需要拷贝 property,这个函数内部有可能引用自身的某个 property,需要考虑 js 里的 this 绑定问题。考虑 ES6 以后箭头函数和普通函数的 this 绑定问题(如何判断是普通函数还是箭头函数: https://stackoverflow.com/questions/28222228/Javascript-es6-test-for-arrow-function-built-in-function-regular-function),无论是哪种函数,可靠的机制都是 apply 原 function 对象为 this。(这种情况需要考虑多次拷贝以后的调用栈深度,上面 StackOverflow 里的答案有人用双下划线开头的属性 hold 了一个最原始对象解决这个问题--评论有人指出 ES6 以后可以用 Symbol 而不是双下划线这种不太可靠的 trick )
    如果需要拷贝 property,那么相当于 js 里如何深拷贝一个(函数)对象 /map/dict,应该就是逐个遍历这个函数对象的属性,值引用类型的拷贝值,“引用”引用类型的同样作递归的深拷贝。同时考虑是否需要拷贝 property descriptor ( https://developer.mozilla.org/en-US/docs/Web/Javascript/Reference/Global_Objects/Object/getOwnPropertyDescriptor )的问题(这里有个参考答案 https://github.com/lodash/lodash/issues/3043 )。面试的话,我觉得答到这里应该足够了,正常编程中感觉很少出现这种需求。
    tlday
        21
    tlday  
       2020-02-22 14:39:19 +08:00
    忽略代码最后两行,测试 js 时顺手写的
    hyy1995
        22
    hyy1995  
       2020-02-22 15:59:10 +08:00
    面试玩的是真的花啊
    vasoner
        23
    vasoner  
       2020-02-22 16:13:52 +08:00
    吃个瓜,我觉得应该是听错了,应该是应该让你写深拷贝而已
    lizz666
        24
    lizz666  
       2020-02-22 16:15:43 +08:00
    曾经也有过这样的疑惑,倒是在网上看到过以下这种改变 this 的方式,可能面试官认为这样就算深拷贝函数了吧

    ```js
    function test1() {}
    test1.a = 1
    let test2 = test1.bind(null)
    test2.a // undefined
    ```
    tonytonychopper
        25
    tonytonychopper  
       2020-02-22 17:35:42 +08:00 via Android
    不了解,但是可以看下 lodash 是怎么实现的
    7DLNU56W
        26
    7DLNU56W  
       2020-02-22 18:11:40 +08:00
    利用 Function.prototype.bind 是不是可以实现呀~
    tinyhill
        27
    tinyhill  
       2020-02-22 18:18:36 +08:00
    应该是问深拷贝时的函数问题吧,比如 JSON.stringify/parse 会 gg
    zhw2590582
        28
    zhw2590582  
       2020-02-22 20:16:52 +08:00
    要么考查 bind 构造一个新函数,要么考查从现有函数体提取字符串再构造一个新函数
    mostkia
        29
    mostkia  
       2020-02-23 09:22:23 +08:00
    把函数当作字符串来处理不知道是不是可以,funciton 不带括号是不执行的,反而会打印出内容,利用 toString()方法接住打印出来的函转为字符串,然后就可以输出了,要转为 fun,外面包一个 eval 执行。
    ```
    function uu(){
    alert('???');
    }
    var echo = uu.toString();

    console.log(echo);
    eval(echo);
    ```
    tairan2006
        30
    tairan2006  
       2020-02-23 20:59:49 +08:00
    深拷贝一个函数?把代码复制一遍…
    revalue
        31
    revalue  
       2020-07-23 21:43:50 +08:00
    @iMusic 为啥一个 eval 一个用的 new Function 呢?不能统一吗?
    cj97
        32
    cj97  
       2021-01-22 09:50:37 +08:00
    浅复制,深复制同理
    ```
    const fn = () => 1;
    fn.a = 2;
    fn.f = () => 3;
    const obj = Object.assign({}, fn);
    const clOneFn= fn.bind();
    Object.keys(obj).forEach(key => { cloneFn[key] = obj[key] })
    ```
    Tsuizen
        33
    Tsuizen  
       2023-04-18 20:53:32 +08:00
    new Function('return ' + fn.toString())();
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2617 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 15:18 PVG 23:18 LAX 08:18 JFK 11:18
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86