what are ES6 class getter and setter actually?

2020-08-10 06:16发布

问题:

what are actually getter and setter methods in ES6 class definition? are they infact prototype props ? for examle:

class Person{
  constructor(){};
  get name(){
    return 'jack';
  }
  set name(){
    // ???
  }
}

does this equals to Person.prototype.name = 'jack';

and another question, i ve seen examples of setters which utilizes the instance's prop like:

class Person{
  constructor(){
    this._name = 'jack';
  };
  get name(){
    return this._name;
  }
  set name(val){
    this._name = val;
  }
}

i dont wanna do this way, i want something like:

class Person{
  constructor(){};
  get name(){
    return 'jack';
  }
  set name(val){
    // like this
    // name = val;
  }
}

what could be done?

回答1:

Yes, it can be done: Just drop the setter/getter syntax and add a property to the class during initialization instead:

class Person{
    constructor(name){
        this.name = name;
    }
}

The getter/setter syntax exists for properties that must be calculated based on other properties, like the area property from a circle of a given radius:

class Circle {
    constructor (radius) {
        this.radius = radius;
    }
    get area () {
        return Math.PI * this.radius * this.radius;
    }
    set area (n) {
        this.radius = Math.sqrt(n / Math.PI);
    }
}

Or getting the full name of a Person object with firstName and lastName properties. You get the idea.



回答2:

As per MDN , The get syntax binds an object property to a function that will be called when that property is looked up.

Here you are returning just a string 'jack' it is not binding to any property.

Interestingly console.log(Person.prototype.name) logs jack

But Person.hasOwnProperty(name) logs false

also once we create instance of Person call i.e const x = new Person();

console.log(x.name) -> this throws error, cant read property x.name because x.hasOwnProperty(name) is false

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get



回答3:

I know this is a late response, but it doesn't look like anyone followed up on your response:

we know that class is infact a shorthand for prototype, in constructor method, we can instantilize the object. however, what i want is to define a prop in its prototype within class definition but outside the constructor method

You can just continue to declare the class as you did:

class Circle {
    constructor (radius) {
        this._radius = radius;
    }
}

And then define the properties like this:

Object.defineProperties(obj, {
    radius: {
        get: function () {
          return this._radius;
        },
        set: function (n) {
            this._radius = n;
        }
    },
    area: {
        get: function () {
          return Math.PI * this._radius * this._radius;
        },
        set: function (n) {
            this._radius = Math.sqrt(n / Math.PI);
        }
    }
});

or whatever getters and setters you want.

I gave the actual _radius member a leading underscore to differentiate it as the member variable separate from the radius property being added, since they'd both be this.radius otherwise, leading to a stack overflow if you try to set it.

But you asked about putting the prop definitions in a separate function, and my first thought would be how to this with multiple separate instances of a Circle...

So here is a full working example with two Circle definitions, adding the props from a separate function, along with a CodePen of it here: https://codepen.io/appurist/pen/ZEbOdeB?editors=0011

class Circle {
  constructor(r) {
    this._radius = r;
    addProps(this);
  }
}

function addProps(obj) {
  Object.defineProperties(obj, {
    radius: {
      get: function () {
        return this._radius;
      },
      set: function (n) {
        this._radius = n;
      }
    },
    area: {
      get: function () {
        return Math.PI * this._radius * this._radius;
      },
      set: function (n) {
        this._radius = Math.sqrt(n / Math.PI);
      }
    }
  });
}

let circle = new Circle(7);
let circle2 = new Circle(2);

console.log(`circle radius and area are: ${circle.radius} ${circle.area}`);
circle.radius = 4;
console.log(`circle radius and area now: ${circle.radius} ${circle.area}`);
circle.area = 78.53981633974483;
console.log(`circle radius and area now: ${circle.radius} ${circle.area}`);

console.log(`circle2 radius and area are: ${circle2.radius} ${circle2.area}`);
circle2.radius = 3;
console.log(`circle2 radius and area now: ${circle2.radius} ${circle2.area}`);
circle2.area = 50.26548245743669;
console.log(`circle2 radius and area now: ${circle2.radius} ${circle2.area}`);

Output of the above is:

circle radius and area are: 7 153.93804002589985
circle radius and area now: 4 50.26548245743669
circle radius and area now: 5 78.53981633974483

circle2 radius and area are: 2 12.566370614359172
circle2 radius and area now: 3 28.274333882308138
circle2 radius and area now: 4 50.26548245743669