Search code examples
javascriptfunctionobjectecmascript-6javascript-objects

How can I provide protection and confidentiality?


I want to restrict access to certain things in the JavaScript language from the outside. I've done some research on this, but I haven't been able to get anything I want. I know the underscore doesn't provide complete protection. When I try to reach from outside, I can easily reach. I'm going to write a sample code.

  function Car(){
    this._mileage = 0;
  }

  Car.prototype.drive = function(miles){
    if(typeof miles == 'number' && miles > 0){
      this._mileage += miles;
    }else{
      throw new Error("Sadece pozitif sayılar girin");
    }
  };

  Car.prototype.readMileage = function(){
    return this._mileage;
  }
  
  var hondo = new Car();
    console.log('old: '+hondo._mileage);
  hondo._mileage = 100;
  console.log('new: '+hondo._mileage);

As you can see: Although I used underscores, I could easily access from outside the classroom.

Another method

I found a method in my research. But I don't quite understand that either.

  var Car = (function(){
    var _ = PrivateParts.createKey(); // createKey = ?

    function Car(mileage){
      _(this).mileage = mileage;
    }
    Car.prototype.drive = function(miles){
      if( typeof miles == 'number' && miles > 0){
        _(this).mileage += miles;
      }else{
        throw new Error('drive only accepts positive numbers');
      }
    }
    Car.prototype.readMileage = function(){
      return _(this).mileage;
    }
    return Car;
  }());


Solution

  • Your second code is generally on the right track, though you need to define privateParts as something first. It also seems a bit too complicated at the moment.

    The idea is to save the variable in a closure; due to normal scoping rules, a variable can't be accessed outside where it's defined:

    const fn = (() => {
      const foo = 'foo';
      return () => 'foo is: ' + foo;
    })();
    
    // at this point, the contents of the "foo" variable are not visible to the outside,
    // you can only call the deliberately exposed function:
    console.log(fn());

    Similarly, with a class, you can save all properties you want to keep private in an Map indexed by the instance used: keep the Map scoped to just the class, and not the outside, and everything you put on the Map won't be visible to the outside:

    const Car = (() => {
      const map = new WeakMap();
      return class Car {
        constructor(mileage) {
          map.set(this, { mileage });
        }
        drive(miles) {
          if (typeof miles == 'number' && miles > 0) {
            map.get(this).mileage += miles;
          } else {
            throw new Error('drive only accepts positive numbers');
          }
        }
        readMileage() {
          return map.get(this).mileage;
        }
      }
    })();
    
    var hondo = new Car(50);
    console.log('old: '+hondo._mileage);
    hondo._mileage = 100;
    console.log('new: '+hondo._mileage);
    console.log(hondo.readMileage());
    hondo.drive(100);
    console.log('newer: '+hondo._mileage);
    console.log(hondo.readMileage());

    The Map is basically just an object indexed by each this (each instance of Car). Because its values can only be retrieved inside the Car closure, it's an effective way of making sure the information is not exposed to the outside.

    That said, this doesn't prevent clients from looking at your source code - no client-side code is truly private. If you have sensitive information, you should only send it to the client in the first place if they have to know it. Using a technique like this will not prevent the client from looking at your code and possibly intercepting information sent. (Nefarious scripts can do something similar, especially if given the opportunity to run before your script runs.) So what this implements isn't so much confidential, so much as it provides reasonable but not airtight restrictions on how other well-behaved scripts can access data.