Object.create to create an object with costructor - javascript

I am learning Javascript and I am a C++ programmer. I have tried creating an object with a constructor with object.create and here is the result:
var PlayGround ={
initGrid : function(N) {
this.N=N;
this.grid = new Array(N);
for (var i = 0; i < N; i++) {
this.grid[i] = new Array(N);
for (var j = 0; j < N; j++) {
this.grid[i][j] = false;
}
}
return true;
}
};
var PlayGround_property = {
N:{
value: 100,
writable:true
},
grid:{
value:null,
writable:true
}
}
var board= Object.create(PlayGround, PlayGround_property);
It works as I want: the object board contains the object grid, and now I can use the set and get keyword to define the behaviour of the = and () operator.
Anyway I have read around the web that the
this
keyword in Javascript is not safe and I want to be sure that it is referring always to the board object and not to the global window object. Is there a way or I am overthinking?
Other question, are there other ways to write object with a constructor (and maybe other members) in Javascript?

I want to be sure that [this] is referring always to the board object
A function's this is set either by how you call the function, or bind. So just make sure you call methods the right way. If you always call functions as methods of board, then this within the methods will always reference board.
If you are only going to have one instance of board, there doesn't seem much point in using a constructor. If you have multiple instances of board, then you want this to reference the particular instance that called the method so you don't want to fix this using bind.
Crockford just doesn't like the use of new, so encouraged Object.create, it fits his idea of how inheritance should work.
Your pattern could be rewritten to use a constructor something like:
function PlayGround (N) {
this.N = N;
this.grid = []; // Use array literal, it's less to type
for (var i = 0; i < N; i++) {
this.grid[i] = [];
for (var j = 0; j < N; j++) {
this.grid[i][j] = false; // Not sure why you bother with this
}
}
}
var board = new Playground(100);
I'm not exactly sure what you're doing, but that should be close. Note that javascipt is loosely typed, so only initialise variables and properties if you have something useful to assign. Variables are created with a value of undefined, Array properties are only created if you actually assign something to them, creating an array with length N does not create any indexes, e.g.
var arr = new Array(10);
console.log(arr.length); // 10
console.log(arr.hasOwnProperty(0)); // false

Related

Number prototype

Hi everyone i need an help.
I try to modify Number.prototype to add the function sum.
I want to add some numbers to my initial number.
Number.prototype.sum = async (...nums) => {
var x = //What I have to write to have my inizial number here?
for (var i = 0;i<nums.length;i++) {
x=x+nums[i]
}
return x
}
console.log((10).sum(2)) // output: 12
console.log((10).sum(4,6)) // output: 20
(I use visual studio code and the hint after this. is only number)
I tried with:
Number.prototype.valueOf(this)
Number.prototype.valueOf(this.number)
Number.parseInt(this.toString())
Number.parseFloat(this.toString())
Number.parseInt(this.number.toString())
Number.parseFloat(this.number.toString())
this.valueOf()
this.number.valueOf()
You have to use function to access the correct this context (which is the number that the method is called on). Arrow functions inherit their this context from the parent scope (the global object in this case). Also async is not needed since you are not doing anything asynchronous here:
Number.prototype.sum = function (...nums) {
var x = this
for (var i = 0; i < nums.length; i++) {
x = x + nums[i]
}
return x
}
console.log((1).sum(2, 3))
Aside from the fact that augmenting native prototypes is a bad idea, wouldn't you think that a function like this is better suited for the Array prototype?

How to create multiple instances of objects in Javascript

I have a constructor object in my code which is:
function Employee(){
this.name = names[Math.floor(Math.random() * names.length)];
this.age=1;
this.level=1;
this.production=400;
this.totalprod=0;
}
So when I create a new Employee I just say:
var employee1 = new Employee();
So then I can manipulate this instance of the object. Now, I want this objects to be created dynamically with the variable names: employee1, employee2, employee3 and so on.. Is there a way to achieve this or is it impossible?
And the other question that I have, say that I want to change the age of all instances at the same time, is there a way to do this? Thanks in advance and sorry if the question in silly, I'm learning!
EDIT: This is not the same as the other question as I'm using a constructor Object, not a literal Object, and, apart from that, I ask another question which is how to change a property of all instances at the same time, thanks!
This isn't really possible without the use of something like eval, which is bad practice.
Instead if you knew how many employees you wanted to make in advance you could do something like this.
Example: https://jsfiddle.net/dbyw7p9x/
function makeEmployees(n) {
var employees = new Array(n)
for (var i = 0; i < n; ++i) {
employees[i] = new Employee()
}
return employees
}
alternatively you could make also make it return an object which interestingly, while not exactly the same as the array, would be accessed in the same way as an array using numbers inside square brackets obj[0], obj[1], obj[2], obj[3] etc.
function makeEmployeesObj(n) {
var employees = {}
for (var i = 0; i < n; ++i) {
employees[i] = new Employee()
}
return employees
}
To change a property for each approach you can do:
// Array
for (var i = 0; i < e1.length; ++i) {
e1[i].age = 2
}
// Object
Object.keys(e2).forEach(function(key) {
e2[key].age = 2
})
Here is one way to do it, using an array, we push to new Employees to it, and return that array:
To add a specific value, in this case age, I recommend passing it in as a parameter to your Employee constructor, you can do this with all of the this parameters if you like:
Notice in the JsBin that all the ages are different, they are actually the value of n:
Working example: JSBin
function Employee(age){
this.name = 'something';
this.age= age;
this.level=1;
this.production=400;
this.totalprod=0;
}
function maker(n) {
var arr = [];
while (n > 0) {
arr.push(new Employee(n));
n--;
}
return arr;
}

Cannot set property '0' of undefined in 2d array

I know this has been asked a lot of times, but how do I fix exactly this thing?
I have a map[][] array (contains tile ids for a game) and I need to copy it to pathmap[][] array (contains just 0's and 1's, it is a path map), however when I do so..
function updatepathmap(){
pathmap = [];
var upm_x = 0;
while (upm_x < map.length){
var upm_y = 0;
while (upm_y < map[upm_x].length){
pathmap[][]
if (canPassthrough(map[upm_x][upm_y])) {
pathmap[upm_x][upm_y] = 1;
} else {
console.log(upm_x);
console.log(upm_y);
pathmap[upm_x][upm_y] = 0;
}
upm_y++;
}
upm_x++;
}
console.log(map);
console.log(pathmap);
}
..it gives me Cannot set property '0' of undefined typeerror at line pathmap[upm_x][upm_y] = 0;
Despite the foo[0][0] syntactic sugar, multi-dimensional arrays do not really exist. You merely have arrays inside other arrays. One consequence is that you cannot build the array in the same expression:
> var foo = [];
undefined
> foo[0][0] = true;
TypeError: Cannot set property '0' of undefined
You need to create parent array first:
> var foo = [];
undefined
> foo[0] = [];
[]
> foo[0][0] = true;
true
You can determine whether it exists with the usual techniques, e.g.:
> var foo = [];
undefined
> typeof foo[0]==="undefined"
true
> foo[0] = true;
true
> typeof foo[0]==="undefined"
false
I would have thought pathmap[][] was a syntax error, I'm surprised you're not seeing one.
Before you can use an array at pathmap[upm_x], you must create an array at pathmap[upm_x]:
pathmap[upm_x] = [];
This would be the first line in your outer while, so:
while (upm_x < map.length){
pathmap[upm_x] = [];
// ...
Remember that JavaScript doesn't have 2D arrays. It has arrays of arrays. pathmap = [] creates the outer array, but doesn't do anything to create arrays inside it.
Side note:
var upm_x = 0;
while (upm_x < map.length){
// ...
upm_x++;
}
is an error-prone way to write:
for (var upm_x = 0; upm_x < map.length; upm_x++){
// ...
}
If you use while, and you have any reason to use continue or you have multiple if branches, it's really easy to forget to update your looping variable. Since looping on a control variable is what for is for, it's best to use the right construct for the job.
Side note 2:
Your code is falling prey to The Horror of Implicit Globals because you don't declare pathmap. Maybe you're doing that on purpose, but I wouldn't recommend it. Declare your variable, and if you need it outside your function, have your function return it.
Side note 3:
map would make this code a lot simpler:
function updatepathmap(){
var pathmap = map.map(function(outerEntry) {
return outerEntry.map(function(innerEntry) {
return canPassthrough(innerEntry) ? 1 : 0;
});
});
console.log(map);
console.log(pathmap);
}

How to properly declare a Javascript array of objects in an object

I'm trying to create an object that contains an array of objects. I'm using a jquery selector to determine the number of objects I want in the array. I'm having some issue here because when I enter the for loop Firefox says that "this.obj is undefined" I tried both the the this.obj = new Array() syntax as well as the this.obj[ ]; syntax.
function Base() {
this.n = document.querySelectorAll('transform').length /3;
this.obj = new Array(n); //array declaration
for (var i = 0; i < this.n; i++) {
this.obj[i] = new x3dSphere("b"+i);
}
}
I've only seen examples of arrays within objects that are declared like this.obj = [1,2,2,4] or the in the JSON form obj: [1,2,3,4]. I'm sure this is something really easy to do but I can't seem to find an example anywhere.
The following worked for me:
function Base() {
this.n = 5;
this.obj = [];
for (var i = 0; i < this.n; i++) {
this.obj.push(new Test());
}
}
Where Test was:
var Test = function () {};
It seems like the real problem is that it never created this.obj because n was undefined. If you want to declare the array how you did before, try new Array(this.n).
EDIT
Would new Array(this.n) be faster than the this.obj=[] syntax since it's pre-allocated?
Interestingly enough, the answer is no.
Additionally, the accepted answer on this question has a great discussion of lots of other aspects of JavaScript array performance: What is the performance of Objects/Arrays in JavaScript? (specifically for Google V8)
I've updated my answer to use Array.push() because it is apparently much, much faster than doing Array[i] = new Obj() (shout out to Jason, who used it in his original answer).
You can declare an array with
this.obj = [];
And then push objects into the array in a loop
for (var i =0; i < n; i ++) {
this.obj.push(new x3dSphere ());
}

Dynamically create Instance fields for a JavaScript Object

I have a dynamically-created list of strings called 'variables'. I need to use these strings as the instance variables for an array of JavaScript objects.
var objectsArr = [];
function obj(){};
for (var i=0; i<someNumberOfObjects; i++ ) {
...
objectsArr[i] = new Object();
for (var j=0; j<variables.length; j++) {
objectArr[i].b = 'something'; //<--this works, but...
//objectArr[i].variables[j] = 'something'; //<---this is what I want to do.
}
}
The commented-out line shows what I am trying to do.
You can use the bracket syntax to manipulate the property by name:
objectArr[i][variables[j]] = 'something';
In other words, get the object from objectArr at index i then find the field with name variables[j] and set the value of that field to 'something'.
In general terms, given object o:
var o = {};
You can set the property by name:
o['propertyName'] = 'value';
And access it in the usual way:
alert(o.propertyName);
Use the bracket notation. This will get it done:
var objectsArr = [], ii, jj;
function Obj() {}
for(ii = 0; ii < someNumberOfObjects; ii += 1) {
objectsArr[ii] = new Obj();
for (jj = 0; jj < variables.length; jj += 1) {
objectArr[ii][variables[jj]] = 'something';
}
}
A couple of additional notes:
Javascript doesn't have block scope, so you must have two separate loop variables.
By convention, constructor functions like Obj should begin with a capital letter to signify that they ought to be used with the new keyword. In this case though, unless you need the objects to have a non-Object prototype, you could just use a plain object literal (objectsArr[ii] = {};).

Categories

Resources