Pull to refresh

Prototype, proto и оператор new

Website development *JavaScript *
Tutorial
В этой статье я кратко в примерах объясню что такое свойства __proto__, prototype и работу оператора new в JavaScript.

Свойство __proto__


Абсолютно любой объект в JavaScript имеет свойство __proto__. Это скрытое системное свойство, и не во всех реализациях языка оно доступно пользователю.
При обращении к любому свойству объекта, оно в первую очередь ищется в самом объекте:
var obj = {ownProperty: 1};
console.log(obj.ownProperty);// 1
Но если его там нет, поиск происходит в свойстве __proto__:
obj.__proto__ = {propertyOfProto: 2};
console.log(obj.propertyOfProto);// 2
Если его нет и там, оно ищется дальше по цепочке:
obj.__proto__.__proto__ = {propertyOfProtosProto: 3};
console.log(obj.propertyOfProtosProto);// 3
Эта цепочка называется цепочкой прототипов (prototype chain).



__proto__ любого значения (кроме null и undefined) ссылается на prototype соответствующего ему типу данных:
(0).__proto__ === Number.prototype &&
false.__proto__ === Boolean.prototype &&
"string".__proto__ === String.prototype &&
(new Date).__proto__ === Date.prototype &&
(function(){}/* new Function */).__proto__ === Function.prototype
Все типы данных наследуются от Object, это означает что к примеру:
Number.prototype.__proto__ === Object.prototype
И наконец, завершение цепочки:
Object.prototype.__proto__ === null

Свойство prototype


А чем же тогда является свойство prototype? Это обычное свойство, ничем не отличающиеся от любых других свойств. За исключением двух особенностей:

1) Функции в JavaScript имеют свойство prototype. Оно по умолчанию является объектом с единственным свойством constructor, которое ссылается на саму функцию.



2) Свойство prototype используется при создании новых объектов оператором new.

Оператор new


Этот оператор делает следущее:

1) Создает пустой объект:
var instance = {};

2) Устанавливает __proto__ этому объекту ссылкой на prototype функции-класса:
instance.__proto__ = FnClass.prototype;

3) Применяет функцию-класс к нашему новосозданному объекту:
constructorReturns = FnClass.apply(instance, arguments);
(т.е. исполняет функцию FnClass, передавая ей instance в качестве this и аргументы в виде массива arguments)

4) Возвращает экземпляр функции-класса, но если FnClass нам вернул обьект, тогда его:
return constructorReturns instanceof Object ? constructorReturns : instance;

Функцией-классом я называю функцию, к которой впоследствии ожидается применение оператора new. Такие функции принято именовать с заглавной буквы.

Использование __proto__ в ваших скриптах


Т.к. свойство __proto__ является скрытым, и не описано в спецификации языка, то использование его в явном виде некорректно. Так что никогда не пишите так как я выше в примерах :) Этот код только для консоли.
Однако в последней (действующей) спецификации ECMA Script 5 наконец-то появились два метода, позволяющие манипулировать свойством __proto__, это Object.create и Object.getPrototypeOf.
Поясню их работу в двух простых примерах:


//var myObj = {__proto__: {property1_OfProto: 1}}
var myObj = Object.create({property1_OfProto: 1});


//myObj.__proto__.property2_OfProto = 2
Object.getPrototypeOf(myObj).property2_OfProto = 2;

Если вы используете более раннюю версию JavaScript, то метод Object.create можете создать самостоятельно:

if(!Object.create){
	Object.create = function(proto){
		var Fn = function(){};
		Fn.prototype = proto;
		return new Fn;
	}
}

C getPrototypeOf ситуация сложнее, его можно эмулировать только для функций, и только при условии что constructor этой функции не был изменен:

if(!Object.getPrototypeOf){
    if( (new Object).__proto__ !== Object.prototype ){
        // may return incorrect value if fn.prototype has been modified
        Function.getPrototypeOf = function(fn){
            if(typeof(fn)!=='function')
                throw new TypeError('Function.getPrototypeOf called on non-function');
            return fn.constructor.prototype;
        }
    }else{
        Object.getPrototypeOf = function(obj){
            return obj.__proto__;
        }
    }
}

А лучше, как посоветовали в комментах, используйте библиотеку github.com/kriskowal/es5-shim

Далее — о классах в JavaScript...

Tags: __proto__protoprototypenewObject.createObject.getPrototypeOfJavaScript
Hubs: Website development JavaScript
Total votes 82: ↑67 and ↓15 +52
Comments 44
Comments Comments 44

Popular right now