我可以在不使用 new 关键字的情况下构造 JavaScript 对象吗?

问题描述 投票:0回答:13

这就是我想做的:

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
javascript inheritance prototype constructor
13个回答
35
投票

您可以使用此模式:

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);


5
投票

使用“new”只是告诉构造函数:

    构造函数中的“this”关键字应该引用函数本身,而不是父对象(像往常一样),如果该函数在全局范围内声明,则父对象将是窗口对象。
  1. 对于新创建的对象/实例上所有失败的查找(未找到 obj 属性),请检查原始构造函数的原型属性。
  2. 所以
有新的

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 属性,这可能不是您想要的。


4
投票

OO Javascript 构造函数模式:新古典与原型


4
投票

它将帮助您确定为什么要避免

new

。也许其他答案之一提到的模式会有所帮助。然而,它们都不会导致

instanceof
在您的测试中返回 true。

新操作本质上是:-

var x = (function(fn) { var r = {}; fn.call(r); return r;}(b);

但是,有一点不同,即使用某些内部属性将构造 
fn

附加到对象(是的,您可以使用

constructor
获取它,但设置它不会产生相同的效果)。让
instanceof
按预期工作的唯一方法是使用
new
关键字。
    


3
投票
new

发挥作用,那么在一般情况下您无法避免

instanceof
(无需走向极端,根据 Zoidberg 间接链接的 Crockford 文章),但是(再次),您为什么要想要或者需要吗?

我能想到您想要避免它的唯一原因是,如果您试图将构造函数传递给另一段不知道它是构造函数的代码。在这种情况下,只需将其包装在工厂函数中即可:

function b() { // ... } function makeB() { return new b(); } var c = makeB();



3
投票

var User = function() { var privateMethod = function() { alert('hello'); } return { sayHello : function() { privateMethod(); this.done = true; } } } var user1 = User();

这个方法有什么问题吗?


2
投票
http://yuiblog.com/blog/2006/11/13/javascript-we-hardly-new-ya/

) 。但它不会帮助你了解“instanceof”故事。


1
投票
new

建立的 ____proto____。


1
投票
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);



0
投票

javascript:xhr=eval(unescape('new\x20XMLHttpRequest();'));alert(xhr);



0
投票

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)


0
投票

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/af358095bd6b36fa5d3dd773971f5fb7


0
投票

function 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

© www.soinside.com 2019 - 2024. All rights reserved.