Основы языка Javascript


javascript frontend

Статья посвящена в первую очередь изучающим Javascript. Некоторые из вещей могут показаться очевидными, но я надеюсь, что читатель найдет что-то интересное и для себя. Сам я прочитал достаточное количество статей в сети по этому языку. Но найти материал который бы кратко и просто излагал сущность языка я так и не нашел. Это меня вдохновило на написание собственной статьи.

Javascript - это

Объявление переменных

JS слабо типизированный язык, что демонстрирует следующий пример:

var text = 'some text';
text = 42;  // there is 42 now

Важно:

Типы данных

Простые

Ссылочные

Разберем каждый тип подробнее:

Number

var num = 100500;   // this is a number type
num = 0.0009;       // also this is a number type

Доступны все стандартные числовые операции: + - * / % ++ --

var thisIsInfinity = 999/0;                 // Infinity
var thisIsNaN = "this is not number" * 3;   // NaN

String

Пример использования кавычек:

var fooString = "I say: 'Yeah!' It's cool.";
fooString = 'He said: "Yeah!"’;

Конкатенация строк:

var text = "a" + "b";   // text has value "ab"

Другие полезные методы:

Boolean, undefined and null

  1. Boolean (true/false)
var thisIsTrue = true;
  1. Undefined - специальный тип, который означает, что переменная не определена
var foo;    // foo is undefined
  1. Null - специальный тип, означает буквально "ничего"
var bar = null; // foo is null

Объекты в Javascript

Объекты в JS это стандартные ассоциативные массивы, другими словами "хэш".

var obj = {
    name: "John",
    lastname: "Johnson"
}

Ассоциативный массив - абстрактный тип данных состоят из набора из пар <ключ>: <значение>.

Создание объектов

Оба способа эквивалентны:

var obj = {};           // simple creating
var obj = new Object(); // standard syntax

Литеральный синтаксис:

// creation with properties
var obj = {
    name: "John",
    lastname: "Johnson"
}

Операции с объектами

obj.name = "John";              // add property
obj[“lastName”] = "Johnson";
alert(obj.name);                // get property
alert(obj["lastName"]);
delete obj.name;                // delete property

Оператор in

var obj = new Object();
obj.prop = 'exists';
'prop' in obj;          // returns true
'toString' in obj;      // returns true

Метод hasOwnProperty

var obj = new Object();
obj.prop = 'exists';
obj.hasOwnProperty('toString'); // returns false

В отличие от оператора in, метод hasOwnProperty не проверяет по объекту цепочку прототипов.

=== undefined

var obj = {};                   // add property with undefined value
obj.test = undefined;
alert(obj.test === undefined);  // true
alert(obj.test2 === undefined); // true

Вполне возможна ситуация, что свойство существует и является равно undefined

Преобразование типов

String

var str1 = String(1);   // string '1'
var str2 = '' + 1;      // string '1'

Numerical

var num1 = Number('42');    // number 42
var num2 = +'42';           // number 42

Boolean

var bool1 = Boolean(null);  // false
var bool2 = !null;          // false

Операторы сравнения

Приведение типов используется в операторах: < > <= >= == != Приведение типов НЕ используется в операторах: === !==<

Советую использовать для более наглядного сравнения равенства/неравенства операторы === и !== соответственно.

Примеры для демонстрации:

"" == "0"   // false
0 == ""     // true
0 == "0"    // true

false == "false"    // false
false == "0"        // true
false == undefined  // false
false == null       // false

null == undefined  // true

"\t \r \n" == 0     // true

"" === "0"  // false
0 === ""    // false
0 === "0"   // false
0 === "0"   // false

false === "false"       // false
false === "0"           // false
false === undefined     // false

false === null      // false

null === undefined  // false

"\t \r \n" === 0    // false

Массивы

Одно из важных и отличительных свойств массивов в Javascript является то, что массивы могут содержать переменные разных типов.

var emptyArray = [];
var numberArrray = [1, 2, 3];
var myCollection = [1, 'my_string', true];
myCollection[0];    // 1

Некоторые полезные функции работы с массивами:

Особое внимание хочется уделить свойству массива length.

var myArray = [1, 2, 3];
myArray.length;     // equals 3
myArray.length = 4;
myArray.length = 2; // [1, 2]
myArray[1000000] = 4;

Таким образом length = последний индекс массива + 1. Если часть элементов массива не будут инициализированы, то они будут равны undefined.

Функции

Функции - это объекты в Javascript. Поэтому их можно присваивать переменным, передавать и, конечно, у них есть свойства. Существует 3 способа создать функцию. Основное отличие в результате их работы - в том, что именованная функция видна везде, а анонимная - только после объявления.

Именнованные

sayAnithing("Hi");
function(message) {
    alert(mesage);
}

Анонимные

var sayBonjour = function () {
    alert("Bonjour!");
}
sayBonjour();   // Says "Bonjour!"

Аргументы функции

Функции можно запускать с любым числом параметров. Если функции передано меньше параметров, чем есть в определении, то отсутствующие считаются undefined.

foo(0, 1, 2, 3, 4);
function foo (a, b, c) { 
    arguments[0] = 2;
    a;              // 2
    b = 17;
    arguments[1];   // 17
    arguments[4];   // 4
}

Аргументы можно изменять.

Одной из любопытных функций является typeof(), которая возвращает тип переменной.

typeof undefined     // undefined
typeof 0             // number
typeof true          // boolean
typeof "foo"         // string

Специфика языка Javascript:

typeof {}            // object
typeof null          // object
typeof function() {} // function

Scope и контекст выполнения

typeof {}            // object
typeof null          // object
typeof function() {} // function

Выполнение JavaScript представляет из себя стэк контекстов выполнения. Контекст, который активирует другой контекст, называется вызывающим контекстом (caller). Контекст, который вызывают, называется вызываемым контекстом (callee). При этом callee-контекст может являться caller’ом для другого callee, что частенько и происходит когда один из одной функции вызывается другая.

var color = "blue"; // Global scope
function changeColor () {
    // changeColor scope
    var anotherColor = "red";
    function swapColors () {
        // swapColors scope
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
    }
    swapColors(); // function call
}
changeColor();  // function call

Схема ниже иллюстрирует контекст выполнения функций:

func_scope

Переменные видны внутри контекста функции не зависимо где они объявлены. Необычно для новичков в JS выглядит следующий пример:

function myFunc () {
    If (true) {
        var localVar = "I’m local";
    }
    console.log(localVar);  //Shows "I’m local" in myFunc
}

Замыкания

Замыкание - внутренняя функция. Javascript позволяет создавать функции по ходу выполнения скрипта. И эти функции имеют доступ к переменным внешней функции.

Рассмотрим пример:

function Counter () {
    var count = 0;
    return function () {
        return ++count;
    }
}

var increaseCount = Counter();
alert(increaseCount()); // Shows 1
alert(increaseCount()); // Shows 2

Внутренняя анонимная функция замыкает на себе функцию Counter. Это означает что когда заканчивает работать функция Counter, внутренняя функция остается жить, ее можно запускать в другом месте кода. В этой функции мы используем переменную count, т.е получается что внутренняя функция замыкает на себе переменную count внешней функции.

Прототипы

В Javascript все объекты наследуют Object, поэтому каждый объект имеет свойство prototype. Prototype это объект, которое позволяет шарить свойства с другими объектами.

prototypes

Например, когда у объекта свойство "jump", то интерпретатор языка ищет сначала это свойство у самого объекта, а потом спускаясь по цепочке прототипов ищет в них пока не найдет.

"Классы"

В спецификации ECMAScript 5 нет понятия класса. Реализовать класс в привычном понятии для ООП можно путем создания конструктора с прототипом. Принадлежность к классу проверяет оператор instanceof.

function Animal (name) {
    //constructor
    this..name = name;
}

Animal.prototype.speed = 0; //Property with value by default
Animal.prototype.run = function (speed) {
    //Method of prototype
    this.speed += speed;
    alert(this.name + ' run, speed is: ' + this.speed);
}

this

this зависит от контекста вызова. Рассмотрим возможные варианты:

this в простом вызове

В этом случае this - это глобальный объект

function simpleFunction () {
    this;
}
simpleFunction();

this в конструкторе

В этом случае this - это новый объект

function simpleConstructor () {
    this.someProperty = "This is some property";
}
var someObject = new simpleConstructor();

this в методе объекта

В данном примере this это объект country:

var country = {
    name: "Sparta",
}

var say = function () {
    alert("This is " + this.country.sayName();
}

country.sayName = say;
country.sayName();

this как первый аргумент в call/apply

Наследование

В JS в отличие от других языков программирования реализация наследования как одного из принципов ООП, может быть реализовано несколькими способами. Думаю в данной статье будет излишне описывать каждый из способов, подробно о них можно прочитать в книге: "Professional JavaScript for Web Developers", N. Zakas.

Литература