Reducing Multiple Variables in JavaScript - javascript

Can I reduce multiple variables in JavaScript?
For example if I have 3 variables:
var foo = 10;
var boo = 15;
var lol = 15;
//Normal syntax:
foo -=1; // -> foo will be 9
boo -=1; // -> boo will be 14
lol -=1; // -> lol will be 14
Is there an option to do it with one line? or better syntax?
For example: foo ,boo ,lol -=1;

No, you cannot. Standard JavaScript does not give this opportunity. The worse thing that you nearly cannot do it functionally as well. lol -=1; or lol--; is just a shortcut for lol = lol - 1;. So if you will try to write a function, which does that for you e.g.:
function reduce() {
for (var i = 0; i < arguments.length; i++) {
arguments[i] = arguments[i] - 1;
}
}
and then call it like
reduce(foo, bar, lol);
it just won't work because you pass primitive numbers (not references). Every time you change the number inside of the function it won't change the number itself but it will return a new number instead.
This could be solved by using some object to store all the variables, e.g.:
var vars = {
foo: 12,
bar: 13,
lol: 14
};
function reduce(variables) {
for (variable in variables) {
if (variables.hasOwnProperty(variable)) {
variables[variable] -= 1;
}
}
return variables;
}
reduce(vars);
But this is not a list of 3 variables, this is kind of a context you attach them to.
If you do the stuff in a global scope (e.g. in a window without wrapping the stuff in a function), you can combine both ways above into one (Window stores all var-declared variables inside):
function reduce(vars) {
var varslist = vars.split(',');
for (var i = 0; i < varslist.length; i++) {
window[varslist[i]] -= 1;
}
}
reduce('foo,boo,lol');
but as soon as you move it to some subcontext it won't work any longer. Also it looks very nasty. I would rather prefer the second solution with vars object representing your variables context.

You can do it with one line, but you still have to repeat the operation:
foo--, bar--, lol--;
Read about the comma operator. It can be useful, but it's usually not very readable.
I wouldn't even combine var statements into 1:
var foo = 1, bar = 2, lol = 3;
because if a var changes, the entire line changes.
I used to do this:
var foo = 1,
bar = 2,
lol = 3;
but that's bad practice too, because deleting foo or lol will change more than just 1 line (because the var prefix or ; suffix).
Sometimes verbosity is good:
var foo = 10;
var boo = 15;
var lol = 15;
foo -= 1;
boo -= 1;
lol -= 1;

Related

Javascript function: change value of a single variable InPlace

The function reverseArrayInPlace(array) is as per solution in eloquentJS. The reverseArrayInPlace function works, by altering the arrayValue as expected. A similar function written for a single variable does not work as expected. In the code, x should come out as 25, but comes out as 20.
//function from eloquentJS solutions, working as expected
`` function reverseArrayInPlace(array) {
for (let i = 0; i < Math.floor(array.length / 2); i++) {
let old = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = old;
}
return array;
}
let arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// working as expected, returns → [5, 4, 3, 2, 1]
// Writing similar function for a single variable
function changeInPlace(a) {
a += 5;
return a;
}
let x = 20;
changeInPlace(x);
console.log(x);
// Not working as expected returns, 20 instead of 25
`
Snippet of the code
Assign changeInPlace to a variable at second last line, and then print that variable in console. It should work.
The problem is that you are returning your calculated variable and not logging it. The one you are logging remains 20.
You must use your function as below :
let variable = changeInPlace(x)
Full code must be like :
function changeInPlace(a) {
a += 5;
return a;
}
let x = 20;
x = changeInPlace(x);
console.log(x);
// x should come out as 25
If for any reason you want to edit a variable value directly, you must access it globally like this:
function changeInPlace() {
x += 5;
return x;
}
let x = 20;
changeInPlace(x);
console.log(x);
For each time you want to change the value in a variable, it needs to be called out again in the form of a declaration. Therefore, output of your function needs to be declared as new value for variable x. Like below:
Your function
// Writing similar function for a single variable
function changeInPlace(a) {
a += 5;
return a;
}
let x = 20;
changeInPlace(x);
console.log(x);
// x should come out as 25
Mine
// Writing similar function for a single variable
function changeInPlace(a) {
return a += 5; // Made a small tweak to your function,
}
let x = 20;
x = changeInPlace(x); // this stores the output of the function in the same variable
console.log(x);
This should give you the desired output, assume this is what you've been asking for if otherwise let me know
Answered by Marijn (author of eloquentJS):
You can't change numbers in JavaScript, only create new ones, so there's no way for a function to change the value of a binding whose value is passes as argument to that function. See for example this section in the book: https://eloquentjavascript.net/04_data.html#h_C3n45IkMhg

Function in "natural language"

I've made a function "ADD" which modifies the value of a variable :
function ADD(xs, n)
{
var nom_variable = xs;
var XS = eval(xs);
nouvelle_valeur = eval(nom_variable + "=XS+n");
}
var x = 5 ;
ADD("x",5); // now x = 10
I would like that the first argument of the function ADD is x, not "x". Is this possible ?
I want my students to write algorithms in a way similar to natural language.
Thanks !
You can't pass x as if it were a reference, but you could construct a functional reference (or Lens) although you are still not passing x but a variable that is a reference of x.
var x = 5;
var xRef = {
get : function(){
return x;
},
set : function(val){
x = val;
}
}
function add(ref, n){
var oldVal = ref.get();
ref.set(oldVal+n);
}
add(xRef, 5);
console.log(x);
It's definitely not pretty though.

Assigning value to object from the onclick function

I'm trying to create a function to handle purchase of the upgrades. Targeting particular upgrade will by done by passing object as parameter to the function (up) and value of upgrade (amount).
This is my player object:
var player = {
tech: 0,
energy: 0,
upgrades:{
engi5Perc: 0,
engi25Perc: 0,
andro5Perc: 0,
andro25Perc: 0,
robot5Perc: 0,
robot25Perc: 0
}
}
This is my function:
function buyUpgrade(techcost, energycost, up, amount){
if(techcost <= player.tech && energycost <= player.energy){
player.tech -= techcost;
player.energy -= energycost;
up = amount;
console.log("Done, upgrade purchased");
}
}
My HTML:
<button type="button" onclick="buyUpgrade(1, 1, 'player.upgrades.engi5Perc', 0.005 )">Buy 5%</button>
There must be some sort of simple error in my function, and I spent good amount of time trying to figure it out. So far with no luck.
You're currently assigning the amount to the string 'player.upgrades.engi5Perc'. This doesn't work.
But you can use square brackets to address some object's property, whose name you only know at runtime, e.g. obj[propertyName] = value.
Here are some more examples to show the difference:
var obj = {foo: 'bar'};
var propertyName = 'foo';
// the following two assignments are essentially equal:
obj.foo = 'newBar';
obj[propertyName] = 'newBar';
// while this one is obviously assigning 'newBar' to the wrong property:
obj.propertyName = 'newBar';
// and this is what happens in your function:
'obj.foo' = 'newBar';
Try this:
function buyUpgrade(techcost, energycost, up, amount){
if(techcost <= player.tech && energycost <= player.energy){
player.tech -= techcost;
player.energy -= energycost;
player.upgrades[up] = amount;
console.log("Done, upgrade purchased");
}
}
and invoke that function with just the name of the upgrade:
buyUpgrade(1, 1, 'engi5Perc', 0.005 )

Two operation in one function

function test(a, b){
a = a + 2;
b = b + 5;
}
var a = 1;
var b = 2;
test(a, b);
console.log(a);
console.log(b);
This return 1 and 2, but i would like 3 and 7.
Is possible to make two operation in one function? This working if i use return, but how to use return to two operation?
live: http://jsfiddle.net/anCq6/
The reason you are getting 1 and 2 instead of 3 and 7 is because there are two different a and b variables. There's the a and b you declared outside the function, and there is the a and b which represent the values you passed into the function. (Basically, the parameters declared in the function's parentheses are newly declared variables.)
If you want to change the external a and b, change your test function to the following:
function test(x, y) {
a = x + 2;
b = y + 5;
}
Or, alternatively, don't pass a reference into the function, so that the a and b in the inner scope refer to the same a and b as the outer scope:
function test() {
a = a + 2;
b = b + 5;
}
Just send it back as an object...
function test(a, b){
a = a + 2;
b = b + 5;
return {a:a,b:b};
}
var a = 1;
var b = 2;
var test = test(a, b);
alert(test.a);
alert(test.b);
DEMO HERE
This doesn't work because since numbers are passed by value and not by reference, you're modifying the local copies of those variables, however the ones in the outer scope remain unmodified.
If you remove the a and b parameters from your function, you'll get the behavior that you want since the a and b parameters that are being modified will be the ones in the outer scope.
What are references?
Here's a pretty decent answer - Javascript by reference vs. by value
In short, only objects and arrays are passed by reference. Although in reality it's more complex than this depending on how functions are defined and syntax, at this point you can assume that anything that's defined by calling new or the syntactic shorthands [] ( array ) and {} ( object ) are passed by reference. Other types like numbers and strings are passed by value.
Another solution: because of how variable scope works in JavaScript, you can just remove the parameters of "test" function and it will work.
function test(){
a = a + 2;
b = b + 5;
}
function test(){
a = a + 2;
b = b + 5;
}
var a = 1;
var b = 2;
test();
console.log(a);
console.log(b);

Javascript prototype operator performance: saves memory, but is it faster?

I read here (Douglas Crockford) using prototype operator to add methods to Javascript classes saves also memory.
Then I read in this John Resig's article "Instantiating a function with a bunch of prototype properties is very, very, fast", but is he talking about using prototype in the standard way, or is he talking about his specific example in his article?
For example, is creating this object:
function Class1()
{
this.showMsg = function(string) { alert(string); }
}
var c = new Class1();
c.showMsg();
slower than creating this object, then?
function Class1() {}
Class1.prototype.showMsg = function(string) { alert(string); }
var c = new Class1();
c.showMsg();
P.S.
I know prototype is used to create inheritance and singleton object etc. But this question does not have anyhting to do with these subjects.
EDIT: to whom it might be interested also in performance comparison between a JS object and a JS static objet can read this answer below. Static object are definitely faster, obviously they can be usued only when you don't need more than one instance of the object.
Edit in 2021:
This question was asked in 2010 when class was not available in JS. Nowadays, class has been so optimized that there is no excuse not to use it. If you need to use new, use class. But back in 2010 you had two options when binding methods to their object constructors -- one was to bind functions inside the function constructor using this and the other was to bind them outside the constructor using prototype. #MarcoDemaio's question has very concise examples. When class was added to JS, early implementations were close in performance, but usually slower. That's not remotely true anymore. Just use class. I can think of no reason to use prototype today.
It was an interesting question, so I ran some very simple tests (I should have restarted my browsers to clear out the memory, but I didn't; take this for what it's worth). It looks like at least on Safari and Firefox, prototype runs significantly faster [edit: not 20x as stated earlier]. I'm sure a real-world test with fully-featured objects would be a better comparison. The code I ran was this (I ran the tests several times, separately):
var X,Y, x,y, i, intNow;
X = function() {};
X.prototype.message = function(s) { var mymessage = s + "";}
X.prototype.addition = function(i,j) { return (i *2 + j * 2) / 2; }
Y = function() {
this.message = function(s) { var mymessage = s + "";}
this.addition = function(i,j) { return (i *2 + j * 2) / 2; }
};
intNow = (new Date()).getTime();
for (i = 0; i < 10000000; i++) {
y = new Y();
y.message('hi');
y.addition(i,2)
}
console.log((new Date()).getTime() - intNow); //FF=5206ms; Safari=1554
intNow = (new Date()).getTime();
for (i = 0; i < 10000000; i++) {
x = new X();
x.message('hi');
x.addition(i,2)
}
console.log((new Date()).getTime() - intNow);//FF=3894ms;Safari=606
It's a real shame, because I really hate using prototype. I like my object code to be self-encapsulated, and not allowed to drift. I guess when speed matters, though, I don't have a choice. Darn.
[Edit] Many thanks to #Kevin who pointed out my previous code was wrong, giving a huge boost to the reported speed of the prototype method. After fixing, prototype is still around significantly faster, but the difference is not as enormous.
I would guess that it depends on the type of object you want to create. I ran a similar test as Andrew, but with a static object, and the static object won hands down. Here's the test:
var X, Y, Z, x, y, z;
X = function() {};
X.prototype.message = function(s) {
var mymessage = s + "";
}
X.prototype.addition = function(i, j) {
return (i * 2 + j * 2) / 2;
}
Y = function() {
this.message = function(s) {
var mymessage = s + "";
}
this.addition = function(i, j) {
return (i * 2 + j * 2) / 2;
}
};
Z = {
message: function(s) {
var mymessage = s + "";
},
addition: function(i, j) {
return (i * 2 + j * 2) / 2;
}
}
function TestPerformance() {
var closureStartDateTime = new Date();
for (var i = 0; i < 100000; i++) {
y = new Y();
y.message('hi');
y.addition(i, 2);
}
var closureEndDateTime = new Date();
var prototypeStartDateTime = new Date();
for (var i = 0; i < 100000; i++) {
x = new X();
x.message('hi');
x.addition(i, 2);
}
var prototypeEndDateTime = new Date();
var staticObjectStartDateTime = new Date();
for (var i = 0; i < 100000; i++) {
z = Z; // obviously you don't really need this
z.message('hi');
z.addition(i, 2);
}
var staticObjectEndDateTime = new Date();
var closureTime = closureEndDateTime.getTime() - closureStartDateTime.getTime();
var prototypeTime = prototypeEndDateTime.getTime() - prototypeStartDateTime.getTime();
var staticTime = staticObjectEndDateTime.getTime() - staticObjectStartDateTime.getTime();
console.log("Closure time: " + closureTime + ", prototype time: " + prototypeTime + ", static object time: " + staticTime);
}
TestPerformance();
This test is a modification of code I found at:
Link
Results:
IE6: closure time: 1062, prototype time: 766, static object time: 406
IE8: closure time: 781, prototype time: 406, static object time: 188
FF: closure time: 233, prototype time: 141, static object time: 94
Safari: closure time: 152, prototype time: 12, static object time: 6
Chrome: closure time: 13, prototype time: 8, static object time: 3
The lesson learned is that if you DON'T have a need to instantiate many different objects from the same class, then creating it as a static object wins hands down. So think carefully about what kind of class you really need.
So I decided to test this as well. I tested creation time, execution time, and memory use. I used Nodejs v0.8.12 and the mocha test framework running on a Mac Book Pro booted into Windows 7. The 'fast' results are using prototypes and the 'slow' ones are using module pattern. I created 1 million of each type of object and then accessed the 4 methods in each object. Here are the results:
c:\ABoxAbove>mocha test/test_andrew.js
Fast Allocation took:170 msec
·Fast Access took:826 msec
state[0] = First0
Free Memory:5006495744
·Slow Allocation took:999 msec
·Slow Access took:599 msec
state[0] = First0
Free Memory:4639649792
Mem diff:358248k
Mem overhead per obj:366.845952bytes
? 4 tests complete (2.6 seconds)
The code is as follows:
var assert = require("assert"), os = require('os');
function Fast (){}
Fast.prototype = {
state:"",
getState:function (){return this.state;},
setState:function (_state){this.state = _state;},
name:"",
getName:function (){return this.name;},
setName:function (_name){this.name = _name;}
};
function Slow (){
var state, name;
return{
getState:function (){return this.state;},
setState:function (_state){this.state = _state;},
getName:function (){return this.name;},
setName:function (_name){this.name = _name;}
};
}
describe('test supposed fast prototype', function(){
var count = 1000000, i, objs = [count], state = "First", name="Test";
var ts, diff, mem;
it ('should allocate a bunch of objects quickly', function (done){
ts = Date.now ();
for (i = 0; i < count; ++i){objs[i] = new Fast ();}
diff = Date.now () - ts;
console.log ("Fast Allocation took:%d msec", diff);
done ();
});
it ('should access a bunch of objects quickly', function (done){
ts = Date.now ();
for (i = 0; i < count; ++i){
objs[i].setState (state + i);
assert (objs[i].getState () === state + i, "States should be equal");
objs[i].setName (name + i);
assert (objs[i].getName () === name + i, "Names should be equal");
}
diff = Date.now() - ts;
console.log ("Fast Access took:%d msec", diff);
console.log ("state[0] = " + objs[0].getState ());
mem = os.freemem();
console.log ("Free Memory:" + mem + "\n");
done ();
});
it ('should allocate a bunch of objects slowly', function (done){
ts = Date.now ();
for (i = 0; i < count; ++i){objs[i] = Slow ();}
diff = Date.now() - ts;
console.log ("Slow Allocation took:%d msec", diff);
done ();
});
it ('should access a bunch of objects slowly', function (done){
ts = Date.now ();
for (i = 0; i < count; ++i){
objs[i].setState (state + i);
assert (objs[i].getState () === state + i, "States should be equal");
objs[i].setName (name + i);
assert (objs[i].getName () === name + i, "Names should be equal");
}
diff = Date.now() - ts;
console.log ("Slow Access took:%d msec", diff);
console.log ("state[0] = " + objs[0].getState ());
var mem2 = os.freemem();
console.log ("Free Memory:" + mem2 + "\n");
console.log ("Mem diff:" + (mem - mem2) / 1024 + "k");
console.log ("Mem overhead per obj:" + (mem - mem2) / count + 'bytes');
done ();
});
});
Conclusion: This backs up what others in this post have found. If you are constantly creating objects then the prototype mechanism is clearly faster. If your code spends most of its time accessing objects then the module pattern is faster. If you are sensitive about memory use, the prototype mechanism uses ~360 bytes less per object.
Intuitively, it seems that it would be more memory-efficient and faster to create functions on the prototype: the function's only created once, not each time a new instance is created.
However, there will be a slight performance difference when it's time to access the function. When c.showMsg is referenced, the JavaScript runtime first checks for the property on c. If it's not found, c's prototype is then checked.
So, creating the property on the instance would result in slightly faster access time - but this might only be an issue for a very deep prototype hierarchy.
We need to separate object construction and usage.
When declaring a function on a prototype, it is shared between all instances. When declaring a function in a constructor, this is recreated every time new instance is made. Given that, we need to benchmark construction and usage separately to have better results. That is what I did and want to share the results with you. This benchmark does not test for speed of construction.
function ThisFunc() {
this.value = 0;
this.increment = function(){
this.value++;
}
}
function ProtFunc() {
this.value = 0;
}
ProtFunc.prototype.increment = function (){
this.value++;
}
function ClosFunc() {
var value = 0;
return {
increment:function(){
value++;
}
};
}
var thisInstance = new ThisFunc;
var iterations = 1000000;
var intNow = (new Date()).getTime();
for (i = 0; i < iterations; i++) {
thisInstance.increment();
}
console.log(`ThisFunc: ${(new Date()).getTime() - intNow}`); // 27ms node v4.6.0
var protInstance = new ProtFunc;
intNow = (new Date()).getTime();
for (i = 0; i < iterations; i++) {
protInstance.increment();
}
console.log(`ProtFunc: ${(new Date()).getTime() - intNow}`); // 4ms node v4.6.0
var closInstance = ClosFunc();
intNow = (new Date()).getTime();
for (i = 0; i < iterations; i++) {
closInstance.increment();
}
console.log(`ClosFunc: ${(new Date()).getTime() - intNow}`); // 7ms node v4.6.0
From these results we can see that the prototype version is the fastest (4ms), but the closure version is very close (7ms). You may still need to benchmark for your particular case.
So:
We can use prototype version when we need to have every bit of performance or share functions between instances.
We can use other versions when what we want is the features they provide. (private state encapsulation, readability etc.)
PS: I used Andrew's answer as a reference. Used the same loops and notation.
I ran my own tests.
The first conclusion is, that static access is actually slower than real prototyping. Interestingly, the Version 23 of this test has a flawed prototyping (Variable X) in it, which just returns the completely overridden prototype object over and over again and when I was creating my test, this prototyping was still slower than my "real prototype" test.
Anyway, to the answer: Unless my test is flawed, it shows that real prototyping is fastest. It beats or is at least equal to the static object when ignoring instantiation. this-assignments on instantiation and private variables are both much slower. I wouldn't have guessed private variables would be this slow.
It might be of interest that I extended the prototype Object with jQuery.extend in between and it was about the same speed as the direct assignment. The extend was outside the test itself, of course. At least this is a way to circumvent writing annoying ".prototype."-Parts all the time.
High Resolution Browser Performance API Tests
None of the tests here are taking advantage of the performance API for high resolution testing so I wrote one that will show current fastest results for many different scenarios including 2 that are faster than any of the other answers on most runs.
Fasted in each category (10,000 iterations)
Property access only (~0.5ms): { __proto__: Type }
Looping object creation with property access (<3ms): Object.create(Type)
The code uses ES6 without babel transpilation to ensure accuracy. It works in current chrome. Run the test below to see the breakdown.
function profile () {
function test ( name
, define
, construct
, { index = 0
, count = 10000
, ordinals = [ 0, 1 ]
, constructPrior = false
} = {}
) {
performance.clearMarks()
performance.clearMeasures()
const symbols = { type: Symbol('type') }
const marks = (
{ __proto__: null
, start: `${name}_start`
, define: `${name}_define`
, construct: `${name}_construct`
, end: `${name}_end`
}
)
performance.mark(marks.start)
let Type = define()
performance.mark(marks.define)
let obj = constructPrior ? construct(Type) : null
do {
if(!constructPrior)
obj = construct(Type)
if(index === 0)
performance.mark(marks.construct)
const measureOrdinal = ordinals.includes(index)
if(measureOrdinal)
performance.mark(`${name}_ordinal_${index}_pre`)
obj.message('hi')
obj.addition(index, 2)
if(measureOrdinal)
performance.mark(`${name}_ordinal_${index}_post`)
} while (++index < count)
performance.mark(marks.end)
const measureMarks = Object.assign (
{ [`${name}_define`]: [ marks.start, marks.define ]
, [`${name}_construct`]: [ marks.define, marks.construct ]
, [`${name}_loop`]: [ marks.construct, marks.end ]
, [`${name}_total`]: [ marks.start, marks.end ]
}
, ordinals.reduce((reduction, i) => Object.assign(reduction, { [`${name}_ordinal_${i}`]: [ `${name}_ordinal_${i}_pre`, `${name}_ordinal_${i}_post` ] }), {})
)
Object.keys(measureMarks).forEach((key) => performance.measure(key, ...measureMarks[key]))
const measures = performance.getEntriesByType('measure').map(x => Object.assign(x, { endTime: x.startTime + x.duration }))
measures.sort((a, b) => a.endTime - b.endTime)
const durations = measures.reduce((reduction, measure) => Object.assign(reduction, { [measure.name]: measure.duration }), {})
return (
{ [symbols.type]: 'profile'
, profile: name
, duration: durations[`${name}_total`]
, durations
, measures
}
)
}
const refs = (
{ __proto__: null
, message: function(s) { var mymessage = s + '' }
, addition: function(i, j) { return (i *2 + j * 2) / 2 }
}
)
const testArgs = [
[ 'constructor'
, function define() {
return function Type () {
this.message = refs.message
this.addition = refs.addition
}
}
, function construct(Type) {
return new Type()
}
]
, [ 'prototype'
, function define() {
function Type () {
}
Type.prototype.message = refs.message
Type.prototype.addition = refs.addition
return Type
}
, function construct(Type) {
return new Type()
}
]
, [ 'Object.create'
, function define() {
return (
{ __proto__: null
, message: refs.message
, addition: refs.addition
}
)
}
, function construct(Type) {
return Object.create(Type)
}
]
, [ 'proto'
, function define() {
return (
{ __proto__: null
, message: refs.message
, addition: refs.addition
}
)
}
, function construct(Type) {
return { __proto__: Type }
}
]
]
return testArgs.reduce(
(reduction, [ name, ...args ]) => (
Object.assign( reduction
, { [name]: (
{ normal: test(name, ...args, { constructPrior: true })
, reconstruct: test(`${name}_reconstruct`, ...args, { constructPrior: false })
}
)
}
)
)
, {})
}
let profiled = profile()
const breakdown = Object.keys(profiled).reduce((reduction, name) => [ ...reduction, ...Object.keys(profiled[name]).reduce((r, type) => [ ...r, { profile: `${name}_${type}`, duration: profiled[name][type].duration } ], []) ], [])
breakdown.sort((a, b) => a.duration - b.duration)
try {
const Pre = props => React.createElement('pre', { children: JSON.stringify(props.children, null, 2) })
ReactDOM.render(React.createElement(Pre, { children: { breakdown, profiled } }), document.getElementById('profile'))
} catch(err) {
console.error(err)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="profile"></div>
I'm sure that as far as instantiating the object goes, it's way faster and also consumes less memory, no doubts about that, but I would think that the javascript engine needs to loop through all the properties of the object to determine if the property/method invoked is part of that object and if not, then go check for the prototype. I am not 100% sure about this but I'm assuming that's how it works and if so, then in SOME cases where your object has a LOT of methods added to it, instantiated only once and used heavily, then it could possibly be a little slower, but that's just a supposition I haven't tested anything.
But in the end, I would still agree that as a general rules, using prototype will be faster.
Funny thing though. It depends not that much on which type of object you create and it matters how you write an example. Likewise i ran similar test as shmuel613 who wrote a similair test as Andrew. The first test is creating a single instance of a constructor, a class and an object literal and then measures the speed of execution from the constructor's instance functions, class's prototype methods and object literal's static functions:
var Y, Z, x, y, z;
class X {
message(s) {
var mymessage = s + "";
};
addition(i, j) {
return (i * 2 + j * 2) / 2;
};
};
Y = function () {
this.message = function (s) {
var mymessage = s + "";
};
this.addition = function (i, j) {
return (i * 2 + j * 2) / 2;
};
};
Z = {
message(s) {
var mymessage = s + "";
},
addition(i, j) {
return (i * 2 + j * 2) / 2;
}
}
function TestPerformance() {
console.time("Closure time:");
y = new Y(); // create a single instance
for (var i = 0; i < 100000; i++) {
// I am comparing a single instance with the other single instances
y.message('hi');
y.addition(i, 2);
}
console.timeEnd("Closure time:");
console.time("Prototype time:");
x = new X(); // create a single instance
for (var i = 0; i < 100000; i++) {
// I am comparing a single instance with the other single instances
x.message('hi');
x.addition(i, 2);
}
console.timeEnd("Prototype time:");
console.time("Static object time:");
for (var i = 0; i < 100000; i++) {
z = Z; // obviously you don't really need this
z.message('hi');
z.addition(i, 2);
}
console.timeEnd("Static object time:");
}
TestPerformance();
The second test measures the speed of execution of creating many instances of a constructor, a class and object literals followed by executing the instance functions, prototype methods and static methods:
var Y, x, y, z;
class X {
message(s) {
var mymessage = s + "";
};
addition(i, j) {
return (i * 2 + j * 2) / 2;
};
};
Y = function () {
this.message = function (s) {
var mymessage = s + "";
};
this.addition = function (i, j) {
return (i * 2 + j * 2) / 2;
};
};
function TestPerformance() {
console.time("Closure time:");
//y = new Y()
for (var i = 0; i < 100000; i++) {
y = new Y(); // creating an instance
y.message('hi');
y.addition(i, 2);
}
console.timeEnd("Closure time:");
console.time("Prototype time:");
//x = new X();
for (var i = 0; i < 100000; i++) {
x = new X(); // creating an instance
x.message('hi');
x.addition(i, 2);
}
console.timeEnd("Prototype time:");
console.time("Static object time:");
for (var i = 0; i < 100000; i++) {
z = {
message(s) {
var mymessage = s + "";
},
addition(i, j) {
return (i * 2 + j * 2) / 2;
}
}; // creating an instance such as from factory functions
z.message('hi');
z.addition(i, 2);
}
console.timeEnd("Static object time:");
}
TestPerformance();
The lesson learned is that DON'T blindly evolve a prejudice against something without being thorough. The execution speed from instance functions of a constructor (pre ES2016 classes) and the speed from prototype methods of a class are really just as fast as the execution speed from static functions of a object. However the creation speed followed by execution speed of a constructor instance with instance functions versus the creation speed of a class instance with prototype methods versus the creation speed of object literals with static methods shows rather that classes with prototype methods are faster created and executed on Chrome, Microsoft edge, and Opera. The creation speed of an object literal with static methods is only faster at Mozilla firefox
So, creating the property on the instance would result in slightly faster access time - but this might only be an issue for a very deep prototype hierarchy.
Actually the result is different then we could expect - access time to prototyped methods is faster then accessing to the methods attached exactly to the object (FF tested).

Categories

Resources