I took this test on http://jsperf.com/literal-obj-vs-function-obj and Literal wins on FF6, Opera 10, IE8, but the Function method faster on Chrome 13.0.782.112, so which one is a better method to use?
var A = {
aa : function(){
var i, j=[];
var arr = ['Literal', 'Function'];
for (i = 0; i < arr.length; i++){
j[i] = arr[i];
}
return j[0];
}
};
var A1 = A;
var A2 = A1;
A1.foo = ' Test';
alert(A1.aa() + A2.foo);
//Function test
function B(){
this.bb = function(){
var i, j=[];
var arr = ['Literal', 'Function'];
for (i = 0; i < arr.length; i++){
j[i] = arr[i];
}
return j[1];
}
}
var B1 = new B();
var B2 = new B();
B.prototype.foo = ' Test';
alert(B1.bb() + B2.foo);
To tell you the truth, the best that I have found is a mix:
function C() {
var i, j = [],
foo;
return {
bb: function() {
var arr = ['Literal', 'Function'];
for (i = 0; i < arr.length; i++) {
j[i] = arr[i];
}
return j[1];
},
setFoo: function(val) {
foo = val;
},
getFoo: function() {
return foo;
}
}
}
var C1 = C();
var C2 = C();
C2.setFoo(' Test');
console.log(C1.bb(), C2.getFoo());
Whichever one you prefer. Speed should never be a concern unless it becomes a real problem in your app. What you're doing looks like premature optimization to me, which is a waste of time. Wait until you need to optimize your code, then optimize the parts that need to be reworked. This is trivial.
Chrome uses an optimisation called hidden classes that allows it to do faster access to object members.
I would bet that this optimisation is enabled only when the object is constructed via new, and as a result an object constructed via new would have faster member access than an object not constructed via new.
well, chrome has around 17% of the market share according to wikipedia. So use literals.
I doubt you're going to do anything intensive enough for the difference to matter.
Function style constructors give you the option of private variables, which is nice.
Related
I currently have an object that adds itself to an array whenever a new one is created. Eventually, I want to remove all of the references in the array so I can add new ones.
I've created an object method (this.removeFromArray()) that looks for itself in the array and splices itself out. removeAll() runs a for loop that makes each object in the array run removeFromArray(), so I expect that when I try to read out the items in the array, I should get nothing.
Instead, depending on the amount of objects created, I get one or two left behind. How can I fix this and have all objects in the array cleared out?
var objArray = [];
function obj(name) {
objArray.push(this);
console.log("Created "+name);
this.name = name;
this.removeFromArray = function() {
objArray.splice(
objArray.findIndex(function(e) {
return e == this;
}),
1
);
}
}
function removeAll() {
for (var i = 0; i <= objArray.length - 1; i++) {
objArray[i].removeFromArray();
}
}
var foo = new obj("foo");
var bar = new obj("bar");
var cat = new obj("cat");
var dog = new obj("dog");
var bird = new obj("bird");
removeAll();
for (var i = 0; i <= objArray.length-1; i++) { //Check the values in the array for leftovers
console.log(objArray[i].name);
}
//Expected nothing in the console but the creation messages, got foo and bar instead
If you want to simply delete all the created object, edit removeAll() function like below:
Note that you have to create a variable for objArray.length, not directly put the objArray.length to for() loop.
function removeAll() {
var len = objArray.length;
for (var i = 0; i <= len - 1; i++) {
objArray.splice(0,1);
}
}
better way to achieve this would be to utilize inheritance through prototype. it is better than creating a function inside the constructor object.
var objArray = [];
function Obj(name) {
this.name = name;
objArray.push(this);
}
Obj.prototype.removeFromArray = function() {
var i = -1,
len = objArray.length,
removed = null;
while (++i < len) {
if (objArray[i] === this) {
removed = objArray.splice(i, 1);
removed = null; //nullify to free memory, though not that necessary
break;
}
}
};
Obj.prototype.removeAll = function() {
var len = objArray.length,
removed = null;
//note that i started from the last item to remove to avoid index out of range error
while (--len >= 0) {
removed = objArray.splice(len, 1);
removed = null; //nullify to free memory, though not that necessary
}
};
I want to generate samples with lodash and it return me the same numbers for each line. what im doing wrong?
var primaryNumsCells = _.range(50);
var extraNumsCells = _.range(20);
var lottery = {lineConfigurations: []};
var numsConfig = {lineNumbers: {}};
for( var i = 0; i < 2; i ++ ) {
numsConfig.lineNumbers.primaryNumbers = _.sample(primaryNumsCells, 5);
numsConfig.lineNumbers.secondaryNumbers = _.sample(extraNumsCells, 2);
lottery.lineConfigurations.push(numsConfig);
}
console.log(lottery);
The results of the first object and second object of the primary and secondary numbers is the same;
here is the fiddle:
http://jsbin.com/vavuhunupi/1/edit
Create a new object inside a loop. It's easy to do with a plain object literal (dropping the variable):
var lottery = {lineConfigurations: []};
for (var i = 0; i < 2; i++) {
lottery.lineConfigurations.push({
lineNumbers: {
primaryNumbers: _.sample(primaryNumsCells, 5),
secondaryNumbers: _.sample(extraNumsCells, 2)
}
});
}
As it stands, at each step of the loop you modify and push the same object (stored in numsConfig var).
And here goes a lodash way of doing the same thing:
var lottery = {
lineConfigurations: _.map(_.range(2), function() {
return {
lineNumbers: {
primaryNumbers: _.sample(primaryNumsCells, 5),
secondaryNumbers: _.sample(extraNumsCells, 2)
}
};
})
};
In JavaScript, if you declare a constructor like this:
var PMFont = function(text, font, size) {
this.text = text;
this.font = font;
this.size = size;
/*
...
ton of code
...
*/
x = 15;
};
var test = new PMFont('dd', 'Arial', 92);
And you create a global variable like the example above: x = 15;, is there a way to know, once your object has been created, if there are new global variables that have been created?
I've downloaded some code, and I'd like to know if there are some useless variables like in my example that stay in memory. I may run into far worse problems, for example:
imgd = ctx.getImageData(0, 0, this.baseWidth, this.baseHeight)
...gets all the data of an HTML5 canvas 2D context, and if it's not freed it takes a lot of RAM.
Since all JS variables default to undefined, if you say the term assigned, the previous answers are not precise:
function isGloballyDefined(varName) {
return window[varName] !== undefined
}
If a variable has a null or false value, it already has been assigned by some piece of code.
Since you didn't specify the context, depending where you are running this code, the window object might not be available, so if you want to use this in a node context, then you probably want to look for the variable in the global object.
Hope this helps.
Yes. You can check if any object has changed by storing it's map and then testing it later against a new map. This helper will do it for you:
JS
function objectWatch(object) {
var keys = Object.keys(object);
return {
done: function () {
var o = {
created: {},
removed: {}
},
newkeys = Object.keys(object);
if (keys.length === newkeys.length) return;
if (keys.length > newkeys.length) {
for (var i = 0, l = keys.length; i < l; i++) {
if (newskeys.indexOf(keys[i]) === -1) o.removed[keys[i]] = object[keys[i]];
}
}
for (var i = 0, l = newkeys.length; i < l; i++) {
if (keys.indexOf(newkeys[i]) === -1) o.created[newkeys[i]] = object[newkeys[i]];
}
return o;
}
};
}
To use it just create an instance of it passing the object you want to watch, run your code, then call the done() method which returns and object with created and removed maps of what has changed.
check = new objectWatch(window);
x = 1;
y = 1;
console.log(check.done());
---> object: {created: {x: 1, y:1, check:object}, removed:{}}
Fiddle
http://jsfiddle.net/L6Lb35nq/
Let's say I have a JavaScript object:
function a(){
var A = [];
this.length = function(){
return A.length;
};
this.add = function(x){
A.push(x);
};
this.remove = function(){
return A.pop();
};
};
I can use it like so:
var x = new a();
x.add(3);
x.add(4);
alert(x.length()); // 2
alert(x.remove()); // 4
alert(x.length()); // 1
I was trying to make .length not a function, so I could access it like this: x.length, but I've had no luck in getting this to work.
I tried this, but it outputs 0, because that's the length of A at the time:
function a(){
var A = [];
this.length = A.length;
//rest of the function...
};
I also tried this, and it also outputs 0:
function a(){
var A = [];
this.length = function(){
return A.length;
}();
//rest of the function...
};
How do I get x.length to output the correct length of the array inside in the object?
You could use the valueOf hack:
this.length = {
'valueOf': function (){
return A.length;
},
'toString': function (){
return A.length;
}
};
Now you can access the length as x.length. (Although, maybe it's just me, but to me, something about this method feels very roundabout, and it's easy enough to go with a sturdier solution and, for example, update the length property after every modification.)
If you want A to stay 'private', you need to update the public length property on every operation which modifies A's length so that you don't need a method which checks when asked. I would do so via 'private' method.
Code:
var a = function(){
var instance, A, updateLength;
instance = this;
A = [];
this.length = 0;
updateLength = function()
{
instance.length = A.length;
}
this.add = function(x){
A.push(x);
updateLength();
};
this.remove = function(){
var popped = A.pop();
updateLength();
return popped;
};
};
Demo:
http://jsfiddle.net/JAAulde/VT4bb/
Because when you call a.length, you're returning a function. In order to return the output you have to actually invoke the function, i.e.: a.length().
As an aside, if you don't want to have the length property be a function but the actual value, you will need to modify your object to return the property.
function a() {
var A = [];
this.length = 0;
this.add = function(x) {
A.push(x);
this.length = A.length;
};
this.remove = function() {
var removed = A.pop();
this.length = A.length;
return removed;
};
};
While what everyone has said is true about ES3, that length must be a function (otherwise it's value will remain static, unless you hack it to be otherwise), you can have what you want in ES5 (try this in chrome for example):
function a(){
var A = [],
newA = {
get length(){ return A.length;}
};
newA.add = function(x){
A.push(x);
};
newA.remove = function(){
return A.pop();
};
return newA;
}
var x = a();
x.add(3);
x.add(4);
alert(x.length); // 2
alert(x.remove()); // 4
alert(x.length); // 1
You should probably use Object.create instead of the function a, although I've left it as a function to look like your original.
I don't think you can access it as a variable as a variable to my knoledge cannot return the value of a method, unless you will hijack the array object and start hacking in an update of your variable when the push/pop methods are called (ugly!). In order to make your method version work I think you should do the following:
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};
These days you can use defineProperty:
let x = {}
Object.defineProperty(x, 'length', {
get() {
return Object.keys(this).length
},
})
x.length // 0
x.foo = 'bar'
x.length // 1
Or in your specific case:
Object.defineProperty(x, 'length', {
get() {
return A.length
}
})
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};
I need to create a function with variable number of parameters using new Function() constructor. Something like this:
args = ['a', 'b'];
body = 'return(a + b);';
myFunc = new Function(args, body);
Is it possible to do it without eval()?
Thank you very much, guys! Actually, a+b was not my primary concern. I'm working on a code which would process and expand templates and I needed to pass unknown (and variable) number of arguments into the function so that they would be introduced as local variables.
For example, if a template contains:
<span> =a </span>
I need to output the value of parameter a. That is, if user declared expanding function as
var expand = tplCompile('template', a, b, c)
and then calls
expand(4, 2, 1)
I need to substitute =a with 4. And yes, I'm well aware than Function is similar to eval() and runs very slow but I don't have any other choice.
You can do this using apply():
args = ['a', 'b', 'return(a + b);'];
myFunc = Function.apply(null, args);
Without the new operator, Function gives exactly the same result. You can use array functions like push(), unshift() or splice() to modify the array before passing it to apply.
You can also just pass a comma-separated string of arguments to Function:
args = 'a, b';
body = 'return(a + b);';
myFunc = new Function(args, body);
On a side note, are you aware of the arguments object? It allows you to get all the arguments passed into a function using array-style bracket notation:
myFunc = function () {
var total = 0;
for (var i=0; i < arguments.length; i++)
total += arguments[i];
return total;
}
myFunc(a, b);
This would be more efficient than using the Function constructor, and is probably a much more appropriate method of achieving what you need.
#AndyE's answer is correct if the constructor doesn't care whether you use the new keyword or not. Some functions are not as forgiving.
If you find yourself in a scenario where you need to use the new keyword and you need to send a variable number of arguments to the function, you can use this
function Foo() {
this.numbers = [].slice.apply(arguments);
};
var args = [1,2,3,4,5]; // however many you want
var f = Object.create(Foo.prototype);
Foo.apply(f, args);
f.numbers; // [1,2,3,4,5]
f instanceof Foo; // true
f.constructor.name; // "Foo"
ES6 and beyond!
// yup, that easy
function Foo (...numbers) {
this.numbers = numbers
}
// use Reflect.construct to call Foo constructor
const f =
Reflect.construct (Foo, [1, 2, 3, 4, 5])
// everything else works
console.log (f.numbers) // [1,2,3,4,5]
console.log (f instanceof Foo) // true
console.log (f.constructor.name) // "Foo"
You can do this:
let args = '...args'
let body = 'let [a, b] = args;return a + b'
myFunc = new Function(args, body);
console.log(myFunc(1, 2)) //3
If you're just wanting a sum(...) function:
function sum(list) {
var total = 0, nums;
if (arguments.length === 1 && list instanceof Array) {
nums = list;
} else {
nums = arguments;
}
for (var i=0; i < nums.length; i++) {
total += nums[i];
}
return total;
}
Then,
sum() === 0;
sum(1) === 1;
sum([1, 2]) === 3;
sum(1, 2, 3) === 6;
sum([-17, 93, 2, -841]) === -763;
If you want more, could you please provide more detail? It's rather difficult to say how you can do something if you don't know what you're trying to do.
A new feature introduced in ES5 is the reduce method of arrays. You can use it to sum numbers, and it is possible to use the feature in older browsers with some compatibility code.
There's a few different ways you could write that.
// assign normally
var ab = ['a','b'].join('');
alert(ab);
// assign with anonymous self-evaluating function
var cd = (function(c) {return c.join("");})(['c','d']);
alert(cd);
// assign with function declaration
function efFunc(c){return c.join("");}
var efArray = ['e','f'];
var ef = efFunc(efArray);
alert(ef);
// assign with function by name
var doFunc = function(a,b) {return window[b](a);}
var ghArray = ['g','h'];
var ghFunc = function(c){return c.join("");}
var gh = doFunc(ghArray,'ghFunc');
alert(gh);
// assign with Class and lookup table
var Function_ = function(a,b) {
this.val = '';
this.body = b.substr(0,b.indexOf('('));
this.args = b.substr(b.indexOf('(')+1,b.lastIndexOf(')')-b.indexOf('(')-1);
switch (this.body) {
case "return":
switch (this.args) {
case "a + b": this.val = a.join(''); break;
}
break;
}
}
var args = ['i', 'j'];
var body = 'return(a + b);';
var ij = new Function_(args, body);
alert(ij.val);
Maybe you want an annoymous function to call an arbitary function.
// user string function
var userFunction = 'function x(...args) { return args.length}';
Wrap it
var annoyFn = Function('return function x(...args) { return args.length}')()
// now call it
annoyFn(args)
new Function(...)
Declaring function in this way causes
the function not to be compiled, and
is potentially slower than the other
ways of declaring functions.
Let is examine it with JSLitmus and run a small test script:
<script src="JSLitmus.js"></script>
<script>
JSLitmus.test("new Function ... ", function() {
return new Function("for(var i=0; i<100; i++) {}");
});
JSLitmus.test("function() ...", function() {
return (function() { for(var i=0; i<100; i++) {} });
});
</script>
What I did above is create a function expression and function constructor performing same operation. The result is as follows:
FireFox Performance Result
IE Performance Result
Based on facts I recommend to use function expression instead of function constructor
var a = function() {
var result = 0;
for(var index=0; index < arguments.length; index++) {
result += arguments[index];
}
return result;
}
alert(a(1,3));
function construct(){
this.subFunction=function(a,b){
...
}
}
var globalVar=new construct();
vs.
var globalVar=new function (){
this.subFunction=function(a,b){
...
}
}
I prefer the second version if there are sub functions.
the b.apply(null, arguments) does not work properly when b inherits a prototype, because 'new' being omitted, the base constructor is not invoked.
In this sample i used lodash:
function _evalExp(exp, scope) {
const k = [null].concat(_.keys(scope));
k.push('return '+exp);
const args = _.map(_.keys(scope), function(a) {return scope[a];});
const func = new (Function.prototype.bind.apply(Function, k));
return func.apply(func, args);
}
_evalExp('a+b+c', {a:10, b:20, c:30});