tob*_*ven 5 javascript oop inheritance class promise
我正在学习javascript中的类和继承。我认为以下是扩展现有对象的相当标准的方法,因为我从Object.create的MDN文档中获得了样式
我期待看到“确定”,然后看到“是!控制台中的“ Hello”,但出现此错误:
Uncaught TypeError: #<MyPromise> is not a promise
at new MyPromise (<anonymous>:5:17)
at <anonymous>:19:6
Run Code Online (Sandbox Code Playgroud)
看起来Promise构造函数正在抛出异常,因为它可以告诉我给我初始化的对象不是一个简单的Promise。
我希望Promise构造函数初始化我的对象,就像它是一个Promise对象一样,这样我就可以扩展该类。他们为什么不编写Promise构造函数来使用这种通用模式?难道我做错了什么?为您加油!
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);});
Run Code Online (Sandbox Code Playgroud)
我最初试图制作一个可以使用的BatchAjax类,例如:
(new BatchAjax([query1, query2]))
.then(function(response) {console.log('Fires when all queries are complete.');});
Run Code Online (Sandbox Code Playgroud)
真的有点有趣。
本机Promise类(如Error和Array)不能用旧的 ES5 风格的子类化机制正确地子类化。
子类化的正确方法Promise是通过class语法:
class MyPromise extends Promise {
}
Run Code Online (Sandbox Code Playgroud)
例子:
class MyPromise extends Promise {
}
Run Code Online (Sandbox Code Playgroud)
如果您的目标是不class使用Reflect.construct. 请注意,这Reflect.construct是一个 ES2015 功能,例如class,但您似乎更喜欢 ES5 风格的创建类。
这是你如何做到的:
// 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());
};
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它Promise:
MyPromise.resolve("it works")
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));
Run Code Online (Sandbox Code Playgroud)
或者
new MyPromise(resolve => resolve("it works"))
.myMethod()
.then(result => console.log(result))
.catch(error => console.error(error));
Run Code Online (Sandbox Code Playgroud)
等等。
现场示例:
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));Run Code Online (Sandbox Code Playgroud)
如果您想避免更改 的原型MyPromise,可以将静态属性复制过来,但这并不完全相同:
// 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());
};
Run Code Online (Sandbox Code Playgroud)
使用它当然是一样的。
现场示例:
// 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());
};
Run Code Online (Sandbox Code Playgroud)
我最新的解决方案是将一个 Promise 对象作为 this.promise 组合到我的类中,然后通过覆盖 Promise 的所有实例方法并将它们传递给 this.promise 对象来假装是从 Promise 继承的。欢闹随之而来。我真的很欢迎人们指出这种方法的缺点。
对我来说,没有什么是显而易见的。
当我将此代码粘贴到 Chrome 控制台时,它似乎可以工作。我理解的就这么多。
为看一眼干杯。
BatchAjax = function(queries) {
var batchAjax = this;
this.queries = queries;
this.responses = [];
this.errorCount = 0;
this.promise = new Promise(function(resolve, reject) {
batchAjax.executor(resolve, reject);
});
};
BatchAjax.prototype = Object.create(Promise.prototype);
BatchAjax.prototype.constructor = BatchAjax;
BatchAjax.prototype.catch = function(fail) {
return this.promise.catch(fail);
}
BatchAjax.prototype.then = function(success, fail) {
return this.promise.then(success, fail);
};
BatchAjax.prototype.executor = function(resolve, reject) {
var batchAjax = this;
$.each(this.queries, function(index) {
var query = this;
query.success = function (result) {
batchAjax.processResult(result, index, resolve, reject);
};
query.error = function (jqXhr, textStatus, errorThrown) {
batchAjax.errorCount++;
var result = {jqXhr: jqXhr, textStatus: textStatus, errorThrown: errorThrown};
batchAjax.processResult(result, index, resolve, reject);
};
$.ajax(query);
});
};
BatchAjax.prototype.processResult = function(result, index, resolve, reject) {
this.responses[index] = result;
if (this.responses.length === this.queries.length) {
if (this.errorCount === 0) {
resolve(this.responses);
} else {
reject(this.responses);
}
}
};
// Usage
var baseUrl = 'https://jsonplaceholder.typicode.com';
(new BatchAjax([{url: baseUrl + '/todos/4'}, {url: baseUrl + '/todos/5'}]))
.then(function(response) {console.log('Yay! ', response);})
.catch(function(error) {console.log('Aww! ', error);});
Run Code Online (Sandbox Code Playgroud)