简体   繁体   English

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

[英]Can I construct a JavaScript object without using the new keyword?

Here is what I'd like to do:这是我想要做的:

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

Is it possible?是否有可能? I can make b be an instance of a easily by hooking a into its prototype chain but then I have to do new b() , which is what I'm trying to avoid.我可以做b是一个实例a容易被钩住a到它的原型链,但后来我不得不做new b()这正是我想避免的。 Is what I want possible?我想要的可能吗?

Update: I feel that it might be possible with judicious use of b.__proto__ = a.prototype .更新:我觉得明智地使用b.__proto__ = a.prototype可能是可能的。 I'm going to experiment more after work.下班后我会尝试更多。

Update 2: Below is what seems to be the closest you can get, which is good enough for me.更新 2:下面是你能得到的最接近的东西,这对我来说已经足够了。 Thanks all for the interesting answers.感谢大家的有趣答案。

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

Update 3: I found exactly what I wanted in a blog post on 'power constructors' , once I added the essential b.__proto__ = a.prototype line:更新 3:一旦我添加了必要的b.__proto__ = a.prototype行,我一篇关于 'power constructors'博客文章中找到了我想要的内容:

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

You can use this pattern:您可以使用此模式:

function SomeConstructor(){
   if (!(this instanceof SomeConstructor)){
        return new SomeConstructor();
   }
   //the constructor properties and methods here
}

after which you can do:之后你可以这样做:

var myObj = SomeConstructor();

In addition to this (rather old) answer: you can use a module pattern to create an object:除了这个(相当旧的)答案:您可以使用模块模式来创建一个对象:

function Person(name, age, male) {
  name = name || 'unknown';
  age = age || 0;
  function get() {
    return ['This person is called ', name,
            (!male ? ', her' : ', his'),' age is ',
            age].join('');
  }
  function setAge(nwage) {
     age = nwage;
  }
  return Object.freeze({get: get, setAge: setAge});
}
// usage
var jane =  Person('Jane', 23)
   ,charles = Person('Charles', 32, 1)
   ,mary = Person('Mary', 16);

console.log(jane.get()); //=> This person is called Jane, her age is 23
mary.setAge(17);
console.log(mary.get()); //=> This person is called Mary, her age is 17

Here's a jsFiddle for some Date functionallity I created using that pattern.这是我使用该模式创建的某些Date功能的jsFiddle

What's wrong with using the new keyword?使用new关键字有什么问题?

At any rate, it sounds like the best thing to do is read up on Javascript inheritance: http://javascript.crockford.com/inheritance.html无论如何,听起来最好的办法是阅读 Javascript 继承: http : //javascript.crockford.com/inheritance.html

Someone posted an article by douglas crockford in this question, and it explains exactly what your asking.有人在这个问题上发表了 douglas crockford 的一篇文章,它准确地解释了你的问题。

OO Javascript constructor pattern: neo-classical vs prototypal OO Javascript 构造函数模式:新古典与原型

The simple answer to your specific question is: no.对您的具体问题的简单回答是:不。

It would help you identified why you want to avoid new .它将帮助您确定为什么要避免使用new Perhaps the patterns alluded to by one of the other answers will help.也许其他答案中提到的模式会有所帮助。 However none of them result in the instanceof returning true in your tests.但是,它们都不会导致instanceof在您的测试中返回 true。

The new operation is essentially:-新的操作本质上是:-

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

However there is the difference that the constructing fn is attached to the object using some internal property (yes you can get it with constructor but setting it doesn't have the same effect).但是,不同之处在于构造fn使用某些内部属性附加到对象(是的,您可以使用constructor获取它,但设置它没有相同的效果)。 The only way to get instanceof to work as intended is to use the new keyword.instanceof按预期工作的唯一方法是使用new关键字。

Yes you can do this.是的,你可以这样做。

var User = function() {
  var privateMethod = function() {
    alert('hello');
  }

  return {
    sayHello : function() {
      privateMethod();
      this.done = true;
    }
  }
}

var user1 = User();

Is anything wrong with this method?这种方法有什么问题吗?

You can't avoid new in the general case (without going to extremes, as per the Crockford article Zoidberg indirectly linked to) if you want inheritance and instanceof to work, but then (again), why would you want or need to?如果您希望继承和instanceof工作,您不能在一般情况下避免new (不走极端,根据 Crockford 文章 Zoidberg 间接链接),但是(再次),您为什么想要或需要?

The only reason I can think of where you'd want to avoid it is if you're trying to pass a constructor function to another piece of code that doesn't know it's a constructor.我能想到您想要避免它的唯一原因是,如果您试图将构造函数传递给另一段不知道它是构造函数的代码。 In that case, just wrap it up in a factory function:在这种情况下,只需将其包装在工厂函数中:

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

You can create instances without the new operator (here is a great article written about this by Douglas Crockfordhttp://yuiblog.com/blog/2006/11/13/javascript-we-hardly-new-ya/ ).您可以在没有 new 运算符的情况下创建实例(这是 Douglas Crockford 撰写的一篇关于此的精彩文章http://yuiblog.com/blog/2006/11/13/javascript-we-hardly-new-ya/ )。 But it will not help you with the "instanceof" story.但它不会帮助您处理“instanceof”故事。

Yes.是的。 If you don't want to use the 'new' keyword, just use prototype, and return something in your constructor function.如果您不想使用 'new' 关键字,只需使用原型,并在构造函数中返回一些内容。

Using 'new' just tells the constructor functions that:使用“new”只是告诉构造函数:

  1. The 'this' keyword in the constructor function should reference the function itself, not the parent object (as per usual), which would be the window object if this function was declared in the global scope.构造函数中的“this”关键字应该引用函数本身,而不是父对象(按照惯例),如果在全局范围内声明了此函数,则父对象将是窗口对象。

  2. For all failed lookups (obj properties not found) on the newly created object/instance, check the original constructor function's prototype property.对于新创建的对象/实例上所有失败的查找(找不到 obj 属性),请检查原始构造函数的原型属性。

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

Without new:没有新的:

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

Try adding removing the 'new' in the the first example, and you'll see the 'this', no longer refers to the constructor function, but the window object instead.尝试在第一个示例中添加删除 'new',您将看到 'this',不再指代构造函数,而是指窗口对象。 You'll be giving your window x and y properties, which proplably isn't what you want.您将提供窗口 x 和 y 属性,这可能不是您想要的。

The only way to get instanceof to work is to use the new keyword.使 instanceof 工作的唯一方法是使用 new 关键字。 instanceof exploits ____proto____ which is established by new . instanceof 利用了由new建立的____proto____。

在 javascript 书签中,您可以使用 eval(unescape("...")) 来创建没有“new”运算符的对象:

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

For those, who may find this via Google (like me...), I developed the original solution further for a better common usage:对于那些可能通过谷歌找到这个的人(像我一样......),我进一步开发了原始解决方案以获得更好的通用用法:

 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)

By using Object.create and the classical Function.prototype .通过使用Object.create和经典的Function.prototype Setting up the prototype chain properly, you preserve proper functioning of the instanceof keyword without any use of the new keyword.正确设置原型链,您可以在不使用new关键字的instanceof保留instanceof关键字的正常功能。

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

Yes.是的。

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

Ref: https://gist.github.com/aniltallam/af358095bd6b36fa5d3dd773971f5fb7参考: https : //gist.github.com/aniltallam/af358095bd6b36fa5d3dd773971f5fb7

Polyfill for new operator:新运营商的 Polyfill:

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

Here is what I'd like to do:这是我想做的:

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

Is it possible?是否有可能? I can make b be an instance of a easily by hooking a into its prototype chain but then I have to do new b() , which is what I'm trying to avoid.我可以做b是一个实例a容易被钩住a到它的原型链,但后来我不得不做new b()这正是我想避免的。 Is what I want possible?我想要的是可能的吗?

Update: I feel that it might be possible with judicious use of b.__proto__ = a.prototype .更新:我认为明智地使用b.__proto__ = a.prototype可能有可能。 I'm going to experiment more after work.下班后我要做更多的实验。

Update 2: Below is what seems to be the closest you can get, which is good enough for me.更新2:以下是您所能找到的最接近的东西,对我来说足够了。 Thanks all for the interesting answers.谢谢大家的有趣回答。

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

Update 3: I found exactly what I wanted in a blog post on 'power constructors' , once I added the essential b.__proto__ = a.prototype line:更新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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM