如何在 javascript 中封装数据,而无需在每个对象实例中重复函数

How to encapsulate data in javascript without function duplication in every object instance?

本文关键字:对象 实例 函数 javascript 封装 数据      更新时间:2023-09-26

我在JavaScript中创建了一个具有公共和私有属性的类 - 数据和对这些数据进行操作的方法。某些数据是私有的,不应通过"."(点) 类实例中的运算符。有没有办法避免每个类实例的方法重复?

function MyClass() {
    let privateVar;
    let publicVar;
    function publicFun() {
        // do something
    }
    function privateFun(){
        // do something else
    }
    this.v = publicVar;
    this.f = publicFun;
}
let obj1 = new MyClass();
let obj2 = new MyClass();   // publicFun and privateFun methods duplication

ClassName.prototype方法需要所有类数据的完全公共 API。所以这对我不起作用。

如果我

理解正确,这是我的例子:

  1. 方法仅在包装函数中定义一次(因此它们不会在每个实例上声明)
  2. 您可以创建对象的实例,这些对象都将引用相同的方法,并且可以公开数据。

下面是一个小提琴示例:

function wrapper() {
  //Methods defined only once
  function method() {
    alert("this is method");
  }
  function methodWithParams(param, callback) {
    var paramsVar = param;
    function realMethodHere() {
      alert("We passed a param: " + paramsVar);
      paramsVar = "Changed"
      callback(paramsVar);
      alert("Now we cahnged the param's value to: " + paramsVar + ", rerun the method to verify");
    }
    return realMethodHere;
  }
  //Class constructor
  function classConstructor() {
    //Private
    var privateData = "Private"
    function privateFunction() {
      alert("this is some private function, inaccesible");
    }
    //This callback was addedto allow yo uto change private data.
    function privateDataChangerCallback(param) {
      privateData = param;
    }

    //Public
    this.publicData = "Public"
    this.callMethod = method;
    this.paramMethod = methodWithParams(privateData, privateDataChangerCallback);
  }

  return classConstructor;
}
var classDefinition = wrapper();
var classInstance = new classDefinition();
classInstance.callMethod(); //method without param
classInstance.paramMethod(); //method with exposed Private data
//rerunning the method to see what the value is:
classInstance.paramMethod(); //method with exposed Private data

您可以尝试使用TypeScript,它是一个支持OOP的JavaScript库,因此您可以像C#或Java一样编写代码,编译器将为您生成真正的JavaScript。

如果我理解正确,您可以在类定义中添加一个参数,并且基于此参数,您可以选择在返回对象中包含其他属性。

样本

function myClass(option) {
  var myFunc1 = function() {}
  var myFunc2 = function() {}
  var myFunc3 = function() {}
  var myFunc4 = function() {}
  var myFunc5 = function() {}
  var finalProps = {
    myFunc1: myFunc1,
    myFunc2: myFunc2,
  }
  switch (option) {
    case "all":
      finalProps["myFunc5"] = myFunc5;
    case "more":
      finalProps["myFunc3"] = myFunc3;
      finalProps["myFunc4"] = myFunc4;
      break;
  }
  return finalProps;
}
(function() {
  var f1 = new myClass();
  var f2 = new myClass("more");
  var f3 = new myClass("all");
  console.log(f1, f2, f3)
})()

您可以在constructor函数中创建独立函数:

var HelloWorld = (function () {
	function anonymouse() {
		return "MUHAHAHA! ALL MINE!!!";
	}
    function HelloWorld() {
        this.greeting = "Hello World";
    }
    //public
    HelloWorld.prototype.greet = function () {
        console.log("Hello, " + this.greeting + " " + anonymouse());
    };
    return HelloWorld;
}());
var greeter = new HelloWorld();
greeter.greet();
console.log(greeter);

但这确实有在类的所有实例上复制所述函数的副作用。

或者,可以创建一个命名空间来隐藏它,并从那里引用你的函数。这将消除重复函数问题:

var MySecretClasses;
(function (MySecretClasses) {
    function anonymouse() {
        return "MUHAHAHA! ALL MINE!!!";
    }
    var HelloWorld = (function () {
        function HelloWorld() {
            this.greeting = "Hello World";
        }
        //public
        HelloWorld.prototype.greet = function () {
            console.log("Hello, " + this.greeting + " " + anonymouse());
        };
        return HelloWorld;
    }());
    MySecretClasses.HelloWorld = HelloWorld;
})(MySecretClasses || (MySecretClasses = {}));
var greeter = new MySecretClasses.HelloWorld();
greeter.greet();
console.log(MySecretClasses);
console.log(greeter);

打字稿

正如Shlomi Haver指出的那样,你可以使用TypeScript。

module MySecretClasses {
    function anonymouse() {
            return "MUHAHAHA! ALL MINE!!!";
    } 
    export class HelloWorld {
        greeting: string = "Hello World";
        constructor() {
        }
        //public
        public greet() {
            console.log("Hello, " + this.greeting + anonymouse());
        }
    }
}
var  greeter = new MySecretClasses.HelloWorld();
greeter.greet();
console.log(greeter);