Javascript getters and setters - recursion issue

Asked
Active3 hr before
Viewed126 times

7 Answers

javascript
90%

3 there are no private/public properties in js, it's just a name conflict. you need a state var separate from your access property for getters. – dandavis Jun 12 '15 at 18:36 ,It's naming convention used to identify private variables or properties. The _ has no sign particular significance to JS.,Can someone please help me understand the significance of the '_' character in the setters and getters of javascript. For example I have the following code which works fine.,Connect and share knowledge within a single location that is structured and easy to search.

Can someone please help me understand the significance of the '_' character in the setters and getters of javascript. For example I have the following code which works fine.

var user = {
   get name() {
      return this._name;
   },
   set name(value) {
      this._name = value;
   }
};

var me = user;
me.name = "Rob";

alert(me.name);
load more v
88%

Here you trigger an infinite stack of recursive calls, and you crashed your browser.,The get method always returns the same value to us. No matter what value we assign to “a.” In this case, foo.a always returns 1.,In case 2.2 The same idea applies to the setter.,I hope this little article has helped you understand the danger that getters and setters can bring to the code.

The get method always returns the same value to us. No matter what value we assign to “a.” In this case, foo.a always returns 1.

var foo = {
   get a() {
      return 1
   }
} //Another way (deprecated)//__defineGetter__ and this.__defineSetter__ are deprecated!//var foo = {}//foo.__defineGetter__('a', () => 1);foo.a=5;foo.b=2const sum = (a, b) => a +b;console.log(sum(foo.a, foo.b));// 5+2 = 3!!
load more v
72%

This issue also appears if the same variable is used in the getter., The JavaScript exception "too much recursion" or "Maximum call stack size exceeded" occurs when there are too many function calls, or a function is missing a base case. ,InternalError: too much recursion,A re-introduction to JavaScript

Error: Out of stack space(Edge)
InternalError: too much recursion(Firefox)
RangeError: Maximum call stack size exceeded(Chrome)
load more v
65%

set - to define a setter method to set the property value,In JavaScript, getter methods are used to access the properties of an object. For example,,get - to define a getter method to get the property value,In JavaScript, setter methods are used to change the values of an object. For example,

Here's an example of data property that we have been using in the previous tutorials.

const student = {

   // data property
   firstName: 'Monica';
};
load more v
75%

JavaScript Getters and Setters are functions that get invoked when an object’s property is accessed or updated. ,Our new properties are only accurate so long as our object’s state does not change. If we update the object’s properties we will need to run our extend function again:,  ECMA 5 defines a similar syntax for defining getters and setters via the Object.defineProperty function.,  Finally there’s a couple of methods you’re sure to need. They let us know which properties are represented by getters or setters. They are as fundamental to object recursion as our old friend hasOwnProperty:

JavaScript Getters and Setters are functions that get invoked when an object’s property is accessed or updated.

var rectangle = {
   height: 20,
   width: 10
};

rectangle.__defineGetter__("area", function() {
   return rectangle.height * rectangle.width;
});
rectangle.__defineSetter__("area", function(val) {
   alert("sorry, you can't update area directly");
});

rectangle.area; //200
rectangle.area = 150; //alerts "sorry..." etc.
rectangle.area; //still 200

 
There’s also an alternative, more declarative syntax that looks prettier but does not allow getters and setters to be assigned dynamically once the object has been created. Moreover I find it less expressive in terms of the JavaScript object model – think function expression vs. function declaration:

var rectangle = {
   height: 20,
   width: 10,
   get area() {
      return rectangle.height * rectangle.width;
   },
   set area(val) {
      alert("sorry, you can't update area directly");
   }
}

 
ECMA 5 defines a similar syntax for defining getters and setters via the Object.defineProperty function.

var rectangle = {
   width: 20,
   height: 10,
};

Object.defineProperty(rectangle, "area", {
   get: function() {
      return this.width * this.height;
   },
   set: function(val) {
      alert("no no no");
   }
});

 
Finally there’s a couple of methods you’re sure to need. They let us know which properties are represented by getters or setters. They are as fundamental to object recursion as our old friend hasOwnProperty:

rectangle.__lookupGetter__("area"); //area Getter function
rectangle.__lookupSetter__("area"); //area Setter function
rectangle.__lookupGetter__("width"); //undefined
rectangle.__lookupSetter__("width"); //undefined

First lets see what happens when we try to simply add these properties directly:

//Bad example - apply array properties directly
var myObj = {
   a: 123,
   b: 345,
   c: 546,
}

//iterate properties and assign each value to indexed property
var index = 0;
for (var prop in myObj) {
   myObj[index] = myObj[prop];
   index++;
}
myObj.length = //??????

This seems more promising. We can easily assign a getter for the array-like properties:

function extendAsArray(obj) {
   var index = 0;
   for (var prop in obj) {
      (function(thisIndex, thisProp) {
         obj.__defineGetter__(thisIndex, function() {
            return obj[thisProp]
         });
      })(index, prop)
      index++;
   };
   obj.__defineGetter__("length", function() {
      return index
   });
   return obj;
}

 
Lets try it out…

var myObj = {
   a: 123,
   b: 345,
   c: 546,
}

extendAsArray(myObj);

myObj[1]; //345
myObj.length; //3
myObj[2] == myObj.c; //true

 
OK much better – now dare we try a function from Array.prototype?

[].slice.call(myObj, 1); //[345, 546] 

Our new properties are only accurate so long as our object’s state does not change. If we update the object’s properties we will need to run our extend function again:

myObj.d = 764;
extendAsArray(myObj);
myObj.length;
8!! ??

 
Why did the length suddenly double? Because our function is iterating every property and second time around that includes our shiny new getters. We need to modify the function so that the iteration skips getters. We can do this with the built-in __lookupGetter__ function:

function extendAsArray(obj) {
   var index = 0;
   for (var prop in obj) {
      if (!obj.__lookupGetter__(prop)) {
         (function(thisIndex, thisProp) {
            obj.__defineGetter__(thisIndex, function() {
               return obj[thisProp]
            });
         })(index, prop)
         index++;
      }
   };
   obj.__defineGetter__("length", function() {
      return index
   });
   return obj;
}

Turns out there’s still one more problem. What if we try running a function (which is, after all an object) through our extend function?

extendAsArray(alert); //TypeError: redeclaration of const length 

Here is our function updated accordingly:

function extendAsArray(obj) {
   if (obj.length === undefined || obj.__lookupGetter__('length')) {
      var index = 0;
      for (var prop in obj) {
         if (!obj.__lookupGetter__(prop)) {
            (function(thisIndex, thisProp) {
               obj.__defineGetter__(thisIndex, function() {
                  return obj[thisProp]
               });
            })(index, prop)
            index++;
         }
      };
      obj.__defineGetter__("length", function() {
         return index
      });
   }
   return obj;
}

Consider an object that positions and sizes a lightbox, or similar:

var myObj = {
   left: 50,
   top: 20,
   width: 10,
   height: 10
}

 
Let’s extend this object and subject it to a broad swathe of the array prototype. We’ll cache an array instance to cut down on object creation.

extendAsArray(myObj);

var arr = [];
arr.join.call(myObj, ', '); //"50 ,20 ,10, 10" 
arr.slice.call(myObj, 2);
[10, 10]
arr.map.call(myObj, function(s) {
   return s + ' px'
}).join(', ');
//"50px ,20px ,10px, 10px" 
arr.every.call(myObj, function(s) {
   return !(s % 10)
});
//true (all values divisible by 10)
arr.forEach.call(myObj, function(s) {
   window.console && console.log(s)
});
//(logs all values)

Now this looks like your latest expense account:

var expenses = {
   hotel: 147.16,
   dinner: 43.00,
   drinks: 15.20,
   taxi: 13.00,
   others: 12.15
}

 
…using extendAsArray we can concisely obtain the biggest expense and also sum the expenses:

extendAsArray(expenses);
var biggestExpense =
   Math.max.apply(null, [].slice.call(expenses)); //147.16
var totalExpenses = [].reduce.call(expenses, function(t, s) {
   return t + s
}); //230.51

Prototypes are regular objects too. So, for example, we can easily return an array containing all functions in JQuery’s fx prototype:

var fxP = extendAsArray(jQuery.fx.prototype);
//make an array of all functions in jQuery.fx.prototype
[].filter.call(fxP, function(s) {
   return typeof s == "function"
}); //(6 functions)
load more v
40%

Your skill setter is calling your skill setter which is blowing the callstack (infinite recursion). Rename this.skill to this._skill or something.,Typically when using getters and setters, convention is to prefix the actual member variable with an underline.,As others have mentioned, you've created an infinite loop because you called this.skill = ... in your constructor, which triggers the setter, which is defined as this.skill = ..., which will call the setter ad ininitum.,As stated, your skill setter is calling your skill setter is calling your skill setter is calling your skill setter...

Typically when using getters and setters, convention is to prefix the actual member variable with an underline.

private _skill;
public get skill() {
   return this._skill;
}
public set skill(value) {
   this._skill = value;
}
22%

I figured out where my issue lies: a) I used the wrong formula in the setter and more importantly b) I wasn’t calling this.temperature in the getter.,Looks like you might have do the challenge a bit the other way around. You need to write getter and setter for the temperature, not the Celsius or Fahrenheit.,@tanner.wiltshire I believe you where doing just like the book author example.,Challenge: Use getters and setters to Control Access to an Object

Your code so far

// Only change code below this line
class Thermostat {
   constructor(temperature) {
      this.temperature = temperature;
   }
   get celsius() {
      return ((5 / 9) * (this.temperature - 32));
   }
   set celsius(newTemp) {
      this.temperature = (newTemp * 9 / 5 + 32);
   }
}
// Only change code above this line

const thermos = new Thermostat(76); // Setting in Fahrenheit scale

console.log(thermos.celsius);
// let temp = thermos.temperature; // 24.44 in Celsius
//thermos.temperature = 26;
//temp = thermos.temperature; // 26 in Celsius
load more v

Other "javascript-undefined" queries related to "Javascript getters and setters - recursion issue"