Как стать автором
Обновить

Комментарии 31

Забавная идея. Вместо объекта в конструкторе можно использовать Object.create и тогда instanceof должен работать.

В ECMAScript 6 для приватных свойств можно использовать символы (уже доступно в Chrome, Firefox, io.js и node.js с версией от 0.12 включительно).
Совсем приватные свойства с помощью символов не получится сделать, есть Object.getOwnPropertySymbols
И что? В C# есть Reflection, в Java тоже есть что-то подобное, в Python есть __dict__, в C++ есть Звезда Пустоты. Во всех языках можно получить доступ к приватным полям окольными путями. Так чем же Object.getOwnPropertySymbols мешает приватным полям в Javascript?
instance_of и прочие штуки не будут работать, видимо. Какой смысл делать полноценные приватные свойства? От кого их скрывать? Если пользователь либы хочет стрелять в ногу, пусть стреляет. Но иногда это помогает поправить поведение, если автор библиотеки не учел каких-то случаев / не хочет что-то менять.
Да, действительно. Метод хороший, но для JS куда более эффективен и полезен подход «кишки наружу», как бы это ужасно ни было с точки зрения нормального ООП.
и отказывается от использования прототипов(создает методы для каждого экземпляра объекта заново)

Предложенный вами способ ведь точно так же создает методы для каждого экземпляра класса заново.
Я, к сожалению, не могу понять, что вы имеете в виду этим кодом. Вы избавились от bind(...)? Тем не менее вы создаете новую анонимную функцию для каждого инстанса.
С этим, конечно, не поспоришь.

Этот способ мне напоминает реализацию приватных свойств с помощью WeakMaps (пример). Только там нет возможной путаницы с this и self.
Что вы имеете ввиду? Что современные js-движки настолько глупы, что для каждого объекта будут по новой компилить одну и туже тяжеловесную функцию?
А как же способ спрятать приватные переменные в замыкании?
вы невнимательно читали
И как же их использовать в прицепленных к прототипу методах?
В вашем способе число создаваемых объектов будет вдвое больше, что скажется на объёме потребляемой памяти.
И вообще, зачем прятать приватные поля и методы? Они придуманы просто ради удобства и понимания кода. Просто используйте какую-нибудь нотацию приватных полей и всё.
Костя, лол :) Но работает через геттер — так-что не засчитывается :)
Интересно, долго еще из Javascript с его системой наследования на базе прототипов будут пытаться сделать True OOP язык? ;)
Это обычно пытаются сделать те, кто пришел в JS после многолетнего опыта с «True-ООП»-языками и уже мыслит в этой «True-ООП»-парадигме. С таким мышлением им приходится пытаться эмулировать поведение привычных им языков, хотя необходимости в этом нет.
Согласен с вами, однако уже и классы в ES6 добавили.
Нет. Те, кто приходят с True-ООП языков первым делом приходят в дикий восторг: «надо же, я могу в рантайме менять структуру всех объектов, офигеть!»
После чего эти люди начинают на каждое упоминание классов писать «не надо классов! вы не понимаете всей красоты прототипов!».
Через какое-то время до некоторых начинает доходить: «ну могу я структуру прототипа в рантайме поменять, ну что дальше?»
Не знаю кто вас минуснул, странно.
А так:

Восторг это дело случая. Кто слезает с PHP не особо удивляется, ведь аналог там есть.

Про классы тоже дело случая, даже скорее вкусовщина. Кто-то хочет классов (я), а кто-то любит писать просто и без заморочек, структур и только базовый инструментарий.

А дальше смотря как принято в личном кодстайле и как в компании. Кто-то может добавить метод к классу (или изменить реализацию или бог его знает что ещё, возможностей и потребностей много), а кто-то связан по рукам и ногам правилом «не меняйте прототипы базовых классов».
Так же в зависимости от условий может быть по-разному реализован метод. И бывает так, что у тебя два варианта: встроить логику в метод или на основе логики создать тот или иной метод (например шаблонизатор может быть один и другой. Вы знаете на момент объявления метода какой есть шаблонизатор. Вы можете в теле проверять при каждом вызове или один раз создать метод с правильным вызовом)
Автор, вопрос в лоб: нужны мне, допустим, приватные и публичные свойства. И с теми и с другими должны уметь работать методы. Как быть?
Приватные пишите в self, публичные пишите в this:

    return {
        hello: funciton(){
            self.private_ = 123;
            this.public_ = 123;
        }
    };
Нужно разобраться, зачем нужны скрытые свойства.

1. Для защиты от страшных хакеров, которые «взломают» мой объект.
2. Для того, чтобы использующий класс программист, видел только его интерфейс и ему не мозолили глаза способы реализации.

Для 2-го вполне хватает jsdoc'ов с private и IDE'шек с автокомплитом.
3. Для грамотного наследования без «леса» частных свойств и методов
4. Для того, чтобы после подключения библиотечного класса не лезли куда нельзя и не ломали что не надо.

Для 4-его есть культура программирования и установка не обращаться к метдам и свойствам, начинающихся с _ (подчёркивания)
Для 3 только если функцию создающую наследование допилить как-то. И пригодно только для JS, кофе лесом

Риторика
О необходимости вопрос равен вопросу применимости. Для маленьких проектов и скриптов по-настоящему пофиг. А для огромной монолитной системы с множественными наследованиями это уже актуально. Пишу на кофе, поэтому классы и наследование — стандартное явление.
Если не наследоваться, а использовать как либу, то можно и кишками наружу. А при наследовании (если в либе все приватные свойства не сидят в замыкании конструктора) никакие подчёркивания не спасут. Если, например, я для обозначения приватности свойства использовал в его имени подчёркивание как и автор либы. Не лезть же в либу проверять нет ли совпадений для каждого _x (а при минифицировании тут вообще нет гарантий защиты от совпадения имён). Использовать в конструкторе либы var вместо this для приватного свойства нельзя, так как нужен доступ к свойству из метода, добавленного в prototype.

function Lib() {
    this._private = 1;
}

Lib.prototype.getPrivate = function() {
    return this._private;
}

function MyClass() {
    this._private = 2;
}

MyClass.prototype = new Lib();

var myClass = new MyClass();

console.log("_private = " + myClass._private);    // 2
console.log("getPrivate = " + myClass.getPrivate());    // 2


function Lib() {
    var self = this;	// свойство доступно только из конструктора

    this._private = 1;	// свойство доступно и из конструктора и из методов, добавленных через prototype

    return {
        getPrivate: function() {
            return self.privateMethod();
        },
        // или
        getPrivateAlt: Lib.prototype.privateMethod.bind(this)
    }
}

Lib.prototype.privateMethod = function() {
    return this._private;
}

function MyClass() {
    this._private = 2;
}

MyClass.prototype = new Lib();

var myClass = new MyClass();

console.log("_private = " + myClass._private);    // 2
console.log("getPrivate = " + myClass.getPrivate());    // 1
console.log("getPrivateAlt = " + myClass.getPrivateAlt());    // 1
>>«Поскольку функция конструктор возвращает простой объект, не работает instanceof;»

Никто не мешает создаваемому объекту указать явно прототип Animal, вместо Object (создаем через Object.create, а не литерал). Тогда и instanceof будет работать корректно через цепочку прототипов и конструктор будет определяться верно у объекта.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории