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

js 构造函数和闭包的问题

  •  
  •   QGabriel · 2022-01-26 12:04:46 +08:00 · 2582 次点击
    这是一个创建于 1061 天前的主题,其中的信息可能已经有所发展或是发生改变。
    function Foo(){
    var a = 1
    this.get = function(){
    console.log(a)
    }
    this.add = function () {
    a++
    }
    }

    let foo1 = new Foo()
    let foo2 = new Foo()
    foo1.add()
    foo1.get() // 2
    foo2.get() // 1

    function C(){
    var a = 1
    return function () {
    return a++
    }
    }

    let c1 = C()
    let c2 = C()
    c1() // 2
    c2() // 2

    问题 1: 构造函数内部声明变量只能通过实例方法调用,这和闭包是一样的吗?
    17 条回复    2022-01-26 16:55:59 +08:00
    charlie21
        1
    charlie21  
       2022-01-26 12:23:27 +08:00
    https://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
    搜关键字 内存,理解一下闭包对内存的影响
    QGabriel
        2
    QGabriel  
    OP
       2022-01-26 12:35:18 +08:00
    @charlie21 构造函数的方式和闭包不是一回事吗?
    zythum
        3
    zythum  
       2022-01-26 12:49:13 +08:00
    你这种情况,大体是一样的。每一个实例都是使用自己创建的 add 方法。一般来说你下面的情况叫工厂函数。

    但是上面的情况,大概应该写成这样就不一样的。
    function Foo() {
    this.a = 1;
    }
    Foo.prototype.add = function () {
    this.a++;
    }
    每个 Foo 实例是共用 prototype 上的 add 方法的。
    rabbbit
        4
    rabbbit  
       2022-01-26 13:06:08 +08:00
    上边那个构造函数大概可以理解成: 

    function Foo() {
      var obj = {};
      var a = 1;

      obj.get = function () {
       console.log(a);
     };
      obj.add = function () {
       a++;
     };
      return obj;
    }

    let foo1 = Foo()
    QGabriel
        5
    QGabriel  
    OP
       2022-01-26 13:18:15 +08:00
    @rabbbit 构造函数的方式是闭包吗?
    cheots
        6
    cheots  
       2022-01-26 13:19:46 +08:00 via iPhone
    rabbbit
        7
    rabbbit  
       2022-01-26 13:21:04 +08:00
    要我个人理解 this.get/this.add 对 var a 的引用算闭包
    mozhizhu
        8
    mozhizhu  
       2022-01-26 13:52:15 +08:00
    c1 和 c2 在内存索引上是同一个
    mozhizhu
        9
    mozhizhu  
       2022-01-26 13:52:53 +08:00
    @mozhizhu 卧槽,今日不宜回复,老是看错
    2i2Re2PLMaDnghL
        10
    2i2Re2PLMaDnghL  
       2022-01-26 14:04:07 +08:00
    构造函数的区别是 prototype 可以共用,其他并无影响。
    我仍然不推荐称呼闭包,闭包是一种__实现__而不是__语法__。这种语法叫做「词法作用域」。
    2i2Re2PLMaDnghL
        12
    2i2Re2PLMaDnghL  
       2022-01-26 14:33:47 +08:00
    @KuroNekoFan 当然不是,一种语法和一种实现的技术当然不是一回事。
    实际上被称为闭包的实体,就是那个可以 xxx() 的东西。你已经找不到函数本身了。
    就算是 new Function 出来的也是个闭包,只是父级域不是当前域而是全局域来着。
    KuroNekoFan
        13
    KuroNekoFan  
       2022-01-26 14:52:44 +08:00
    @2i2Re2PLMaDnghL 嗷我我误会了,楼主这个确实更能体现 lexical scope 的特性而不是闭包
    QGabriel
        14
    QGabriel  
    OP
       2022-01-26 15:06:19 +08:00
    @2i2Re2PLMaDnghL 你意思是说只有函数本身消失了但其作用域还在的方式叫闭包?构造函数那种不算闭包吗?
    2i2Re2PLMaDnghL
        15
    2i2Re2PLMaDnghL  
       2022-01-26 16:03:46 +08:00
    @QGabriel 不是函数本身消失了,而是封在闭包里;并且在现在大部分支持闭包的语言中,你找不到函数本身,只能找到包含这个函数的闭包。你几乎不可能生成函数的引用,只能生成闭包的引用;你也无法直接调用函数,只能调用闭包让闭包去调用函数。
    但因为这个闭包是 first-class function 的一个实例,也是你唯一可以找来调用的东西,所以实际上大部分人在所有时间并且所有人在大部分时间还是称闭包为函数。

    至于你#14 的这句话,因为太过混乱我甚至不知道从哪开始回复。
    你根本拿不到函数,因为函数早已被(编译器、解释器)封装进闭包。
    除非你能想办法把让这段代码返回 true

    (function(){
    var a = {};
    // create something called new_get with foo1.get
    return a===new_get()
    })
    codermagefox
        16
    codermagefox  
       2022-01-26 16:16:54 +08:00
    真无聊..
    pendulum
        17
    pendulum  
       2022-01-26 16:55:59 +08:00
    你运行过了吗?我的运行结果是 2 1 1 1
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2419 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:50 · PVG 23:50 · LAX 07:50 · JFK 10:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.