Русский
Русский
English
Статистика
Реклама

Технология

Фичи JavaScript. Часть 1

19.06.2020 08:12:45 | Автор: admin


Доброго времени суток, друзья!

В этой статье я хочу поделиться с Вами некоторыми находками, сделанными мной в процессе изучения JavaScript. Возможно, Вы найдете для себя что-то интересное. Данная часть серии будет посвящена, преимущественно, работе с DOM.

Настоятельно рекомендую применить к body следующие стили:

body {    margin: 0;    min-height: 100vh;    overflow: hidden;}

Если планируете тестировать примеры, используйте эту функцию для очистки документа для того, чтобы каждый раз не создавать новый:

const clear = () => document.body.innerHTML = ''clear()

1. Активный элемент


Свойство activeElement позволяет получить элемент, находящийся в фокусе.

const input = document.createElement('input')input.setAttribute('type', 'text')input.setAttribute('placeholder', 'Введите свое имя')input.className = 'username'document.body.append(input)input.focus()console.log(document.activeElement)// <input type="text" placeholder="Введите свое имя" class="username">

2. Редактирование страницы


Свойство designMode позволяет редактировать страницу, открытую в браузере.

document.designMode = 'on'



3. Стили элемента


Метод getComputedStyle() позволяет получить стили элемента. Для получения определенного свойства следует использовать getPropertyValue().

// напишем вспомогательную функцию для получения определенного свойства элемента// мы будем использовать ее в нескольких примерахconst getStyle = (element, property) => getComputedStyle(element).getPropertyValue(property)// возьмем инпут из первого примера// и определим его ширину и высотуconst inputWidth = getStyle(input, 'width')const inputHeight = getStyle(input, 'height')console.log(`Ширина: ${inputWidth}\nВысота: ${inputHeight}`)// Ширина: 156.8px// Высота: 16px// позиционируем элемент, используя полученные данные// предположим, что мы собираемся анимировать элемент// поэтому не хотим использовать transform: translate(-50%, -50%)// допустим также, что мы не знаем размеров элемента// поэтому не можем использовать calc(50% - ширина/высота элемента)input.setAttribute('style',    `position: absolute; top: calc(50% - ${inputHeight.replace('px', '') / 2}px); left: calc(50% - ${inputWidth.replace('px', '') / 2}px);`)

4. Определение браузера


Объект Navidator, в числе прочего, позволяет получить информацию о браузере пользователя.

let browserconst agent = navigator.userAgentif (agent.indexOf('Google')) {    browser = 'Google Chrome'} else if (agent.indexOf('Safari')) {    browser = 'Apple Safari'} else if (agent.indexOf('Opera')) {    browser = 'Opera'} else if (agent.indexOf('Firefox')) {    browser = 'Mozilla Firefox'} else if (agent.indexOf('MSIE')) {    browser = 'Microsoft Interner Explorer'}console.log(browser) // Google Chrome// вероятно, в данном случае надо было использовать switchif (browser === 'Google Chrome' || browser === 'Mozilla Firefox') {    console.log('ok') // ok} else if (browser === 'Opera' || browser === 'Apple Safari') {    console.log('50/50')} else if (browser === 'Microsoft Interner Explorer') {    console.log('!ok')}

5. Получение координат


Объект Navigator также позволяет получить информацию о местонахождении пользователя, т.е. его координаты.

const success = position => {    // деструктурируем объект    const {        latitude,        longitude,        altitude,        speed    } = position.coords    console.log(`${latitude.toFixed(2)}\n${longitude.toFixed(2)}\n${altitude}\n${speed}`)    // об этом ниже    getCityAndWeather(latitude, longitude)}navigator.geolocation.getCurrentPosition(success)/*    56.90    60.63    null    null*/// вот как мы можем использовать полученные данные// определим город пользователя и погодуconst getCityAndWeather = (latitude, longitude) => {    // прокси для преодоления CORS    const proxy = 'https://cors-anywhere.herokuapp.com/'    // данный сервис был куплен Facebook и станет платным в 2021 году    const api = `${proxy}https://api.darksky.net/forecast/fd9d9c6418c23d94745b836767721ad1/${latitude}, ${longitude}`    fetch(api)        .then(response => response.json())        .then(data => {            console.log(data) // много всего            // получаем город            const city = data.timezone            // получаем температуру            const { temperature, summary } = data.currently            // переводим фаренгейт в цельсий            const celsius = Math.floor((temperature - 32) * (5 / 9)).toFixed()            // выводим результат            console.log(                `${city}\n${celsius}C\n${summary}`            )            /*                Asia/Yekaterinburg                15C                Overcast            */        })}

6. Получение элементов


Как нам получить все элементы DOM? Использовать рекурсию.

const template = `<div>    <p> Lorem ispum        <span>dolor sit amet</span>    </p></div><a href="#">link</a>`document.body.innerHTML = templateconst getElements = element => {    for (const i of element.children) {        console.log(i.tagName)        // 0 -> ! -> false -> ! -> true        if (!!i.children.length) {            console.log('дочерний элемент')            getElements(i)        }    }}getElements(document.body)/*    DIV    дочерний элемент    P      дочерний элемент    SPAN    A*/

7. Разбор URL


Как нам получить отдельные части URL? Это можно сделать двумя способами.

// с помощью регуляркиconst regex = /(\w+):\/\/([\w.]+)\/(\S*)/const url = 'https://example.com/index.html'const result = url.match(regex)// полный адрес (абсолютный путь), протокол, хост, страницаconsole.log(result[0], result[1], result[2], result[3])// https://example.com/index.html https example.com index.html// с помощью конструктора URLconst url2 = new URL('https://example.com/search?query=fetch&page=2#awesome-page')console.log(url2) // много всегоconst {    origin,    protocol,    host,    pathname} = url2console.log(    `${origin} ${protocol} ${host} ${pathname}`)// https://example.com https: example.com /search// рекомендую почитать про свойство searchParams// searchParams.get(), searchParams.append(), searchParams.has(), searchParams.delete() и т.д.

8. Позиционирование одного элемента относительно другого


const toCenter = (element, parent) => {    element.style.position = 'relative'    element.style.left = (parent.clientWidth - element.offsetWidth) / 2 + 'px'    element.style.top = (parent.clientHeight - element.offsetHeight) / 2 + 'px'}const div = document.createElement('div')div.setAttribute('style', 'width: 150px; height: 150px; background: red;')document.body.append(div)const div2 = document.createElement('div')div2.setAttribute('style', 'width: 100px; height: 100px; background: green;')div.append(div2)const div3 = document.createElement('div')div3.setAttribute('style', 'width: 50px; height: 50px; background: blue;')div2.append(div3)toCenter(div, document.body)toCenter(div2, div)toCenter(div3, div2)


9. Ширина и высота документа


Как нам получить полную ширину и высоту документа?

const pageWidth = Math.max(    document.body.scrollWidth, document.documentElement.scrollWidth,    document.body.offsetWidth, document.documentElement.offsetWidth,    document.body.clientWidth, document.documentElement.clientWidth)const pageHeight = Math.max(    document.body.scrollHeight, document.documentElement.scrollHeight,    document.body.offsetHeight, document.documentElement.offsetHeight,    document.body.clientHeight, document.documentElement.clientHeight)// один из вариантов использования// определяем центр страницыconst pageCenter = [pageWidth / 2, pageHeight / 2]console.log(pageCenter)// создаем элемент для позиционированияconst p = document.createElement('p')p.textContent = 'Lorem ipsum dolor sit amet'document.body.append(p)p.style.position = 'absolute'// получаем ширину и высоту элемента, используя getStyleconst elementWidth = getStyle(p, 'width').replace('px', '')const elementHeight = getStyle(p, 'height').replace('px', '')// определяем центр элементаconst elementCenter = [elementWidth / 2, elementHeight / 2]console.log(elementCenter)// позиционируем элементp.style.top = pageCenter[1] - elementCenter[1] + 'px'p.style.left = pageCenter[0] - elementCenter[0] + 'px'

10. Координаты элемента в контексте документа


Метод getBoundingClientRect() возвращает размер элемента и его позицию относительно области просмотра.

// возьмем p из предыдущего примераconsole.log(p.getBoundingClientRect()) // много всегоconsole.log(    `Отступ сверху => ${p.getBoundingClientRect().top.toFixed()}\nОтступ слева => ${p.getBoundingClientRect().left.toFixed()}`)/*    Отступ сверху => 352    Отступ слева => 288*/// создадим два элемента// и определим, в какой части страницы находится каждый из нихconst div = document.createElement('div')div.setAttribute('style', 'width: 100px; height: 100px; background: #222; position: absolute; top: calc(50% - 50px); left: calc(25% - 50px);')document.body.append(div)const div2 = document.createElement('div')div2.setAttribute('style', 'width: 100px; height: 100px; background: #222; position: absolute; top: calc(50% - 50px); left: calc(75% - 50px);')document.body.append(div2)document.querySelectorAll('div').forEach(div => div.addEventListener('click', event => {    const x = event.target.getBoundingClientRect().x    const width = event.target.getBoundingClientRect().width    // расчеты приблизительные    x + width < innerWidth / 2    ? console.log('Элемент находится в левой части страницы.')    : console.log('Элемент находится в правой части страницы.')}))div.click() // Элемент находится в левой части страницы.div2.click() // Элемент находится в правой части страницы.// определим расстояние между нимиconst distanceBetweenDivs = (div, div2) =>console.log((div2.getBoundingClientRect().x - div.getBoundingClientRect().x + div.getBoundingClientRect().width).toFixed())distanceBetweenDivs(div, div2) // 477

11. Координаты курсора


Как нам получить координаты курсора? Очень просто.

// document.addEventListener('click', ev => console.log(`X => ${ev.clientX}\nY => ${ev.clientY}`))/*    X => 348    Y => 304*/// вот как мы можем это использовать// создаем холст и получаем его контекстconst canvas = document.createElement('canvas')document.body.append(canvas)const $ = canvas.getContext('2d')// размер холста - область просмотраcanvas.width = innerWidthcanvas.height = innerHeight// создаем вспомогательную функцию для получения случайного целого числа в заданном диапазонеconst randomInt = (min, max) => Math.floor(min + Math.random() * (max + 1 - min))// создаем вспомогательную функцию для получения случайного цветаconst randomColor = () => `#${((Math.random()*0xfff)<<0).toString(16)}`// давайте порисуем// рисование фигур осуществляется по клику// центр фигуры - место клика// форма фигуры - круг или квадратlet i = 0canvas.addEventListener('click', ev => {    $.beginPath()    // если i - четное число, то рисуем круг    // если нечетное - квадрат    if (i % 2 === 0) {        // $.arc(x, y, радиус, угол)        $.arc(ev.clientX, ev.clientY, randomInt(10, 30), 0, 2 * Math.PI)        $.fillStyle = randomColor()        $.fill()    } else {        let randomSize = randomInt(20, 60)        $.fillStyle = randomColor()        // $.fillRect(x, y, ширина, высота)        $.fillRect(ev.clientX - randomSize / 2, ev.clientY - randomSize / 2, randomSize, randomSize)    }    $.closePath()    i++})

Напоследок реализуем функцию рисования определенного количества фигур.

const manyShapes = number => {    // очищаем холст    $.clearRect(0, 0, canvas.width, canvas.height)    for (let i = 0; i < number; i++) {        let randomX = randomInt(0, innerWidth)        let randomY = randomInt(0, innerHeight)        if (i % 2 === 0) {            $.beginPath()            $.arc(randomX, randomY, randomInt(10, 30), 0, 2 * Math.PI)            $.fillStyle = randomColor()            $.fill()        } else {            let randomSize = randomInt(20, 60)            $.beginPath()            $.rect(randomX, randomY, randomSize, randomSize)            $.fillStyle = randomColor()            $.fill()        }    }}manyShapes(100)



Благодарю за потраченное время. Надеюсь, оно было потрачено не зря.

Продолжение следует
Подробнее..

Фичи JavaScript. Часть 2

27.06.2020 10:22:34 | Автор: admin


Доброго времени суток, друзья!

В этой статье я продолжаю делиться с Вами некоторыми находками, сделанными мной в процессе изучения JavaScript. Данная часть посвящена, преимущественно, новым и продвинутым фичам.

См. Фичи JavaScript. Часть 1.

1. Частое обращение к одним и тем же элементам


Порой при написании кода приходится снова и снова обращаться к одним и тем же элементам. При работе с DOM, например, такими элементами являются document и document.body. Казалось бы, что тут такого? 8 и 13 символов, соответственно, да еще и emmet помогает. Однако, когда кода действительно много, автозавершение начинает предлагать неправильные варианты. Либо, когда работаешь не с html, а, например, с php без правильного синтаксического анализатора, многие привычные вещи приходится набирать вручную. Задумавшись о том, как решить указанную проблему, я вспомнил о canvas. Помните, с чего начинается работа с холстом? Правильно, с его определения и инициализации двумерного контекста рисования:

const C = document.querySelector('canvas')const $ = C.getContext('2d')

Также я подумал об объекте jQuery ($).

Так вот, могу предложить три варианта (один из вариантов я подглядел у разработчиков Facebook при изучении протокола Open Graph):

    // внутри функцииfunction foo() {    const D = document    const B = document.body    const div = D.createElement('div')    B.append(div)    const p = D.createElement('p')    p.textContent = 'Lorem ipsum dolor sit amet...'    div.append(p)    console.log(div)    B.removeChild(div)}foo()// снаружи функцииfunction bar(D, B) {    const div = D.createElement('div')    B.append(div)    const p = D.createElement('p')    p.textContent = 'Lorem ipsum dolor sit amet...'    div.append(p)    console.log(div)    B.removeChild(div)}bar(document, document.body)// IIFE;((D, B) => {    const div = D.createElement('div')    B.append(div)    const p = D.createElement('p')    p.textContent = 'Lorem ipsum dolor sit amet...'    div.append(p)    console.log(div)    B.removeChild(div)})(document, document.body)

Это была разминка, переходим к тренировке.

2. Генератор


Генератор это особая функция, которая работает как фабрика итераторов. Объект является итератором, если он умеет обращаться к элементам коллекции по одному за раз, при этом отслеживая свое текущее положение внутри этой последовательности. Генераторы позволяют определить алгоритм перебора элементов коллекции с помощью единственной функции, поддерживающей собственное состояние.

// пример 1function* takeItem(arr) {    for (let i = 0; i < arr.length; i++) {        yield arr[i]    }}const arr = ['foo', 'bar', 'baz', 'qux']const generator = takeItem(arr)const timer = setInterval(() => {        const item = generator.next()        item.done            ? clearInterval(timer)            : console.log(item.value)    }, 1000)// пример 2async function* range(start, end) {    for (let i = start; i <= end; i++) {        yield Promise.resolve(i)    }};(async () => {    const generator = range(1, 4)    for await (const item of generator) {        console.log(item)    }})()

3. Async/await + fetch


Async/await является альтернативой промисов, позволяя обеспечить синхронность выполнения асинхронных функций. В свою очередь, fetch является альтернативой XMLHttpRequest, представляя собой интерфейс для получения ресурсов (в том числе, по сети).

const url = 'https://jsonplaceholder.typicode.com/users';(async () => {    try {        const response = await fetch(url)        const data = await response.json()        console.table(data)    } catch (er) {        console.error(er)    } finally {        console.info('потрачено')    }})()

4. For await


Выражение for await...of создает цикл, проходящий через асинхронные итерируемые объекты, а также синхронные итерируемые сущности. Он вызывает пользовательский итерационный хук с инструкциями, которые должны быть выполнены для значения каждого отдельного свойства объекта.

const delayedPromise = (id, ms) => new Promise(resolve => {    const timer = setTimeout(() => {        resolve(id)        clearTimeout(timer)    }, ms)})const promises = [    delayedPromise(1, 1000),    delayedPromise(2, 2000),    delayedPromise(3, 3000)]// старый стильasync function oldStyle() {    for (const promise of await Promise.all(promises)) {        console.log(promise)    }}oldStyle() // все промисы через 3 секунды// новый стильasync function newStyle() {    for await (const promise of promises) {        console.log(promise)    }}newStyle() // каждый промис в свой черед

5. Proxy


Прокси используются для объявления расширенной семантики JS объектов. Стандартная семантика реализована в движке JS, который обычно написан на низкоуровневом языке программирования, например C++. Прокси позволяют определить поведение объекта при помощи JS. Другими словами, они являются инструментом метапрограммирования.

const person = {    firstname: 'Harry',    lastname: 'Heman',    city: 'Mountain View',    company: 'Google'}const proxy = new Proxy(person, {    get(target, property) {        if (!(property in target)) {            return property                .split('_')                .map(p => target[p])                .sort()                .join(' ')        }        console.log(`получено свойство: ${property}`)        return target[property]    },    set(target, property, value) {        if (property in target) {            target[property] = value            console.log(`изменено свойство: ${property}`)        } else {            console.error('нет такого свойства')        }    },    has(target, property) {        // return property in target        return Object.entries(target)            .flat()            .includes(property)    },    deleteProperty(target, property) {        if (property in target) {            delete target[property]            console.log(`удалено свойство: ${property}`)        } else {            console.error('нет такого свойства')        }    }})console.log(proxy.company_city_firstname_lastname) // Google Harry Heman Mountain Viewproxy.firstname = 'John' // изменено свойство: firstnameproxy.surname = 'Smith' // нет такого свойстваconsole.log(proxy.city) // получено свойство: city Mountain Viewconsole.log('company' in proxy) // truedelete proxy.age // нет такого свойства// proxy + cookieconst getCookieObject = () => {    const cookies = document.cookie.split(';').reduce((cks, ck) => ({        [ck.substr(0, ck.indexOf('=')).trim()]: ck.substr(ck.indexOf('=') + 1),        ...cks    }), {})    const setCookie = (name, value) => document.cookie = `${name}=${value}`    const deleteCookie = name => document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:01 GTM;`    return new Proxy(cookies, {        set: (obj, prop, val) => (setCookie(prop, val), Reflect.set(obj, prop, val)),        deleteProperty: (obj, prop) => (deleteCookie(prop), Reflect.deleteProperty(obj, prop))    })}

6. Reduce


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

const arr = [1, 2, 3]const total = arr.reduce((sum, cur) => sum + cur)console.log(total) // 6// forEachlet total2 = 0arr.forEach(num => total2 += num)console.log(total2) // 6

Однако возможности reduce() этим далеко не исчерпываются:

const devs = [    {        name: 'John',        sex: 'm',        age: 23    },    {        name: 'Jane',        sex: 'f',        age: 24    },    {        name: 'Alice',        sex: 'f',        age: 27    },    {        name: 'Bob',        sex: 'm',        age: 28    }]const men = devs.reduce((newArr, dev) => {    if (dev.sex === 'm') newArr.push(dev.name)    return newArr}, [])console.log(men) // ["John", "Bob"]// filter + mapconst olderThan25 = devs    .filter(dev => dev.age > 25)    .map(dev => dev.name)console.log(olderThan25) // ["Alice", "Bob"]

Сформируем список имен разработчиков одной строкой:

const devsNamesList = `<ul>${devs.reduce((html, dev) => html += `<li>${dev.name}</li>`, '')}</ul>`document.body.innerHTML = devsNamesList// mapconst devsNamesList2 = `<ul>${devs.map(dev => `<li>${dev.name}</li>`).join('')}</ul>`document.body.insertAdjacentHTML('beforeend', devsNamesList2)

Поговорим о группировке:

const groupBy = (arr, criteria) =>    arr.reduce((obj, item) => {        const key = typeof criteria === 'function'            ? criteria(item)            : item[criteria]        if (!obj.hasOwnProperty(key)) obj[key] = ''        obj[key] = item        return obj    }, {})const nums = [6.1, 4.2, 2.3]console.log(groupBy(nums, Math.floor)) // {2: 2.3, 4: 4.2, 6: 6.1}// forEachconst groupBy2 = (arr, criteria, obj = {}) => {    arr.forEach(item => {        const key = typeof criteria === 'function'            ? criteria(item)            : item[criteria]                if (!obj.hasOwnProperty(key)) obj[key] = ''        obj[key] = item        return obj    })    return obj}const words = ['one', 'three', 'five']console.log(groupBy2(words, 'length')) // {3: "one", 4: "five", 5: "three"}

Сделаем выборку:

const cash = {    A: 1000,    B: 2000}const devsWithCash = devs.reduce((arr, dev) => {    const key = dev.name.substr(0,1)        if (cash[key]) {        dev.cash = cash[key]        arr.push(`${dev.name} => ${dev.cash}`)    } else dev.cash = 0    return arr}, [])console.log(devsWithCash) // ["Alice => 1000", "Bob => 2000"]// map + filterconst devsWithCash2 = devs.map(dev => {    const key = dev.name.substr(0,1)    if (cash[key]) {        dev.cash = cash[key]    } else dev.cash = 0    return dev}).filter(dev => dev.cash !== 0)console.log(devsWithCash2)

И последний пример. Помните, как мы формировали список имен разработчиков из массива объектов одной строкой? Но что если у нас имеется такой массив:

const users = [    {        john: {            name: 'John'        }    },    {        jane: {            name: 'Jane'        }    },    {        alice: {            name: 'Alice'        }    },    {        bob: {            name: 'Bob'        }    }]

Как нам сделать тоже самое?

document.body.insertAdjacentHTML('afterbegin', `<ul>${users.reduce((html, el) => html + `<li>${Object.values(el)[0].name}</li>`, '')}</ul>`) // фух!

Давайте рассмотрим что-нибудь попроще.

7. Новые методы работы со строками


// trimStart() trimEnd() trim()const start = '   foo bar'const end = 'baz qux   'console.log(`${start.trimStart()} ${end.trimEnd()}`) // foo bar baz quxconsole.log((`${start} ${end}`).trim()) // тоже самоеconst startMiddleEnd = '   foo  bar   baz  ' // три пробела в начале, два - между foo и bar, три - между bar и baz и два - в конце// при помощи регулярного выражения заменяем два и более пробела одним// затем посредством trim() удаляем пробелы в начале и концеconst stringWithoutRedundantSpaces = startMiddleEnd.replace(/\s{2,}/g, ' ').trim()console.log(stringWithoutRedundantSpaces) // foo bar baz// padStart() padEnd()let str = 'google'str = str.padStart(14, 'https://') // первый аргумент - количество символовconsole.log(str) // https://googlestr = str.padEnd(18, '.com')console.log(str) // https://google.com

8. Новые методы работы с массивами


const arr = ['a', 'b', ['c', 'd'], ['e', ['f', 'g']]]console.log(arr.flat(2)) // ["a", "b", "c", "d", "e", "f", "g"]const arr2 = ['react vue', 'angular', 'deno node']console.log(arr2.map(i => i.split(' ')))/*    [Array(2), Array(1), Array(2)]        0: (2) ["react", "vue"]        1: ["angular"]        2: (2) ["deno", "node"]*/console.log(arr2.flatMap(i => i.split(' '))) // ["react", "vue", "angular", "deno", "node"]

9. Новые методы работы с объектами


const person = {    name: 'John',    age: 30}console.log(Object.getOwnPropertyDescriptor(person, 'name')) // {value: "John", writable: true, enumerable: true, configurable: true}const arr = Object.entries(person)console.log(arr) // [["name", "John"], ["age", 30]]console.log(Object.fromEntries(arr))for (const [key, value] of Object.entries(person)) {    console.log(`${key} => ${value}`) // name => John age => 30}console.log(Object.keys(person)) // ["name", "age"]console.log(Object.values(person)) // ["John", 30]

10. Приватные переменные в классах


class Person {    // значения по умолчанию    static type = 'человек'    static #area = 'Земля'    name = 'John'    #year = 1990    get age() {        return new Date().getFullYear() - this.#year    }    set year(age) {        if (age > 0) {            this.#year = new Date().getFullYear() - age        }    }    get year() {        return this.#year    }    static area() {        return Person.#area    }}const person = new Person()console.log(person) // Person{name: "John", #year: 1990}console.log(person.age) // 30// console.log(person.#year) // errorperson.year = 28console.log(person.year) // 1992console.log(Person.type) // человек// console.log(Person.#area) // errorconsole.log(Person.area()) // Земля

11. Еще парочка нововведений


// промисыconst p1 = Promise.resolve(1)const p2 = Promise.reject('error')const p3 = Promise.resolve(3);(async () => {const result = await Promise.all([p1, p2, p3])console.log(result)})() // Uncaught (in promise) error;(async () => {const result = await Promise.allSettled([p1, p2, p3])console.log(result)})()/*    [{}, {}, {}]        0: {status: "fulfilled", value: 1}        1: {status: "rejected", reason: "error"}        2: {status: "fulfilled", value: 3}*/// приведение к null (nullish coercion)const values = {    undefined: undefined,    null: null,    false: false,    zero: 0,    empty: ''}console.log(values.undefined || 'default undefined')console.log(values.undefined ?? 'default undefined')// default undefinedconsole.log(values.null || 'default null')console.log(values.null ?? 'default null')// default nullconsole.log(values.false || 'default false') // default falseconsole.log(values.false ?? 'default false') // falseconsole.log(values.zero || 'default zero') // default zeroconsole.log(values.zero ?? 'default zero') // 0console.log(values.empty || 'default empty') // default emptyconsole.log(values.empty ?? 'default empty') // ''// опциональная цепочка (optional chaining)const obj1 = {    foo: {        bar: {            baz: {                qux: 'veryDeepInside'            }        }    }}const obj2 = {    foo: {}}// старый стильfunction getValueOld(obj) {    if (obj.foo !== undefined &&    obj.foo.bar !== undefined &&    obj.foo.bar.baz !== undefined &&    obj.foo.bar.baz.qux !== undefined) {        return obj.foo.bar.baz.qux    }}console.log(getValueOld(obj1)) // veryDeepInsideconsole.log(getValueOld(obj2)) // нет ошибки// новый стильconst getValueNew = obj => obj?.foo?.bar?.baz?.quxconsole.log(getValueNew(obj1)) // veryDeepInsideconsole.log(getValueNew(obj2)) // нет ошибки

Благодарю за потраченное время. Надеюсь, оно было потрачено не зря.

Продолжение следует
Подробнее..

Российские учёные создают устройство, которое позволит видеть кожей

18.08.2020 18:15:11 | Автор: admin


В основе проекта лежит технология нейропластичности, позволяющая заменить один способ восприятия другим по замыслу учёных незрячие люди смогут видеть окружающий мир с помощью осязания.

Передача зрительной информации происходит по определённому алгоритму, изучив который, человек может представлять глубину и очертания находящихся перед ним предметов и объектов. На трехмерной карте окружающего пространства каждому объекту присваивается значение удаленности, и чем ближе к незрячему находится предмет, тем больше вибрация в соответствующей области виброматрицы.

Идея сенсорного зрения не нова, при обзоре литературы мы нашли статью 1969 года в журнале Nature, где экспериментально доказали, что изображения, генерируемые на спине человека с помощью матрицы из множества вибраторов, могут распознаваться. В ходе этого эксперимента человек мог прочесть буквы и даже различать силуэты. И эта работа вдохновила меня на идею разработки прибора для незрячих, рассказал Дмитрий Шитц, заведующий лабораторией оптических излучений научно-технологического парка Фабрика Балтийского федерального университета имени И. Канта.

Принцип работы, изобретенного Дмитрием Шитцем прибора, весьма оригинален. 3D-камера считывает окружающее пространство незрячего пациента. Изображение поступают на встроенный в устройство мини компьютер, который мгновенно выстраивает карту удалённости предметов, находящихся в поле зрения.

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

Несмотря на разработки прошлых лет, идея аппарата для незрячих на основе сенсорного зрения является полностью оригинальной. Сотрудниками Балтийского федерального университета имени Канта на неё уже получен соответствующий патент.

На данном этапе мы научились строить 3D-карту удаленности предметов: нами создана специальная программа для обработки изображения со стереокамеры, которая также умеет разбить это изображение на участки-пикселы и присваивать каждому из них значение удалённости, отметил Шитц. По его словам, отдельной и не менее сложной задачей проекта является разработка контроллера и виброматрицы с хорошим разрешением.

Технология сенсорного замещения была разработана в 60-х годах XX века американским нейрофизиологом Полом Бах-у-Рита. Она опирается на свойство нейропластичности мозга, которое позволяет отдельным зонам мозга меняться под действием опыта, а также восстанавливать утраченные связи после повреждения или вырабатывать новые связи. На практике это позволяет научиться заменять один способ восприятия другим.

Схожая технология уже применяется в России. В частности, проект vOISe vision обучает незрячих людей ощущать окружающее пространство с помощью звука. Регулируя громкость и высоту по определённому алгоритму устройство позволяет воспринимать не только глубину пространства и очертания объектов, но и различать полную картину пространства в чёрно-белом виде.

Об этой и других технологиях читайте в нашем блоге на Хабр: Реабилитационная индустрия России.

По материалам Балтийского федерального университета имени Иммануила Канта. Фото: Elia Pellegrini.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru