Присвоювання деструктуризації - це спеціальний синтаксис, який дозволяє нам «розпакувати» масиви або об'єкти в купу змінних, так як іноді вони зручніші. Деструктуризація також прекрасно працює зі складними функціями, які мають багато параметрів, значень за замовчуванням і так далі.
// в нас є масив з двома елементами
let arr = ["Red", "Green"]
// Присвоювання деструктуризації
// записує first=arr[0], second=arr[1]
let [first, second] = arr;
console.log(first); // Red
console.log(second); // Green
Варіант 1. Зберігати одну загальну сіль для всіх паролів користувачів поза БД
hash(secret + password)
На перший це виглядає безпечніше, адже якщо хтось отримає доступ до БД, то солі у ньому не буде, і напевно відновити паролі не зможе? ..
Але якщо зловмисник отримає доступ і до БД, і до солі зі змінної середовища, то для добування паролів все одно треба буде будувати райдужну таблицю. І якщо у вас одна сіль на всіх користувачів, то це зробити набагато простіше. Інша проблема з безпекою: якщо зловмисник (або його співучасник/жертва) має доступ до системи як користувач, то він вже знає 1 пароль і його хеш, можливо зможе змінювати пароль і дивитися зміну хеша, знаходити в БД інших користувачів з таким же паролем...
Цей варіант схожий на принцип Security through obscurity (безпека через неясність/заплутування), а цього принципу радять уникати і покладатися на сильніші криптографічні методи.
Варіант 2. Зберігати свою для кожного користувача сіль в БД з хешамі паролів
hash(salt + password)
В цьому випадку, якщо зловмисник отримає доступ до БД, то разом з хешами паролів він отримає і солі до них. Але тепер для отримання паролів треба буде згенерувати не одну райдужну таблицю на всіх, а для кожного користувача свою! При цьому, важливо коректно реалізувати свою систему роботи з користувачами: при зміні пароля треба міняти і сіль, щоб навіть маючи стару версію БД, зловмисник вже не зміг отримати з цього вигоду.
Цей же спосіб використовується в Django, також його радять і обгрунтовують в аналогічному питанні на enSO - раджу почитати, там обговорені різні варіанти і їх обгрунтування.
Питання насправді спірне і залежить від реалізації вашої системи. Якщо у вас лише 1 або кілька серверів з повним або слабо захищеним доступом один до одного, то швидше за все зловмисник отримавши доступ до БД, легко отримає доступ і до ОС зі змінними оточення, і навпаки, що нівелює сенс першого варіанту. Якщо ж у вас велика і продумана інфраструктура, доступи до БД і серверів з кодом розмежовані, налаштовані жорсткі групи безпеки, всюди використовуються користувачі з обмеженнями і в БД, і в ОС, то можна отримати вигоду з першого способу. Тому є наступний варіант.
Варіант 3. Змішати обидва варіанти
Можна поєднати краще від двох світів, наприклад так:
hash(hash(salt + secret) + password)
Хоча є й інші варіанти, деталі можна знайти все в тому ж питанні . Але знову ж таки, користі в цьому не сильно більше, ніж у другому варіанті, особливо якщо ваша серверна інфраструктура слабо захищена.
Методи map, forEach, і reduce дійсно мають багато спільного, що і коли використовувати залежить від того який саме результат за підсумком потрібно отримати.
Якщо нам потрібно просто виконати певну дію для кожного елемента масиву, то тут підійде метод forEach :
locations.forEach(location => {
console.log(location)
// мы отримаємо такий вивід на консоль
// по одному для кожнго елемента масиву
// {country: "Україна", population: 2}
// {country: "Китай", population: 100}
// {country: "США", population: 20}
})
Або так, якщо нам потрібно лише певне значення
locations.forEach(location => {
console.log(location.country)
// Україна
// Китай
// США
})
Або так, по кількості значень в масиві
locations.forEach(() => {
console.log("Як справи?")
// Як справи?
// Як справи?
// Як справи?
})
Якщо ми хочемо трансформувати наш масив і занести результати в змінну, то тут метод map буде доречніше ніж forEach, оскільки перший за підсумком відразу поверне новий масив.
Подивимося на різницю forEach vs map в разі коли нам потрібно "обернути" кожну власну назву країни в HTML тег:
// через forEach
const result = []
locations.forEach(location => {
result.push(`<h1>${location.country}</h1>`)
})
console.log(result)
// ["<h1>Україна</h1>", "<h1>Китай</h1>", "<h1>США</h1>"]
Метод reduce відрізняється від map тим що він повертає фінальне "значення" .
Припустимо ми хочемо порахувати сумарний розмір населення:
const result = locations.reduce((total, location) => {
return total + location.population
}, 0)
console.log(result)
// 122
Це досить простий приклад, але "фінальним значенням" може бути не тільки число, а, наприклад, об'єкт або масив, що робить метод reduce дійсно потужним інструментом трансформацій.
При написанні досить великого шматка коду (неважливо, класу, функції або чого-небудь ще) важливим прийомом є декомпозиція. Ви ділите функціональність на логічні частини, і в головній функції складаєте з них, як з цеглинок, загальну логіку.
При цьому самі цеглинки можуть бути не пристосовані для доступу зовні. Наприклад, відкритий метод може перевіряти вхідні параметри, а допоміжним методам-цеглинам це вже не потрібно, оскільки вони викликаються лише зсередини. Якби ці методи були відкритими, в них потрібно було б реалізовувати перевірку параметрів, і при їх імплементації не можна було б розраховувати на те, що вони будуть викликані в контрольований вами момент.
Крім того, внутрішні методи мають право псувати стан класу, якщо ви знаєте, що код який їх викликає потім цю проблему виправить. Якщо зробити ці методи відкритими, користувачі цього класу зможуть зіпсувати внутрішній стан класу без виправлення.
Потім, внутрішні методи можуть не мати нічого спільного з тим, що повинен надавати клас, з його зовнішнім інтерфейсом. Наприклад, якщо клас представляє машину, то відкритий метод в ньому, що переводить дюйми в сантиметри, виглядав би безглуздо. А ось всередині такий переклад цілком може знадобитися.
Ну і в кінці-кінців, публічний метод - це обіцянка для користувачів. Кожна зміна (видалення, зміна сигнатури, а іноді і додавання) відкритого методу - breaking change для клієнтів, вони повинні переглянути код, який використовує ваш клас. Таким чином, ви не повинні просто так, без особливої на то потреби міняти відкриті методи класу. А ось зміни в закритих методах зазвичай відбуваються при рефакторінгу в масовому порядку: методи спрощуються, об'єднуються, розкладаються на декілька, переносяться вгору-вниз по ієрархії, змінюється їх семантика, і все це ніяк не відбивається на користувачах вашого класу.
У документації по Obj-C використовуються терміни class object і class instance. Якщо їх дослівно перекласти, то вийде якраз те, про що Вас запитували. Причому в українській мові природньо об'єкт класу прийнято вважати його экземпляром. У той час, як очевидно, що означає англійський термін class object - цей об'єкт, в якому зберігається, так би мовити, інформація про клас.
Class Objects
A class definition contains various kinds of information, much of it about instances of the class:
The name of the class and its superclass
A template describing a set of instance variables
The declarations of method names and their return and argument types
The method implementations
This information is compiled and recorded in data structures made available to the runtime system . The compiler creates just one object, a class object , to represent the class. The class object has access to all the information about the class , which means mainly information about what instances of the class are like . It's able to produce new instances according to the plan put forward in the class definition .
Although a class object keeps the prototype of a class instance , it's not an instance itself . It has no instance variables of its own and it can not perform methods intended for instances of the class . However, a class definition can include methods intended specifically for the class object -class methods as opposed to instance methods. A class object inherits class methods from the classes above it in the hierarchy , just as instances inherit instance methods.
Основна ідея - поліпшення переносимості. Не гарантується, що на різних системах виконуваний файл буде лежати по шляху, який вказаний в shebang.
Використання env дозволяє знизити цей ризик за рахунок запуску команди на основі даних зі змінної середовища PATH
Більш того, якщо з яких-небудь причин замість стандартного файлу користувач хоче використовувати свій, то йому достатньо додати шлях до цього файлу в PATH без необхідності виправлення скриптів:
В наведеному вище прикладі я скопіював bash до себе в домашню директорію (перейменувавши при цьому файл в python), додав шлях в PATH і запустив python за допомогою env, яка запустила bash, тому що знайшла його раніше.
Ще одним прикладом є використання віртуальних оточень при розробці на Python (virtualenv). Оскільки вони також перебивають PATH, env дозволяє використовувати потрібну версію виконуваного файлу:
~ $ workon black-box-challenge-2016-py2
~ (venv:black-box-challenge-2016-py2) $ env python
Python 2.7.11 (default, Mar 31 2016, 06:18:34)
[GCC 5.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print sys.executable
/home/soon/.virtualenvs/black-box-challenge-2016-py2/bin/python
>>>
Різниця між PUT і POST - це питання семантики. Оскільки для операцій використовуються різні дієслова, то і сенс у них повинен бути різним.
Уявіть, що ваш сервіс оперує поняттями блокнот (notebook) і запис (post). Один блокнот може містити безліч записів.
Для додавання нового запису в блокнот c ідентифікатором id ви будете використовувати метод POST з URL mydomain/notebooks/id/. Ваш сервіс, орієнтуючись на метод POST, сам присвоїть потрібний ідентифікатор запису, додасть її в блокнот і поверне вам URL створеного запису (для доступу до запису по GET або для видалення по DELETE). При цьому добре б повернути клієнту URL створеної записи.
Припустимо, запис з ідентифікатором post-id вже створено і він доступний по URL mydomain/notebooks/id/posts/post-id. Але клієнт (власник запису) виправив в ній помилку і хоче перезаписати її. Для цього він використовує метод PUT з URL mydomain/notebooks/id/posts/post-id і передає оновлений запис в тілі запиту. Ваш сервіс, орієнтуючись на метод PUT видаляє старий запис і записує новий, при цьому він доступний за тим же URL.
Звичайно, ніхто не заважає вам завжди використовувати метод POST (наприклад HTML 4 дозволяв використовувати тільки методи GET і POST). Але все ж варто дотримуватися рекомендацій з метою однакового трактування методів усіма розробниками.
Рекомендується використовуватися метод POST для створення підлеглого ресурсу (дочірнього по відношенню до іншого ресурсу; приклад блокнота і записи якраз дуже підходить).
Отже, якщо ви хочете порівняти рядки на рівність, слід використовувати equals.
Однак в деяких випадках рядки гарантовано представлені одним і тим же об'єктом завдяки пулу рядків (string interning). Ці випадки явно описані в специфікації мови Java .
Оператор == використовується для перевірки, що два рядки вказують на один і той же об'єкт.
// Ці рядки мають одне і те саме значення
new String("test").equals("test") // --> true
// ...але це різні об'єкти
new String("test") == "test" // --> false
// ...ці рядки також різні об'єкти
new String("test") == new String("test") // --> false
// ...але ці рядки вказують а один і той самий об'єкт
// дому що компілятор додає всі літерали в пул
"test" == "test" // --> true
// Об'єднання літералів токож відбувається на стадії компіляції
// тому вони вказують на один об'єкт
"test" == "te" + "st" // --> true
// але виклик substring() відбувається під час виконання,
// в результаті виходять різні об'єкти
"test" == "!test".substring(1) // --> false
// Рядки з пулу можуть буди отримані за допомогою виклику intern().
"test" == "!test".substring(1).intern() // --> true
Треба відзначити, що == помітно швидше, ніж equals (порівняння посилання замість виклику методу і посимвольного порівняння, якщо рядки різної довжини), тому, якщо ви працюєте з рядками з пулу (або системного, або свого), заміна equals на == може привести до помітного прискорення. Але це трапляється дуже рідко.
Остерігайтеся виклику equals на null! Оператор == прекрасно порівнює рядки, якщо один або більше з них дорівнює null, але виклик методу equals на рядок, що дорівнює null, призведе до виключення.
Для порівняння рядків, які можуть бути рівні null, ви можете скористатися наступним методом:
Він присутній в деяких сторонніх бібліотеках, наприклад, в Apache Commons.
Якщо ви користуєтеся сучасними середовищами розробки, то вони попередять, якщо ви спробуєте порівняти рядки за допомогою оператора ==. Завжди звертайте увагу на подібні попередження.
Це можна зробити так:
або так
або так
або так
або так
або так (поки що найкоротший запис)
Присвоювання деструктуризації - це спеціальний синтаксис, який дозволяє нам «розпакувати» масиви або об'єкти в купу змінних, так як іноді вони зручніші. Деструктуризація також прекрасно працює зі складними функціями, які мають багато параметрів, значень за замовчуванням і так далі.
Для вибору необхідної версії скористайтеся командою
І далі з запропонованого списку виберіть ту яка вам необхідна
Для цього вам необхідно додати PPA репозиторій
ppa:ondrej/php
Після чого ви зможете встановити останню версію php командою
Це можна зробити наступним чином
Розглянемо варіанти детальніше
Варіант 1. Зберігати одну загальну сіль для всіх паролів користувачів поза БД
На перший це виглядає безпечніше, адже якщо хтось отримає доступ до БД, то солі у ньому не буде, і напевно відновити паролі не зможе? ..
Але якщо зловмисник отримає доступ і до БД, і до солі зі змінної середовища, то для добування паролів все одно треба буде будувати райдужну таблицю. І якщо у вас одна сіль на всіх користувачів, то це зробити набагато простіше. Інша проблема з безпекою: якщо зловмисник (або його співучасник/жертва) має доступ до системи як користувач, то він вже знає 1 пароль і його хеш, можливо зможе змінювати пароль і дивитися зміну хеша, знаходити в БД інших користувачів з таким же паролем...
Цей варіант схожий на принцип Security through obscurity (безпека через неясність/заплутування), а цього принципу радять уникати і покладатися на сильніші криптографічні методи.
Варіант 2. Зберігати свою для кожного користувача сіль в БД з хешамі паролів
В цьому випадку, якщо зловмисник отримає доступ до БД, то разом з хешами паролів він отримає і солі до них. Але тепер для отримання паролів треба буде згенерувати не одну райдужну таблицю на всіх, а для кожного користувача свою! При цьому, важливо коректно реалізувати свою систему роботи з користувачами: при зміні пароля треба міняти і сіль, щоб навіть маючи стару версію БД, зловмисник вже не зміг отримати з цього вигоду.
Цей же спосіб використовується в Django, також його радять і обгрунтовують в аналогічному питанні на enSO - раджу почитати, там обговорені різні варіанти і їх обгрунтування.
Питання насправді спірне і залежить від реалізації вашої системи. Якщо у вас лише 1 або кілька серверів з повним або слабо захищеним доступом один до одного, то швидше за все зловмисник отримавши доступ до БД, легко отримає доступ і до ОС зі змінними оточення, і навпаки, що нівелює сенс першого варіанту. Якщо ж у вас велика і продумана інфраструктура, доступи до БД і серверів з кодом розмежовані, налаштовані жорсткі групи безпеки, всюди використовуються користувачі з обмеженнями і в БД, і в ОС, то можна отримати вигоду з першого способу. Тому є наступний варіант.
Варіант 3. Змішати обидва варіанти
Можна поєднати краще від двох світів, наприклад так:
Хоча є й інші варіанти, деталі можна знайти все в тому ж питанні . Але знову ж таки, користі в цьому не сильно більше, ніж у другому варіанті, особливо якщо ваша серверна інфраструктура слабо захищена.
Методи
map
,forEach
, іreduce
дійсно мають багато спільного, що і коли використовувати залежить від того який саме результат за підсумком потрібно отримати.Уявімо що у нас є масив:
Якщо нам потрібно просто виконати певну дію для кожного елемента масиву, то тут підійде метод
forEach
:Або так, якщо нам потрібно лише певне значення
Або так, по кількості значень в масиві
Якщо ми хочемо трансформувати наш масив і занести результати в змінну, то тут метод
map
буде доречніше ніжforEach
, оскільки перший за підсумком відразу поверне новий масив.Подивимося на різницю
forEach
vsmap
в разі коли нам потрібно "обернути" кожну власну назву країни в HTML тег:З використанням
map
Метод
reduce
відрізняється відmap
тим що він повертає фінальне "значення" .Припустимо ми хочемо порахувати сумарний розмір населення:
Це досить простий приклад, але "фінальним значенням" може бути не тільки число, а, наприклад, об'єкт або масив, що робить метод
reduce
дійсно потужним інструментом трансформацій.При написанні досить великого шматка коду (неважливо, класу, функції або чого-небудь ще) важливим прийомом є декомпозиція. Ви ділите функціональність на логічні частини, і в головній функції складаєте з них, як з цеглинок, загальну логіку.
При цьому самі цеглинки можуть бути не пристосовані для доступу зовні. Наприклад, відкритий метод може перевіряти вхідні параметри, а допоміжним методам-цеглинам це вже не потрібно, оскільки вони викликаються лише зсередини. Якби ці методи були відкритими, в них потрібно було б реалізовувати перевірку параметрів, і при їх імплементації не можна було б розраховувати на те, що вони будуть викликані в контрольований вами момент.
Крім того, внутрішні методи мають право псувати стан класу, якщо ви знаєте, що код який їх викликає потім цю проблему виправить. Якщо зробити ці методи відкритими, користувачі цього класу зможуть зіпсувати внутрішній стан класу без виправлення.
Потім, внутрішні методи можуть не мати нічого спільного з тим, що повинен надавати клас, з його зовнішнім інтерфейсом. Наприклад, якщо клас представляє машину, то відкритий метод в ньому, що переводить дюйми в сантиметри, виглядав би безглуздо. А ось всередині такий переклад цілком може знадобитися.
Ну і в кінці-кінців, публічний метод - це обіцянка для користувачів. Кожна зміна (видалення, зміна сигнатури, а іноді і додавання) відкритого методу - breaking change для клієнтів, вони повинні переглянути код, який використовує ваш клас. Таким чином, ви не повинні просто так, без особливої на то потреби міняти відкриті методи класу. А ось зміни в закритих методах зазвичай відбуваються при рефакторінгу в масовому порядку: методи спрощуються, об'єднуються, розкладаються на декілька, переносяться вгору-вниз по ієрархії, змінюється їх семантика, і все це ніяк не відбивається на користувачах вашого класу.
У документації по Obj-C використовуються терміни
class object
іclass instance
. Якщо їх дослівно перекласти, то вийде якраз те, про що Вас запитували. Причому в українській мові природньо об'єкт класу прийнято вважати його экземпляром. У той час, як очевидно, що означає англійський термінclass object
- цей об'єкт, в якому зберігається, так би мовити, інформація про клас.Основна ідея - поліпшення переносимості. Не гарантується, що на різних системах виконуваний файл буде лежати по шляху, який вказаний в shebang.
Використання
env
дозволяє знизити цей ризик за рахунок запуску команди на основі даних зі змінної середовищаPATH
Більш того, якщо з яких-небудь причин замість стандартного файлу користувач хоче використовувати свій, то йому достатньо додати шлях до цього файлу в
PATH
без необхідності виправлення скриптів:В наведеному вище прикладі я скопіював
bash
до себе в домашню директорію (перейменувавши при цьому файл вpython
), додав шлях вPATH
і запустивpython
за допомогоюenv
, яка запустилаbash
, тому що знайшла його раніше.Ще одним прикладом є використання віртуальних оточень при розробці на Python (virtualenv). Оскільки вони також перебивають
PATH
,env
дозволяє використовувати потрібну версію виконуваного файлу:Різниця між PUT і POST - це питання семантики. Оскільки для операцій використовуються різні дієслова, то і сенс у них повинен бути різним.
Уявіть, що ваш сервіс оперує поняттями блокнот (notebook) і запис (post). Один блокнот може містити безліч записів.
Для додавання нового запису в блокнот c ідентифікатором id ви будете використовувати метод POST з URL mydomain/notebooks/id/. Ваш сервіс, орієнтуючись на метод POST, сам присвоїть потрібний ідентифікатор запису, додасть її в блокнот і поверне вам URL створеного запису (для доступу до запису по GET або для видалення по DELETE). При цьому добре б повернути клієнту URL створеної записи.
Припустимо, запис з ідентифікатором post-id вже створено і він доступний по URL mydomain/notebooks/id/posts/post-id. Але клієнт (власник запису) виправив в ній помилку і хоче перезаписати її. Для цього він використовує метод PUT з URL mydomain/notebooks/id/posts/post-id і передає оновлений запис в тілі запиту. Ваш сервіс, орієнтуючись на метод PUT видаляє старий запис і записує новий, при цьому він доступний за тим же URL.
Звичайно, ніхто не заважає вам завжди використовувати метод POST (наприклад HTML 4 дозволяв використовувати тільки методи GET і POST). Але все ж варто дотримуватися рекомендацій з метою однакового трактування методів усіма розробниками.
Рекомендується використовуватися метод POST для створення підлеглого ресурсу (дочірнього по відношенню до іншого ресурсу; приклад блокнота і записи якраз дуже підходить).
Оператор
==
порівнює посилання.Метод
equals
порівнює значення.Отже, якщо ви хочете порівняти рядки на рівність, слід використовувати
equals
.Однак в деяких випадках рядки гарантовано представлені одним і тим же об'єктом завдяки пулу рядків (string interning). Ці випадки явно описані в специфікації мови Java .
Оператор
==
використовується для перевірки, що два рядки вказують на один і той же об'єкт.Треба відзначити, що
==
помітно швидше, ніжequals
(порівняння посилання замість виклику методу і посимвольного порівняння, якщо рядки різної довжини), тому, якщо ви працюєте з рядками з пулу (або системного, або свого), замінаequals
на==
може привести до помітного прискорення. Але це трапляється дуже рідко.Остерігайтеся виклику
equals
наnull
! Оператор==
прекрасно порівнює рядки, якщо один або більше з них дорівнюєnull
, але виклик методуequals
на рядок, що дорівнюєnull
, призведе до виключення.Для порівняння рядків, які можуть бути рівні null, ви можете скористатися наступним методом:
Він присутній в деяких сторонніх бібліотеках, наприклад, в Apache Commons.
Якщо ви користуєтеся сучасними середовищами розробки, то вони попередять, якщо ви спробуєте порівняти рядки за допомогою оператора
==
. Завжди звертайте увагу на подібні попередження.Підписуйтесь на щотижневу розсилку
Отримуйте найкращі статті тижня на поштуПідписуйтесь на щотижневу розсилку