V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
px920906

js 如何深拷贝一个函数?

  •  1
     
  •   px920906 · Feb 22, 2020 · 12678 views
    This topic created in 2257 days ago, the information mentioned may be changed or developed.

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

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

    eval(foo.toString())(1)
    ```
    afpro
        5
    afpro  
       Feb 22, 2020
    为啥要 copy 一个函数 莫非 javascript 的函数是可变的?
    rabbbit
        6
    rabbbit  
       Feb 22, 2020
    https://stackoverflow.com/questions/1833588/javascript-clone-a-function

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

    求大神解释
    otakustay
        8
    otakustay  
       Feb 22, 2020
    不可能的,闭包是完全没办法克隆的
    zckevin
        9
    zckevin  
       Feb 22, 2020
    1. hook javascript functions
    2. utilize/modify VM internals
    ila
        10
    ila  
       Feb 22, 2020 via Android
    eval 吗
    MzM2ODkx
        11
    MzM2ODkx  
       Feb 22, 2020
    笔记里的
    ```
    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  
       Feb 22, 2020 via Android
    ctrl c,ctrl v,深拷贝
    fengbjhqs
        13
    fengbjhqs  
       Feb 22, 2020
    感觉写一个深拷贝的函数会比较现实,
    huanglexus
        14
    huanglexus  
       Feb 22, 2020
    不知道楼主是不是听错了,如果是真的话,问这种问题的人很明显连基本的编程语言常识都不懂
    Hilong
        15
    Hilong  
       Feb 22, 2020 via Android
    是不是如何实现深拷贝函数吧?
    px920906
        16
    px920906  
    OP
       Feb 22, 2020
    @huanglexus 我当时问了一句“深拷贝一个函数?”,说是的。。面试官水平应该没问题的,之前也问了许多正常的问题。不过后悔没追问他这种需求的场景
    @fengbjhqs 我也是这么想的
    @rabbbit 当时还真没想这么多
    dartabe
        17
    dartabe  
       Feb 22, 2020
    看了一下 好像上面的 eval(func.toString)是可以的
    rabbbit
        18
    rabbbit  
       Feb 22, 2020
    面试者的原话说的是什么,直接问的如何深拷贝函数吗.
    我猜可能是想问如何继承构造函数?
    leafdream
        19
    leafdream  
       Feb 22, 2020
    拷贝对象吧 拷贝个🔨的函数
    tlday
        20
    tlday  
       Feb 22, 2020
    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  
       Feb 22, 2020
    忽略代码最后两行,测试 js 时顺手写的
    hyy1995
        22
    hyy1995  
       Feb 22, 2020
    面试玩的是真的花啊
    vasoner
        23
    vasoner  
       Feb 22, 2020
    吃个瓜,我觉得应该是听错了,应该是应该让你写深拷贝而已
    lizz666
        24
    lizz666  
       Feb 22, 2020
    曾经也有过这样的疑惑,倒是在网上看到过以下这种改变 this 的方式,可能面试官认为这样就算深拷贝函数了吧

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

    console.log(echo);
    eval(echo);
    ```
    tairan2006
        30
    tairan2006  
       Feb 23, 2020
    深拷贝一个函数?把代码复制一遍…
    revalue
        31
    revalue  
       Jul 23, 2020
    @iMusic 为啥一个 eval 一个用的 new Function 呢?不能统一吗?
    cj97
        32
    cj97  
       Jan 22, 2021
    浅复制,深复制同理
    ```
    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  
       Apr 18, 2023
    new Function('return ' + fn.toString())();
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1007 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 84ms · UTC 19:18 · PVG 03:18 · LAX 12:18 · JFK 15:18
    ♥ Do have faith in what you're doing.