Можно ли создать объект JavaScript без использования нового ключевого слова?
Вот что я хотел бы сделать:
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
Ответы
Ответ 1
Вы можете использовать этот шаблон:
function SomeConstructor(){
if (!(this instanceof SomeConstructor)){
return new SomeConstructor();
}
//the constructor properties and methods here
}
после чего вы можете:
var myObj = SomeConstructor();
В дополнение к этому (довольно старому) ответу: вы можете использовать шаблон модуля для создания объекта
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
Здесь jsFiddle для некоторой функциональной функции Date
, которую я создал с использованием этого шаблона.
Ответ 2
Что не так с использованием ключевого слова new
?
Во всяком случае, кажется, что лучше всего читать на Javascript-наследовании:
http://javascript.crockford.com/inheritance.html
Ответ 3
Кто-то опубликовал статью Дугласа Крокфорда в этом вопросе, и он точно объясняет, что вы спрашиваете.
Конструктор конструктора OO Javascript: неоклассический против прототипа
Ответ 4
Вы не можете избежать new
в общем случае (не доходя до крайностей, в соответствии с статьей Crockford Zoidberg, косвенно связанной с), если вы хотите, чтобы наследование и instanceof
работали, но затем (снова), почему вам нужно или нужно?
Единственная причина, по которой я могу думать о том, где вы хотите этого избежать, - это попытаться передать функцию-конструктор другому фрагменту кода, который не знает его как конструктор. В этом случае просто заверните его в функцию factory:
function b() {
// ...
}
function makeB() {
return new b();
}
var c = makeB();
Ответ 5
Простой ответ на ваш конкретный вопрос: no.
Это поможет вам определить, почему вы хотите избежать new
. Возможно, шаблоны, на которые ссылается один из других ответов, помогут. Однако ни один из них не приводит к тому, что instanceof
возвращает true в ваших тестах.
Новая операция по существу: -
var x = (function(fn) { var r = {}; fn.call(r); return r;}(b);
Однако существует разница в том, что конструкция fn
привязана к объекту с использованием некоторого внутреннего свойства (да, вы можете получить его с помощью constructor
, но установка его не имеет такого же эффекта). Единственный способ получить instanceof
для работы по назначению - использовать ключевое слово new
.
Ответ 6
Вы можете создавать экземпляры без нового оператора (вот большая статья, написанная об этом Дугласом Крокфордом http://yuiblog.com/blog/2006/11/13/javascript-we-hardly-new-ya/). Но это не поможет вам с историей "instanceof".
Ответ 7
Да, вы можете это сделать.
var User = function() {
var privateMethod = function() {
alert('hello');
}
return {
sayHello : function() {
privateMethod();
this.done = true;
}
}
}
var user1 = User();
Что-то не так с этим методом?
Ответ 8
Единственный способ заставить instanceof работать - использовать новое ключевое слово. instanceof exploits ____proto____, который устанавливается новым.
Ответ 9
Объекты JavaScript могут быть созданы без использования нового ключевого слова.
Например, следующая функция возвращает объект без использования нового ключевого слова
function a(){
var obj ={};
obj.name = "hello";
obj.age = 12;
return obj;
}
Ответ 10
В ярлыке javascript вы можете использовать eval (unescape ( "..." )) для создания объекта без "нового" оператора:
javascript:xhr=eval(unescape('new\x20XMLHttpRequest();'));alert(xhr);
Ответ 11
Для тех, кто может найти это через Google (например, я...), я разработал оригинальное решение для более широкого использования:
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)
Ответ 12
Используя 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);
Ответ 13
Да.
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()