You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

JavaScript OOP中SyntaxError: Identifier 'password' has already been declared错误修复及私有成员实现方案

问题:JavaScript类中如何实现私有变量并修复标识符重复声明错误

我正在学习JavaScript面向对象编程(OOP),并以创建第一个类作为练习,编写了如下代码:

'use strict';
const crypto = require('crypto');
class FileVault {
  constructor(password, filesPath = null) {
    let password = password;
    console.log(password);
    this.filePath = filesPath;
    let algo = 'aes-256-gcm';
  }
  encrypt() {
    let salt = crypto.randomBytes(32);
    let key = crypto.scryptSync(password, salt, 32);
    let iv = crypto.randomBytes(16);
    let cipher = crypto.createCipheriv(algo, key, iv);
    console.log(salt, key, iv, cipher);
  }
  decrypt() {
  }
}
let encryptor = new FileVault('test');
console.log(encryptor.encrypt());

在repl中测试这段代码时,我遇到了错误:SyntaxError: Identifier 'password' has already been declared。我原本以为可以在constructor中声明变量并在类方法中使用,但实际出现了该错误。请问有没有修复方法?我不希望password变量公开,仅允许类内部访问——我主要使用PHP,在PHP中会用private关键字实现该需求,想知道在JavaScript中如何实现相同效果。


解答

先解决你当前的语法错误:在constructor里,你已经有一个名为password的参数,又用let password = password;重新声明了同名变量,这就触发了重复声明的错误——JavaScript不允许在同一作用域内重复声明同一个标识符。

接下来针对你核心的需求(实现类内部私有变量,对应PHP的private),给你两种实用的方案:

1. ES6+ 原生私有字段(推荐)

现在JavaScript已经支持原生的私有字段,用#前缀定义,这类字段只能在类内部访问,外部完全无法读取或修改,和PHP的private行为完全一致,而且是标准实现,兼容性也很好(现代浏览器、Node.js 12+都支持)。修改后的代码如下:

'use strict';
const crypto = require('crypto');
class FileVault {
  // 先声明私有字段
  #password;
  #algo = 'aes-256-gcm';

  constructor(password, filesPath = null) {
    this.#password = password; // 给私有字段赋值
    this.filePath = filesPath;
  }

  encrypt() {
    let salt = crypto.randomBytes(32);
    // 访问私有字段需要加this.#前缀
    let key = crypto.scryptSync(this.#password, salt, 32);
    let iv = crypto.randomBytes(16);
    let cipher = crypto.createCipheriv(this.#algo, key, iv);
    console.log(salt, key, iv, cipher);
  }

  decrypt() {
    // 这里同样可以访问this.#password和this.#algo
  }
}

let encryptor = new FileVault('test');
encryptor.encrypt();
// 外部尝试访问私有字段会直接报错,确保私有性
// console.log(encryptor.#password); // SyntaxError: Private field '#password' must be declared in an enclosing class

2. 闭包实现私有变量(兼容旧环境)

如果需要兼容更老的JavaScript环境(比如不支持私有字段的Node.js版本),可以利用闭包的特性,把私有变量放在构造函数的作用域内,类方法定义在构造函数内部(用箭头函数绑定this)。不过这种方式每个实例都会重新创建方法,内存开销会略大一点:

'use strict';
const crypto = require('crypto');
class FileVault {
  constructor(password, filesPath = null) {
    // 这些变量只在构造函数作用域内存在,外部无法访问
    const _password = password;
    const _algo = 'aes-256-gcm';
    this.filePath = filesPath;

    // 把方法定义在构造函数内,通过闭包访问私有变量
    this.encrypt = () => {
      let salt = crypto.randomBytes(32);
      let key = crypto.scryptSync(_password, salt, 32);
      let iv = crypto.randomBytes(16);
      let cipher = crypto.createCipheriv(_algo, key, iv);
      console.log(salt, key, iv, cipher);
    };

    this.decrypt = () => {
      // 这里同样可以访问_password和_algo
    };
  }
}

let encryptor = new FileVault('test');
encryptor.encrypt();
// 外部无法获取私有变量,下面的代码会返回undefined
// console.log(encryptor._password); // undefined

最后补充一点:你原来的代码里,encrypt方法直接用passwordalgo是无效的——因为这两个是constructor里的局部变量,作用域仅限于构造函数内部,类的其他方法根本访问不到。上面的两种方案既解决了这个问题,又实现了变量的私有性。

内容的提问来源于stack exchange,提问作者newbiedev

火山引擎 最新活动