JavaScript 私有方法使用自调用功能和调用使用 Node 更简单.js(新!)未来 JavaScript 版本中的本机私有方法(已弃用)带有绑定运算符的 ES7

2022-08-29 23:03:23

要使用公共方法创建JavaScript类,我会做这样的事情:

function Restaurant() {}

Restaurant.prototype.buy_food = function(){
   // something here
}

Restaurant.prototype.use_restroom = function(){
   // something here
}

这样,我的类的用户可以:

var restaurant = new Restaurant();
restaurant.buy_food();
restaurant.use_restroom();

如何创建可由 和 方法调用但不能由类的用户在外部调用的私有方法?buy_fooduse_restroom

换句话说,我希望我的方法实现能够做到:

Restaurant.prototype.use_restroom = function() {
   this.private_stuff();
}

但这不应该起作用:

var r = new Restaurant();
r.private_stuff();

如何定义为私有方法,以便这两者都成立?private_stuff

我读过Doug Crockford的文章几次,但似乎“私有”方法不能由公共方法调用,“特权”方法可以在外部调用。


答案 1

你可以这样做,但缺点是它不能成为原型的一部分:

function Restaurant() {
    var myPrivateVar;

    var private_stuff = function() {  // Only visible inside Restaurant()
        myPrivateVar = "I can set this here!";
    }

    this.use_restroom = function() {  // use_restroom is visible to all
        private_stuff();
    }

    this.buy_food = function() {   // buy_food is visible to all
        private_stuff();
    }
}

答案 2

使用自调用功能和调用

JavaScript使用原型,并且没有像面向对象语言那样的类(或方法)。JavaScript开发人员需要用JavaScript思考。

维基百科引用:

与许多面向对象的语言不同,函数定义和方法定义之间没有区别。相反,这种区别发生在函数调用期间;当函数作为对象的方法调用时,函数的本地 this 关键字将绑定到该对象以进行该调用。

解决方案使用自调用函数调用函数来调用私有“方法”:

var MyObject = (function () {
    
  // Constructor
  function MyObject(foo) {
    this._foo = foo;
  }

  function privateFun(prefix) {
    return prefix + this._foo;
  }
    
  MyObject.prototype.publicFun = function () {
    return privateFun.call(this, ">>");
  }
    
  return MyObject;

}());
var myObject = new MyObject("bar");
myObject.publicFun();      // Returns ">>bar"
myObject.privateFun(">>"); // ReferenceError: private is not defined

调用函数允许我们使用适当的上下文 () 调用私有函数。this

使用 Node 更简单.js

如果您使用的是 Node.js,则不需要 IIFE,因为您可以利用模块加载系统

function MyObject(foo) {
  this._foo = foo;
}
    
function privateFun(prefix) {
  return prefix + this._foo;
}

MyObject.prototype.publicFun = function () {
  return privateFun.call(this, ">>");
}
    
module.exports= MyObject;

加载文件:

var MyObject = require("./MyObject");
    
var myObject = new MyObject("bar");
myObject.publicFun();      // Returns ">>bar"
myObject.privateFun(">>"); // ReferenceError: private is not defined

(新!)未来 JavaScript 版本中的本机私有方法

TC39 私有方法和 JavaScript 类的 getter/setters 提案是第 3 阶段。这意味着在不久的将来,JavaScript 都会在本地实现私有方法!

请注意,JavaScript 私有类字段已经存在于现代 JavaScript 版本中。

以下是如何使用它的示例:

class MyObject {

  // Private field
  #foo;
    
  constructor(foo) {
    this.#foo = foo;
  }

  #privateFun(prefix) {
   return prefix + this.#foo;
  }
    
  publicFun() {
    return this.#privateFun(">>");
  }

}

您可能需要一个 JavaScript 转译器/编译器才能在旧的 JavaScript 引擎上运行此代码。

PS:如果您想知道为什么使用前缀,请阅读此内容#

(已弃用)带有绑定运算符的 ES7

警告:绑定运算符 TC39 命题已接近死 https://github.com/tc39/proposal-bind-operator/issues/53#issuecomment-374271822

bind 运算符是一个 ECMAScript 提案在 Babel阶段 0)中实现。::

export default class MyObject {
  constructor (foo) {
    this._foo = foo;
  }

  publicFun () {
    return this::privateFun(">>");
  }
}

function privateFun (prefix) {
  return prefix + this._foo;
}