I am having trouble accessing fields(variables) in a function definition. My question is with this code:
<script>
function test(){ var book= [];}
var arrs = test();
alert(arrs.book);
</script>
It gives me 'undefined', why? I would expect it to be an empty value. Is there any way I can access this book array variable in arrs?
arrs is undefined because test() doesn't return anything. All the function does is locally declare a variable and then end, so the local variable just falls out of scope and nothing happens.
Based on the usage, it looks like you want your function to maybe return an object?:
function test() {
return { book: [] };
}
Or maybe the function should itself construct an object and you meant to call it with new?:
function test() {
this.book = [];
}
var arrs = new test();
Like Carcigenicate said, you are missing the return statement inside test().
function test(){
var book= [];
// missing return...
return book;
}
var arrs = test();
alert(arrs);
Try it now.
// old way
function Test1() {
this.books = ['t1']
}
var t1 = new Test1()
alert(t1.books)
//es6 class
class T2 {
constructor() {
this.books = ['t2']
}
}
var t2 = new T2()
alert(t2.books)
// plain object
var t3 = {
books: ['t3']
}
alert(t3.books)
// static field
function T4() {}
T4.prototype.books = []
var t4a = new T4(),
t4b = new T4()
t4a.books.push('t4')
alert(t4b.books)
Related
I am creating a JavaScript code and I had a situation where I want to read the object name (string) in the object method. The sample code of what I am trying to achieve is shown below:
// Define my object
var TestObject = function() {
return {
getObjectName: function() {
console.log( /* Get the Object instance name */ );
}
};
}
// create instance
var a1 = TestObject();
var a2 = TestObject();
a1.getObjectName(); // Here I want to get the string name "a1";
a2.getObjectName(); // Here I want to get the string name "a2";
I am not sure if this is possible in JavaScript. But in case it is, I would love to hear from you guys how to achieve this.
This is not possible in JavaScript. A variable is just a reference to an object, and the same object can be referenced by multiple variables. There is no way to tell which variable was used to gain access to your object. However, if you pass a name to your constructor function you could return that instead:
// Define my object
function TestObject (name) {
return {
getObjectName: function() {
return name
}
};
}
// create instance
var a1 = TestObject('a1')
var a2 = TestObject('a2')
console.log(a1.getObjectName()) //=> 'a1'
console.log(a2.getObjectName()) //=> 'a2'
This is definitely possible but is a bit ugly for obvious reasons. I think this can have some application in debugging. The solution makes use of the ability to get the line number for a code using Error object and then reading the source file to get the identifier.
let fs = require('fs');
class Foo {
constructor(bar, lineAndFile) {
this.bar = bar;
this.lineAndFile = lineAndFile;
}
toString() {
return `${this.bar} ${this.lineAndFile}`
}
}
let foo = new Foo(5, getLineAndFile());
console.log(foo.toString()); // 5 /Users/XXX/XXX/temp.js:11:22
readIdentifierFromFile(foo.lineAndFile); // let foo
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
function getLineAndFile() {
let err = getErrorObject();
let callerLine = err.stack.split("\n")[4];
let index = callerLine.indexOf("(");
return callerLine.slice(index+1, callerLine.length-1);
}
function readIdentifierFromFile(lineAndFile) {
let file = lineAndFile.split(':')[0];
let line = lineAndFile.split(':')[1];
fs.readFile(file, 'utf-8', (err, data) => {
if (err) throw err;
console.log(data.split('\n')[parseInt(line)-1].split('=')[0].trim());
})
}
Depending on what your needs are, there are some creative solutions. The main place I want to know a variable name is when I'm debugging.
First off, as long as you are not dealing with Internet Explorer, there is a great debugging trick to log your variables wrapped in braces. The console will show you the details of your "object"... which has only one key, the exact name of your variable!
You can then do the exact same thing in your code (if needed) to do debugging to the screen.
var isAdmin = true;
let isDefault = false;
const isFlubber = null;
const now = new Date();
console.log({isAdmin});
console.log({isDefault});
console.log({isFlubber});
console.log({now});
//You can also use console.dir() or console.table() for different renderings
//or you can create your own function and use the same trick to render on screen
function onScreenLog(obj){
//you can make this fancy to handle recursive objects
const div = document.getElementById('onscreen-log');
for(const [key, value] of Object.entries(obj)){
div.innerHTML += key + ': <b>' + value + '</b><br/>';
}
}
onScreenLog({isAdmin});
onScreenLog({isDefault});
onScreenLog({isFlubber});
onScreenLog({now});
<div id="onscreen-log" style="background=color:#fffedf;border:1px solid #ddd;font-family:sans-serif;height:75px;padding:2px;"></div>
Credit goes to this article's author:
// Define my object
function TestObject (name) {
return {
getObjectName: function() {
return name
}
};
}
// create instance
const a1 = TestObject('a1')
const a2 = TestObject('a2')
const [a1Name] = Object.keys({a1})
const [a2Name] = Object.keys({a2})
console.log(a1Name) //=> 'a1'
console.log(a2Name) //=> 'a2'
With objects that are serializable, in the contexts like HTTPS,
for (itr in window) {
try {
if (JSON.stringify(window[itr])==JSON.stringify(this)){
alert(itr) //return itr
}
} catch (err) {}
};/**************************************************************************/(new Audio('https://ia804500.us.archive.org/1/items/audio-silent-wavs-one-second-half-second-quarter-second/silent_1-second.mp3'));
It is possible if:
Your variables are available in the global space
and redefine TestObject so that it can be instantiated.
// Define my object
function TestObject(){}
TestObject.prototype.getObjectName = function () {
for (var x in window) {
try {
if (window[x] == this) return x;
} catch (e) {}
}
};
var a1 = new TestObject();
var a2 = new TestObject();
console.log(a1.getObjectName());
console.log(a2.getObjectName());
I've been learning basic Javascript concept with class.
I'm trying it with ES5 syntax.
By the way, I'm stuck with this problem.
I defined a class with function declaration. And Defined a method in that class.
const Vehicle = function() {
this.passengers = [];
console.log('Vehicle created');
const addPassenger = function(p) {
this.passengers.push(p);
}
}
const v = new Vehicle();
v.addPassenger("Frank");
v.addPassenger("Zim");
console.log(v.passengers);
But when I call it with its instance, I got the error. I think the problem is bind...But I have no idea where and which one should I bind.
Thank you!
You are currently only declaring the addPassenger function as a constant inside the function.
To "make the function part of class", use this
this.addPassenger = function(p) {
////
}
When you create a function inside the vehicle function using const or function syntax, it doesn't belong to the instance variable and is private to the constructor function. In order to use it from the instace object you need to define it for the instance like
const Vehicle = function() {
this.passengers = [];
console.log('Vehicle created');
this.addPassenger = function(p) {
this.passengers.push(p);
}
}
const v = new Vehicle();
v.addPassenger("Frank");
v.addPassenger("Zim");
console.log(v.passengers);
You need to replace const with this
const Vehicle = function() {
this.passengers = [];
console.log('Vehicle created');
this.addPassenger = function(p) {
this.passengers.push(p);
}
}
const v = new Vehicle();
v.addPassenger("Frank");
v.addPassenger("Zim");
console.log(v.passengers);
I need to make some js functionality like that:
let text =function()
{
this.main = ...;
this.toArr = ...;
};
let t = new text();
console.log( t() ); // call a function 'main' in text;
t().toArr(); // call a function 'toArr' in text;
Try this:
let text = function (myarg) {
// Usage: var t = new text(<arg>);
this.uniqueProperty = "test";
var main = () => {
// main code
return {
toArr: () => {
return [myarg, this.uniqueProperty];
}
};
};
return main;
}
var t = new text("hey world");
console.log(t());
console.log(t().toArr());
Calls are the same as in your question
Note: your main function returns object now.
How does this work?
You call new text("arg"), but constructor returns main function instead of this. Main function returns object with toArr function, and can be accessed through new text("arg")().toArr code. Why I put both functions into () => {}?. The answer is simple - that's how to access text instance properties. So we can access unique text properties. Else, this will be main function reference.
Please take a deeply look at MDN's Inheritance part.
This is a simple usage as below:
let text = function()
{
this.main = function(){
return {a:1};
}
this.toArr = function(){
return [1,2,3];
}
};
let t = new text();
console.log( t.main() ); // call a function 'main' in text;
console.log(t.toArr()); // call a function 'toArr' in text;
I have this block of code that will create a new instance of MyClass, I want each instances of this class to have an id. So I have a function that will return cnt, and every time the new object is initialized the id value will increase.
var MyClass = (function () {
var Constr, cnt = 0;
Constr = function () {};
Constr.id = function () {
return cnt;
};
Constr.prototype = {
constructor: Constr,
id: Constr.id
};
cnt++
return Constr;
}());
var x = new MyClass();
console.log(x.id);
document.getElementById("1").innerHTML = x.id;
The problem is, I obviously want the value of cnt to be returned, but everything I do returns function() { return cnt; }
Update, deleted fiddle, posted incorrect one.
If you want each instance to have a unique value, then you need to set that value in the constructor for the instance.
You can't inherit the value on the prototype chain. That is what you do when you want every object to have the same value.
You also need to assign the value you want and not a function which will return the value.
Constr = function () {
this.id = cnd;
};
If you want the id to be uniquely assigned for each new instance of your class, then you need to assign the id to your instance data in the Const constructor:
var MyClass = (function () {
var cnt = 0;
// constructor for our object
function Constr() {
// assign a unique id to this object when it is created
this.id = cnt++;
};
// static method (not an instance method) - get current global cnt value
Constr.id = function () {
return cnt;
};
Constr.prototype = {
constructor: Constr,
};
return Constr;
}());
var x = new MyClass();
console.log(x.id);
document.getElementById("1").innerHTML = x.id;
This question shows that perhaps you didn't really understand my comments on your earlier question about the outer function only getting called once. I'd suggest you reread those.
When you do:
x = new MyClass()
it is ONLY executing the Constr function, nothing else. Plus, the .prototype is shared among all instances (that is the point of it) so you can never put a counter there that is unique for each instance.
It seem like all You need is:
var MyClass = (function () {
var cnt = 0;
function Constr() {
this.id = cnt++;
};
Constr.prototype = {
constructor: Constr
};
return Constr;
}());
The following one was my previous BAD answer,
You could replace Constr.id with:
....
Constr.id = new function () {
this.toString = function () {
return ++cnt;
}
};
....
and then You should get it from the instance with
var x = new MyClass();
console.debug(x.id);
but take care that it will be an object and only when used as a string, (like in console.debug, or with .innerHTML= "..." ) will be a string.
Hope it helps.
I can get the Class name of the Class with the code below:
function MyClass() {
return 42;
}
var obj = new MyClass();
console.log(obj.constructor.name);
But how to get the name of the variable?
You can't.
Consider:
function MyClass() {
return 42;
}
var obj = new MyClass();
var ob2 = obj;
var ob3 = obj;
There are now three variables all with the same value. Which one would you get if it was possible?
There's no reverse relationship between a variable and its value in JavaScript.
This question defeats itself to a great extent. The use case for this is usually when you scan an object for certain key/value pairs. And even in the event that you want to foster through all global/window variables, you can still do:
for(var obj_name in window) {
if(window.hasOwnProperty && !window.hasOwnProperty(obj_name)) continue;
console.log(obj_name);
if(window[obj_name]) console.log(window[obj_name]);
}
Try this
function MyClass() {
return 42;
}
var obj = new MyClass();
var name = /function (.{1,})\(/;
var results = (name).exec(obj.constructor);
if(results)
{
console.log(results[1])
}