这就是我想做的:
function a() {
// ...
}
function b() {
// Some magic, return a new object.
}
var c = b();
c instanceof b // -> true
c instanceof a // -> true
b instanceof a // -> true
可能吗?我可以通过将
b
挂接到它的原型链中,轻松地使 a
成为 a
的实例,但随后我必须做 new b()
,这是我试图避免的。我想要的可能吗?
更新:我觉得明智地使用
b.__proto__ = a.prototype
是可能的。下班后我会尝试更多。
更新2: 下面是你能得到的最接近的,这对我来说已经足够了。感谢大家的有趣回答。
function a() {
// ...
}
function b() {
if (!(this instanceof arguments.callee)) {
return new arguments.callee();
}
}
b.__proto__ = a.prototype
var c = b();
c instanceof b // -> true
c instanceof a // -> false
b instanceof a // -> true
更新3:我在关于“权力构造者”的博客文章中找到了我想要的东西,一旦我添加了必要的
b.__proto__ = a.prototype
行:
var object = (function() {
function F() {}
return function(o) {
F.prototype = o;
return new F();
};
})();
function a(proto) {
var p = object(proto || a.prototype);
return p;
}
function b(proto) {
var g = object(a(proto || b.prototype));
return g;
}
b.prototype = object(a.prototype);
b.__proto__ = a.prototype;
var c = b();
c instanceof b // -> true
c instanceof a // -> true
b instanceof a // -> true
a() instanceof a // -> true
您可以使用此模式:
function SomeConstructor(){
if (!(this instanceof SomeConstructor)){
return new SomeConstructor();
}
//the constructor properties and methods here
}
之后你可以做:
var myObj = SomeConstructor();
[编辑 2023(实际上:重新编辑)] 为了完全避免使用
new
关键字,您可以使用 工厂函数。这是一个例子。这就是 Douglas Crockford 所说的“无类面向对象解决方案”。
该模式/想法用于(除其他外)这个小型 github 存储库
const Person = (name = 'unknown', age = 0, male = false) => {
const value = () => `This is ${name}. ${
!male ? `Her` : `His`} age is ${age} years.`;
return {
get whoIs() { return value(); },
toString() { return value(); },
addAge: years => age += years,
setAge: newAge => age = newAge,
rename: newName => name = newName,
};
}
// usage
const [ jane, charles, mary ] = [
Person(`Jane`, 23),
Person(`Charles`, 32, 1),
Person(`Mary`, 16), ];
jane.addAge(17);
charles.setAge(76);
console.log(`${jane}`);
console.log(`${mary}`);
console.log(charles.whoIs);
使用“new”只是告诉构造函数:
:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.getDistance = function(otherPoint){
var Dx = (this.x - otherPoint.x) ** 2;
var Dy = (this.y - otherPoint.y) ** 2;
var d = Dx + Dy;
d = Math.sqrt(d);
return d
}
var pointA = new Point(3, 6);
var pointB = new Point(5, 8);
var distanceAB = pointA.getDistance(pointB);
function Point(x, y) {
let d = Object.create(Point.prototype);
d.x = x;
d.y = y;
return d
}
Point.prototype.getDistance = function(otherPoint){
var Dx = (this.x - otherPoint.x) ** 2;
var Dy = (this.y - otherPoint.y) ** 2;
var d = Dx + Dy;
d = Math.sqrt(d);
return d
}
var pointA = Point(3, 6);
var pointB = Point(5, 8);
var distanceAB = pointA.getDistance(pointB);
尝试添加删除第一个示例中的“new”,您将看到“this”不再指构造函数,而是指窗口对象。您将提供窗口 x 和 y 属性,这可能不是您想要的。
它将帮助您确定为什么要避免
new
。也许其他答案之一提到的模式会有所帮助。然而,它们都不会导致
instanceof
在您的测试中返回 true。新操作本质上是:-
var x = (function(fn) { var r = {}; fn.call(r); return r;}(b);
但是,有一点不同,即使用某些内部属性将构造
fn
附加到对象(是的,您可以使用
constructor
获取它,但设置它不会产生相同的效果)。让 instanceof
按预期工作的唯一方法是使用 new
关键字。new
发挥作用,那么在一般情况下您无法避免
instanceof
(无需走向极端,根据 Zoidberg 间接链接的 Crockford 文章),但是(再次),您为什么要想要或者需要吗?我能想到您想要避免它的唯一原因是,如果您试图将构造函数传递给另一段不知道它是构造函数的代码。在这种情况下,只需将其包装在工厂函数中即可:
function b() {
// ...
}
function makeB() {
return new b();
}
var c = makeB();
var User = function() {
var privateMethod = function() {
alert('hello');
}
return {
sayHello : function() {
privateMethod();
this.done = true;
}
}
}
var user1 = User();
这个方法有什么问题吗?
建立的 ____proto____。
Object.create
和经典的
Function.prototype
。正确设置原型链,您可以保留 instanceof
关键字的正常功能,而无需使用 new
关键字。function A() {
return Object.create(A.prototype);
}
function B() {
return Object.create(B.prototype);
}
B.prototype = Object.create(A.prototype);
var c = B();
assert(c instanceof A);
assert(c instanceof B);
javascript:xhr=eval(unescape('new\x20XMLHttpRequest();'));alert(xhr);
var myObject = function() {}; // hint: Chrome debugger will name the created items 'myObject'
var object = (function(myself, parent) {
return function(myself, parent) {
if(parent){
myself.prototype = parent;
}
myObject.prototype = myself.prototype;
return new myObject();
};
})();
a = function(arg) {
var me = object(a);
me.param = arg;
return me;
};
b = function(arg) {
var parent = a(arg),
me = object(b, parent)
;
return me;
};
var instance1 = a();
var instance2 = b("hi there");
console.log("---------------------------")
console.log('instance1 instance of a: ' + (instance1 instanceof a))
console.log('instance2 instance of b: ' + (instance2 instanceof b))
console.log('instance2 instance of a: ' + (instance2 instanceof a))
console.log('a() instance of a: ' + (a() instanceof a))
console.log(instance1.param)
console.log(instance2.param)
function _new(classConstructor, ...args) {
var obj = Object.create(classConstructor.prototype);
classConstructor.call(obj, ...args);
return obj;
}
function test_new() {
function TestClass(name, location) {
this._name = name;
this._location = location;
this.getName = function() {
return this._name;
}
}
TestClass.prototype.getLocation = function() {
return this._location;
}
TestClass.prototype.setName = function(newName) {
this._name = newName;
}
const a = new TestClass('anil', 'hyderabad');
const b = _new(TestClass, 'anil', 'hyderabad');
const assert = console.assert
assert(a instanceof TestClass)
assert(b instanceof TestClass)
assert(a.constructor.name === 'TestClass');
assert(b.constructor.name === 'TestClass');
assert(a.getName() === b.getName());
assert(a.getLocation() === b.getLocation());
a.setName('kumar');
b.setName('kumar');
assert(a.getName() === b.getName());
console.log('All is well')
}
test_new()
参考:
https://gist.github.com/aniltallam/af358095bd6b36fa5d3dd773971f5fb7function sampleClass() {
this.cname = "sample";
}
sampleClass.prototype.getCname = function() {
return this.cname;
}
const newPolyfill = function(fname) {
if (typeof fname !== "function")
throw Error("can't call new on non-functional input");
let newFun = {};
newFun.__proto__ = Object.assign(fname.prototype);
fname.prototype.constructor();
for (let key in fname.prototype) {
if (typeof fname.prototype[key] !== "function") {
newFun[key] = fname.prototype[key];
delete newFun.__proto__[key];
delete fname.__proto__[key];
}
}
return newFun;
}
let newObj = new sampleClass();
console.log("new obj", newObj);
console.log("new cname", newObj.getCname());//sample
let newPolyObj = newPolyfill(sampleClass);
console.log("new poly obj", newPolyObj);
console.log("newPly cname", newPolyObj.getCname());//sample
console.log(newPolyObj instanceof(sampleClass)) // true