I'm trying to create a constructor function that includes a call to indexedDB or localStorage to retrieve some data if it exists and then populate it's values, either from the cache or the given (default) data.
I had it working, but somehow broke my code. Given that my method of programming is "hit it with a stick until it works", the code is an absolute mess. So I have simplified the problem down to a contrived example, which fails in the same way.
Removing the async function (setTimeout) fixes the problem, but then my code won't work.
var person = (function(){
function privateFn (value){
return value;
}
function private_asyncFn(value, callback){
setTimeout(function () {
return callback(value);
}, 10);
}
var DATA, NUM;
var personConstructor = function(name, age, gender, callback){
this.name = privateFn(name);
this.gender = privateFn(gender);
DATA = DATA || [];
NUM = NUM || 0;
this.num = NUM;
private_asyncFn(age, function(ret){
DATA[NUM++] = { name: this.name, age: ret };
if (callback instanceof Function) return callback(this.name);
}.bind(this));
};
personConstructor.prototype.getAge = function () {
if (this.gender === "male") return DATA[this.num].age;
else return DATA[this.num].age < 20 ? 18 : (Math.floor(DATA[this.num].age / 10) - 1) + "9 and holding";
};
return personConstructor;
})();
var name1;
var person1 = new person("jill", 32, "female", function(name){
name1 = name;
});
var age1 = person1.getAge(); //Uncaught TypeError: Cannot read property 'age' of undefined????
I see other code on SO using classes and promises and async/await, but I don't understand how that all works, so this code is a bit "old school", sorry about that.
In this example, can you retrieve the age of the person, immediately following the initialization of a new person?
There is no way to make an asynchronous constructor. What you want to do instead is probably create an asynchronous function that will yield your constructed object after the asynchronous operation is completed. I'd give you a more concrete example, but frankly, I don't understand what the async part of your code is attempting to do. Here's an example of how you might accomplish this, though:
function Person(name, age, gender) {
this.name = name
this.gender = gender
this.age = age
}
Person.prototype.getAge = function() {
return this.age
}
Person.create = function create(name, age, gender, done) {
var person = new Person(name, age, gender)
setTimeout(function () {
done(null, person)
}, 1000)
}
Person.create("jill", 32, "female", function (person) {
person.getAge()
})
I would recommend using Promises and ES6 classes if you don't need to support very old browsers.
class Person {
static create(name, age, gender) {
return new Promise(resolve => {
const person = new Person(name, age, gender)
resolve(person)
})
}
constructor(name, age, gender) {
this.name = name
this.age = age
this.gender = gender
}
getAge() {
return this.age
}
}
Person.create("jill", 32, "female")
.then((person) => {
person.getAge()
})
It would be helpful when you post your next SO question to give a real world example of what your code is trying to achieve - getAge
returning different results depending on gender doesn't make much sense:)
By moving all of the async logic into an init
function that is called after creating a new person
keeps the constructor synchronous. Then getAge
can be called from inside the init
callback function using either this.getAge()
or person1.getAge()
(because person1 exists now)
var person = (function(){
function privateFn (value){
return value;
}
function private_asyncFn(value, callback){
setTimeout(function () {
return callback(value);
}, 10);
}
var DATA, NUM;
//removed all data inputs and callback from constructor function
var personConstructor = function(){
//initialise publically accessible data
this.name = null;
this.gender = null;
//initialise blank data store
DATA = DATA || [];
NUM = NUM || 0;
this.num = NUM;
DATA[NUM++] = {
age: null
};
};
//created new init function
personConstructor.prototype.init = function (name, age, gender, callback){
this.name = privateFn(name);
this.gender = privateFn(gender);
private_asyncFn(age, function(ret){
DATA[this.num].age = ret;
//note: .call(this,...) on the callback to use "this" in the callback
if (callback instanceof Function) return callback.call(this, this.name);
}.bind(this));
};
personConstructor.prototype.getAge = function () {
if (this.gender === "male") return DATA[this.num].age;
else return DATA[this.num].age < 20 ? 18 : (Math.floor(DATA[this.num].age / 10) - 1) + "9 and holding";
};
return personConstructor;
})();
var name1, age1;
var person1 = new person();
person1.init("jill", 32, "female", function(name){
name1 = name;
age1 = this.getAge();
console.log(age1);//29 and holding, YES!
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.