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 · 11749 次点击
    这是一个创建于 1720 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前几天一个面试中的问题,听到有点懵逼,因为从没听说过这种需求,这几天搜索了一通好像也没有明确的方案,自己能想到的是用 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 吗
    iMusic
        11
    iMusic  
       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
    面试玩的是真的花啊
    lipeiwei
        23
    lipeiwei  
       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   ·   实用小工具   ·   1003 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 20:41 · PVG 04:41 · LAX 12:41 · JFK 15:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.