Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
98
rated 0 times [  100] [ 2]  / answers: 1 / hits: 16955  / 7 Years ago, sun, january 22, 2017, 12:00:00

I'm learning about classes and inheritance in javascript. I thought that the following is a fairly standard way of extending an existing object as I got the style from the MDN docs on Object.create



I was expecting to see 'ok' and then 'Yay! Hello' in the console, but instead I go this error:



Uncaught TypeError: #<MyPromise> is not a promise
at new MyPromise (<anonymous>:5:17)
at <anonymous>:19:6


It looks like the Promise constructor is throwing an exception because it can tell that the object I've given it to initialise isn't a straightforward Promise.



I want the Promise constructor to initialise my object as if it was a Promise object, so I can then extend the class. Why wouldn't they write the Promise constructor to work with this common pattern? Am I doing something wrong? Cheers for taking a look!



MyPromise = function(message, ok) {
var myPromise = this;
this.message = message;
this.ok = ok;
Promise.call(this, function(resolve, reject) {
if(this.ok) {
console.log('ok');
resolve(myPromise.message);
} else {
console.log('not ok');
reject(myPromise.message);
}
});
};

MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;

(new MyPromise('Hello', true))
.then(function(response) {console.log('Yay! ' + response);})
.except(function(error) {console.log('Aww! ' + error);});


I was originally trying to make a BatchAjax class that you could use like:



(new BatchAjax([query1, query2]))
.then(function(response) {console.log('Fires when all queries are complete.');});


It was just a bit of fun really.


More From » class

 Answers
4

The native Promise class (like Error and Array) cannot be correctly subclassed with the old ES5-style mechanism for subclassing.



The correct way to subclass Promise is through class syntax:



class MyPromise extends Promise {
}


Example:





class MyPromise extends Promise {
myMethod() {
return this.then(str => str.toUpperCase());
}
}

// Usage example 1
MyPromise.resolve(it works)
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));

// Usage example 2
new MyPromise((resolve, reject) => {
if (Math.random() < 0.5) {
resolve(it works);
} else {
reject(new Error(promise rejected; it does this half the time just to show that part working));
}
})
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));








If it's your goal to do that without class, using mostly ES5-level features, you can via Reflect.construct. Note that Reflect.construct is an ES2015 feature, like class, but you seem to prefer the ES5 style of creating classes.



Here's how you do that:



// Create a constructor that uses `Promise` as its super and does the `super` call
// via `Reflect.construct`
const MyPromise = function(executor) {
return Reflect.construct(Promise, [executor], MyPromise);
};
// Make `MyPromise` inherit statics from `Promise`
Object.setPrototypeOf(MyPromise, Promise);
// Create the prototype, add methods to it
MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;
MyPromise.prototype.myMethod = function() {
return this.then(str => str.toUpperCase());
};


Then use it just like Promise:



MyPromise.resolve(it works)
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));


or



new MyPromise(resolve => resolve(it works))
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));


etc.



Live Example:





// Create a constructor that uses `Promise` as its super and does the `super` call
// via `Reflect.construct`
const MyPromise = function(executor) {
return Reflect.construct(Promise, [executor], MyPromise);
};
// Make `MyPromise` inherit statics from `Promise`
Object.setPrototypeOf(MyPromise, Promise);
// Create the prototype, add methods to it
MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;
MyPromise.prototype.myMethod = function() {
return this.then(str => str.toUpperCase());
};

// Usage example 1
MyPromise.resolve(it works)
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));

// Usage example 2
new MyPromise((resolve, reject) => {
if (Math.random() < 0.5) {
resolve(it works);
} else {
reject(new Error(promise rejected; it does this half the time just to show that part working));
}
})
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));








If you want to avoid changing the prototype of MyPromise, you can copy the static properties over, but it's not quite the same thing:



// Create a constructor that uses `Promise` as its super and does the `super` call
// via `Reflect.construct`
const MyPromise = function(executor) {
return Reflect.construct(Promise, [executor], MyPromise);
};
// Assign the statics (`resolve`, `reject`, etc.) to the new constructor
Object.assign(
MyPromise,
Object.fromEntries(
Reflect.ownKeys(Promise)
.filter(key => key !== length && key !== name)
.map(key => [key, Promise[key]])
)
);
// Create the prototype, add methods to it
MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;
MyPromise.prototype.myMethod = function() {
return this.then(str => str.toUpperCase());
};


Using it is the same, of course.



Live Example:





// Create a constructor that uses `Promise` as its super and does the `super` call
// via `Reflect.construct`
const MyPromise = function(executor) {
return Reflect.construct(Promise, [executor], MyPromise);
};
// Assign the statics (`resolve`, `reject`, etc.) to the new constructor
Object.assign(
MyPromise,
Object.fromEntries(
Reflect.ownKeys(Promise)
.filter(key => key !== length && key !== name)
.map(key => [key, Promise[key]])
)
);
// Create the prototype, add methods to it
MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;
MyPromise.prototype.myMethod = function() {
return this.then(str => str.toUpperCase());
};

// Usage example 1
MyPromise.resolve(it works)
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));

// Usage example 2
new MyPromise((resolve, reject) => {
if (Math.random() < 0.5) {
resolve(it works);
} else {
reject(new Error(promise rejected; it does this half the time just to show that part working));
}
})
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));




[#59248] Friday, January 20, 2017, 8 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
austonjuancarlosb

Total Points: 238
Total Questions: 89
Total Answers: 99

Location: Chad
Member since Mon, Dec 5, 2022
1 Year ago
;