Вопросы?

Занятие 2

Вопросы!

Передача по значению / по ссылке

  • Как/где располагаются данные?
  • Что такое переменная?
  • Передача по ссылке
  • Передача по значению

Правила именования переменных / свойств

  • "Говорящее название"
  • Переменная - существительное / функция - глагол
  • camelCase / CamelCase / CAMEL_CASE / _x
  • Венгерская нотация *
  • myButton

Вопросы?

Объекты

  • Структура данных - хэш
  • Ссылочный тип данных
Как создать

// Литерал
var o1 = {};
var o2 = {
  prop1: 'Some value',
  prop2: null,
  prop3: 3
};
          

// Вызвать функцию возвращающую объект
var o3 = Object.create(null);
          

// Использовать `new`
var o4 = new Object();
var o5 = new Object({
  a: 1,
  b: 2
});
          
Как работать со свойствами

var o = {};
o.prop1 = 1;
o['prop2'] = 2;
          

var o = {};
o['some property with spaces'] = 3;
          

var o = {};
var propName = true ? 'prop1' : 'prop2';
o[propName] = 4;
          

Вопросы?


var o = {
  x: 1
};
console.log(o.x); // ?
var a = 'x';
o.a = 2;
console.log(o.x); // ?
var b = 'x';
o['b'] = 3;
console.log(o.x); // ?
                        
Принципы ООП
  • Абстракция - позволяет оперировать аналогами объектов из реального мира
  • Инкапсуляция - позволяет не думать о реализации
  • Наследование - позволяет уменьшить дублирование кода
  • Полиморфизм
Наследование

Позволяет один раз описать свойства / поведение класса объектов и дальше использовать это описание ( и реализацию ) многократно

Вопросы?

Свойства объекта

var o = {
  prop1: 2,
};
console.log(o);
console.log(o.prop1); //? 
console.log(o.prop2); // ?
          

var o = {
  someMethod: function() {
    console.log('Hey!');
  }
};
console.log(o);
console.log(o.someMethod); //?
console.log(o.toString); // ?
          
__proto__

var o = {
  prop1: 1,
  __proto__: {
    prop2: 2
  }
};
console.log(o);
console.log(o.prop1); //1
console.log(o.prop2); //2
console.log(o.prop3); //undefined
          

var o = {
  prop1: 1,
  __proto__: {
    prop2: 2,
    __proto__: {
      prop3: 3
    }
  }
};
console.log(o);
console.log(o.prop1); //1
console.log(o.prop2); //2
console.log(o.prop3); //3
          
Запись свойств

var proto = {
  prop0: 1
};
var o1 = {
  prop1: 1,
  __proto__: proto
};
var o2 = {
  prop2: 2,
 __proto__: proto
};
console.log(o1.prop0, o2.prop0); // ?
          

proto.prop0 = 5;
console.log(o1.prop0, o2.prop0); // ?
          

o2.prop0 = 7;
console.log(o1.prop0, o2.prop0); // ?
          

console.log(proto.prop0); // ?
          
Запись свойств

var proto = {
  settings: {
    isAdmin: false,
  }
};
var u1 = {
  name: 'Bob',
  __proto__: proto
};
var u2 = {
  name: 'Sam',
  __proto__: proto
};
          

console.log(u1.settings.isAdmin); // ?
          

 u1.settings.isAdmin = true;
console.log(u1.settings.isAdmin); // ?
          

console.log(u2.settings.isAdmin); // ?
          
Как прочитать свойства объекта?

var o = {
  prop1: 1,
  prop2: 2
};
for(propName in o) {
  console.log(propName);
}
          

var o = {
  prop1: 1,
  __proto__: {
    prop2: 2
  }
};
for(propName in o) {
  console.log(propName);
}
          

var o = {
  prop1: 1,
  __proto__: {
    prop2: 2
  }
};
for(propName in o) {
  console.log(propName, o.hasOwnProperty(propName) ? 'в объекте' : 'в цепочке прототипов');
}
          
Как удалить свойства объекта?

var o = {
  prop1: 1,
  __proto__: {
    prop1: 2
  }
};
console.log(o.prop1); // ?
delete(o.prop1);
console.log(o.prop1); // ?
          

delete(o.prop1); 
console.log(o.prop1); // ?
          
Задание прототипа
  • __proto__
  • Object.setPrototypeOf(obj, prototype);
  • Object.create(proto[, propertiesObject])
  • ...

Вопросы?

Функции

Характеристики функции? Сигнатура?
  • Имя функции
  • Число и тип параметров (аргументов)
  • Тип возвращаемого значения
  • Контекст *
Способы создания функции (3)
Function Declaration

function greet1(name) {
  console.log("Hello, " + name);
}
greet1();
          
Functional Expression

var greet2 = function(name) {
  return console.log("Hi, " + name);
}
greet2();
          

var greet2 = function greet(name) {
  return console.log("Hi, " + name);
}
greet2();
          
Function by constructor

var greet3 = function("name") {
  return console.log("Hi, " + name);
}
greet3();
          

var greet3 = new Function("name", "return 'Hola, ' + name;");
greet3();
          
Функции высшего порядка

Принимают параметром и/или возвращают функции как результат работы


var createGreet = function(age) {
  var text = age > 18 ? 'Приветствую' : 'Хаюшки';
  return function(name) {
    console.log(text + ', ' + name);
  }
};
var greet1 = createGreet(45);
greet1("Роберт"); // ?
var greet2 = createGreet(11);
greet2("Саня"); // ?
          

// Приветствую, Роберт
// Хаюшки, Саня
          
Функции высшего порядка

Принимают параметром и/или возвращают функции как результат работы


document.findElementById('btn')
  .addEventListener('click', function() {
    alert('*Opa')!
  });
          
Функция - объект

var greet = function(name) { return 'Hi, ' + name; };
console.log(typeof(greet));
          
greet.

console.log(greet.hasOwnProperty('hasOwnProperty'));
console.log(greet.hasOwnProperty('toString'));
console.log(greet.toString());
          
Функция - как свойство

var o = {
  method: function(param) {
    console.log('Do somethind with', param);
  }
};
o.method('icecream');
          

Вопросы?

Замыкания

var createGreet = function(age) {
  var text = age > 18 ? 'Приветствую' : 'Хаюшки';
  return function(name) {
    console.log(text + ', ' + name);
  }
};
var greet1 = createGreet(45); 
greet1("Роберт");
          

function getCounter() {
  var i = 0;
  return {
    next: function() { i = i + 1; },
    reset: function() { i = 0; },
    current: function() { return i; }
  }
};
var counter = getCounter();
console.log(counter.current()); // ?
counter.next(); counter.next();
console.log(counter.current()); // ?
counter.reset();
console.log(counter.current()); // ?
          

var i = counter.current();
i = 9;
console.log(counter.current()); // ?
          

Вопросы?

Контекст / this
Определяет кто/где выполняет функцию

function someStrangeFunction() {
 console.log('this for someStrangeFunction', this);
}
someStrangeFunction();
          

var o = {
  prop1: 1,
  someStrangeFunctionInObject: function() {
    console.log('this for someStrangeFunctionInObject', this);
  }
}
o.someStrangeFunctionInObject();
          

this позволяет задавать/изменять окружение исполнения функции


function someStrangeFunction() { console.log('this for someStrangeFunction', this); }
var o = { prop1: 1 };
someStrangeFunction(); // ?
o.someStrangeFunction = someStrangeFunction;
o.someStrangeFunction(); // ?
          

var o = {
  prop1: 1,
  ssMethod: function() {
    console.log('this for ssMethod', this);
  }
}
o.ssMethod();
var ssm = o.ssMethod;
ssm();
          
Три возможных значения this
  • window
  • undefined
  • object
Передача методов как параметров

var o = {
  name: 'Bob',
  greet: function() {
    console.log('Hello, ' + this.name);
  }
}
document.body.addEventListener('click', o.greet);
          

var x = o.greet;
document.body.addEventListener('click', x); // x()
Изменение контекста функции

var o = { prop1: 1, name: 'Sam' }; 
var f = function() { console.log(this); };
f(); // ?
          

o.of = f; o.of(); // ?
          

f.call(o);
          

f.apply(o);
          

var of = f.bind(o);
of();
          
call/apply/bind

var o = { prop1: 1, name: 'Sam' }; 
var f = function(name) { console.log(this, name); };
f('user 1');
f.call(o, 'user 2'); // параметры один за одним
f.apply(o, ['user 3']); // параметры списком

f.bind(o)('user 4'); // bind возвращает функцию для вызова
          
new
Еще один способ изменить this

var f = function(name) { console.log(this); };
f('Sam'); // ?
console.log(new f('Bob')); // ?
          
  • new с любой функцией создает новый объект
  • Новый объект получает значение в __proto__
  • туда записывается f.prototype
  • Новый объект становится возвращаемым значением по-умолчанию
  • Функции предназначенные для вызова с new - конструкторы
  • Конструкторы именуются с большой буквы

function User(name, greet) {
  // изменяем новый объект при создании
  this.name = name;
  this.greetPhrase = greet;
  this.greet = function() {
    console.log(this.greetPhrase + ', ' + this.name);
  }
};
var u1 = new User('Bob', "Hello");
var u2 = new User('Sam', "hi");
console.log(u1, u2);
u1.greet();
u2.greet();
          

function User(name, greet) {
  this.name = name;
  this.greetPhrase = greet;
};
User.prototype = {
 greet: function() { console.log(this.greetPhrase + ', ' + this.name); }
}
var u1 = new User('Bob', "Hello");
var u2 = new User('Sam', "hi");
console.log(u1, u2);
u1.greet();
u2.greet();
          

function User(name, greet) {
  this.name = name;
  // читаем greet через замыкание
  this.greet = function() {
    console.log(greet + ', ' + this.name);
  }
};
var u1 = new User('Bob', "Hello");
console.log(u1);
u1.greet();
          
Использование конструкторов позволяет
  • создавать свои "классы" / типы объектов
  • убрать дублирование кода для однотипных объектов
Как проверить, что объект является экземпляром класса?

function User() { }
var fu = {};
var u = new User();

console.log(fu, fu instanceof User);
console.log(u, fu instanceof User);
          
instanceof ходит по цепочке прототипов

x instanceof Y 
-> x.__proto__ === Y.prototype 
-> x.__proto__.__proto__ === Y.prototype 
-> ...
          

var o = {};
console.log(o instanceof Array); // ?
          

o.__proto__ = []
console.log(o instanceof Array); // o.__proto__.__proto__
          

Вопросы?

Что со всем этим делать?