ООП в Java Script (1): Объекты

Все в JavaScript, на самом деле, является объектом. Массив — это объект. Функция — это объект. Объект — тоже объект. Так что такое объект? Объект — это коллекция свойств. Каждое свойство представляет собой пару имя-значение. Имя свойства - это строка, а значение свойства — строка, число, булево значение, или объект (включая массив и функцию).

Когда мы определяем какую-то переменную, например:

var s = 'hello world';
alert(typeof s); // выводит string

мы, в действительности, неявням образом задаем свойство какого-то объекта. В данном случае, таким объектом будет глобальный объект window:

alert (s == window.s); // выводит true
alert (typeof window); // выводит object

Более того, это свойство window.s само по себе является объектом, т.к. в нем уже изначально определена своя коллекция свойств:

alert(s.length); // выводит 11 (число символов в строке)

При всем при том, что это, на первый взгляд, обычный строковый литерал!

Если значение свойства — функция, мы можем назвать это свойство методом объекта. Чтобы вызвать метод объекта достаточно дописать после его имени две круглые скобки (). Когда метод объекта выполняется, переменная this внутри этой функции ссылается на сам объект. С помощью ключевого слова this метод объекта получает доступ ко всем остальным свойствам и методам объета.

var s = 'futurico'; // создаем новое свойство s объекта window (window.s)
var f = function(){ // создаем новый метод f объекта window (window.f)
alert(this == window); // выводит true
alert(this.s); // выводит 'futurico'
}
f(); // вызываем метод f объекта window (window.f())

var o = {}; // создаем новое свойство o объекта window (window.o)
o.s = 'karaboz'; // создаем новое свойство s объекта window.o (window.o.s)
o.f = function(){ // создаем новый метод f объекта window.o (window.o.f)
alert(this == o); // выводит true
alert(this.s); // выводит 'karaboz'
}
o.f(); // вызываем метод f объекта window.o (window.o.f())

Объект создается с помощью функции-конструктора, инициализирующей объект, и ключего слова new. Функция-конструктор предоставляет те же возможности, что и класс в других языках программирования: а именно, описывает шаблон, по которому будут создаваться объекты (экземпляры) класса. В основе такого шаблона лежит перечисление свойств и методов, которыми будет обладать объект, созданный на основе данного класса. Для всех встроенных типов данных в JavaScript существуют встроенные функции-конструткоры.

Например, когда мы объявляем строковую переменую:

var str='karaboz';

мы неявным образом вызываем встроенную функцию-конструтор:

var str = new String('karaboz');

и тем самым создаем объект (экземпляр) класса String.

Это же утверждение верно и для всех остальных типов данных JavaScript:

// число
var num = 12345.6789; // var num = new Number(12345.6789);

// булево значение
var bul = true; // var c = new Boolean(true);

// функция
var fun = function(x){var p = x}; // var fun = new Function('x', 'var p = x');

// массив
var arr = ['a', 'b', 'c']; // var arr = new Array('a', 'b', 'c');

// объект
var obj = {}; // var obj = new Object();

У всех этих объектов сразу же после создания определены все свойства и методы, описанные в их функциях-конструкторах (классах):

alert(num.toFixed(1)); // выводит 12345.6
alert(arr.length); // выводит 3

На самом деле, интерпретатор JavaScript действует несколько хитрее, чем может показаться из предыдущего примера. Так, несмотря на то, что следующий код показывает равенство двух переменных (объектов класса String):

var str1 = 'karaboz';
var str2 = new String('karaboz');
alert(str1 == str2); // выводит true

при попытке определить новый пользовательский метод для str1 мы получим ошибку:

str1.tell = function(){
alert(this);
}
str1.tell(); // выводит ошибку 'str1.tell is not a function'

При этом, для str2 все сработает, как мы и ожидаем:

str2.tell = function(){
alert(this);
}
str2.tell(); // выводит 'karaboz'

Это ограничение, наложенное JavaScript на переменные (объекты), созданные через строковые, числовые и булевы литералы, тем не менее, не распространяется на объекты, созданные через литералы функции, массива или объекта. Т.е. переменным (объектам), содержащим в себе функцию, или массив, или объект можно напрямую присваивать пользовательские свойства и методы:

var s = 'futurico'; // создаем новое свойство s объекта window (window.s)
var f = function(){ // создаем новый метод f объекта window (window.f)
alert(this == window); // выводит true
alert(this.s); // выводит 'futurico'
}
f(); // вызываем метод f объекта window (window.f())


f.s = 'karaboz'; // создаем новое свойство s объекта window.f (window.f.s)
f.m = function(){ // создаем новый метод m объекта window.f (window.f.m)
alert(this == f); // выводит true
alert(this.s); // выводит 'karaboz'
}
f.m(); // вызываем метод m объекта window.f (window.f.m())

Здесь мы наглядно убеждаемся, что функция f, созданная как метод глобального объекта window, сама оказывается объектом, у которого могут быть свои собственные свойства и методы!

Все публикации по теме ООП в JavaScript

Комментарии (11) на “ООП в Java Script (1): Объекты”

  1. Zeroglif:

    > Например, когда мы объявляем строковую переменую мы неявным образом вызываем встроенную функцию-конструтор и создаем объект (экземпляр) класса String.

    Если бы это было так, как вы говорите (а это не так), то вы не смогли бы отличить объектный тип от не-объектного со всеми из этого вытекающими последствиями, и объяснять странное поведение javascript пришлось бы только с помощью термина "хитрость", но ничего хитрого тут нет, javascript различает типы, на этих различиях построена логика, в зависимости от операций постоянно происходит преобразование значений из типа в тип…

    > Это же утверждение верно и для всех остальных типов данных JavaScript.

    Только в отношении инициализаторов массива и объекта, всё остальное надумано. ;-)

    > У всех этих объектов сразу же после создания определены все свойства и методы, описанные в их функциях-конструкторах

    В нативных конструкторах (Object, Array, Function…) ничего не описано, свойства наследуются с помошью цепи прототипов. При необходимости примитивные значения (кроме undefined и null) конвертируются в объектный тип, чтобы мы могли получить доступ к соответствующим свойствам.

  2. karaboz:

    Все, что вы сказали — чистая правда и мне нечего возразить (= Однако я под объектом подразумевал не один из типов данных в JavaScript, а способ организации и управления данными, коротко опредлеив в самом начале, что "Объект — это коллекция свойств". (=

    Посыл всей этой публикации будет, видимо, более очевиден после ознакомления со всем задуманным циклом ООП в JavaScript

  3. Zeroglif:

    Посыл понятен и полезен. Я только комментирую некоторые терминологические неточности. Для общей пользы и просветления. Удачи!

  4. ihrd:

    опечатка:
    > var o = {}; // создаем новое свойство o объекта window (window.o)
    ^^^

  5. ihrd:

    нет никакой опечатки, извините, просто запутался в >

  6. C'est_la_vie:

    >>// число
    >>var num = 12345.6789; // var num = new Number(12345.6789);

    Почему же тогда:
    alert(typeof 12345.6789 == 'number') //выведет true
    alert(typeof new Number(12345.6789) == 'number') //выведет "false"!!!

    , при том, что:
    alert(12345.6789 instanceof Number) //выведет "false"
    alert(new Number(12345.6789) instanceof Number) //выведет "true"

    Думаю, что в JavaScript реализовано что-то типа Java`овского autoboxing`а и на самом деле простое число - это на самом деле неявный примитив, а не объект (который хранится в стеке, а не в куче для более быстрых операций с ним) и оборачивается объектом только при необходимости (когда контекст его использования этого требует). И для быстроты выполнения сценария, если это возможно, действительно лучше предпочитать объектам их неявные примитивы.
    Ну и с другими типами похожая ситуация.

    А в остальном статья хорошая, спасибо! :)

  7. romass:

    Автору статьи спасибо. И вообще ресурс очень хороший!!

  8. sarlv:

    "Имя свойства - это строка, а значение свойства — строка"
    То ли я ничего не понимаю, то ли автор не совсем удачно составил предложение

  9. Mitya:

    Функция-конструктор описывает шаблон, по которому будут создаваться объекты (экземпляры) класса.

  10. TestPage:

    И почему так не объясняют в учебниках (или как щас модно - самоучителях) по JS?

    Если бы это было так, как вы говорите (а это не так), то вы не смогли бы отличить объектный тип от не-объектного со всеми из этого вытекающими последствиями,

    Кто-то наверное забыл что Джава Скрипт "нетипизированный" язык. В нём нет жосткого определения типов, как напиример в Си. И если у нас одна переменная была просто числом, то на следующей строке кода мы вполне можем присвоить ей значение объекта, а уже на следующей значение этого объекта обработать как строковое значение…

  11. helper:

    Почему-то прочитав множество статей на javascript.ru, в книге Библия Javasciprt википедии и где-то мало-помалу, нигде нет полного описания того, что такое динамическая типизация. А ведь от этого многое становится ясно. Вот, например, ни следует думать что в переменную записывается значение объекта, в него копируется ссылка на объект. А потом уже в дело вступают такие свойства(заданные компилятором для объекта) объекта, как изменяемость или неизменемость. Те же строки, числа, булевые значения нельзя изменить можно поменять ссылку и ссылаться на другой объект(var a = 1; a = 2, тоже самое var a = Number(1); a = Number(2)), а массивы и объекты можно изменять добавлять или удалять их элементы(var b = {c:1}; b.c = 2). Так вот хотелось бы попросить автора сделать такую статью в которой описывается динамическая типизация и изменяемость, неизменяемость объектов.

Оставить комментарий

Вам нужно войти, чтобы оставить комментарий.