Золотые три серебряные четыре заметки к предварительным интервью 2021 г.

внешний интерфейс

Золотые три серебряные четыре заметки к предварительным интервью 2021 г.

Это лучшее время, чтобы снова искать работу.С марта по апрель смена работы — это процесс, через который каждый должен пройти в своей карьере.javascriptа такжеvueнекоторые проблемы. Если вы читаете эту статью, если вы чувствуете, что она вам полезна, она не так хороша, как качество трех соединений, кодирование не простое, спасибо за вашу поддержку!

JavaScript

тип данных

Познакомить с типами данных в js и как хранятся значения

  • Всего в JavaScript существует 8 типов данных, среди которых основные типы данных: Null, Undefined, Boolean, String, Number, Bigint, Symbol.

Есть другой тип данныхobject: содержитfunction,Array,DateЖдать.

  • Базовые типы данных хранятся в области стека, занимая мало места и имея фиксированный размер.

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

Оценка типа данных в js

Расскажите о методе оценки типа данных в js

typeof

  • typeof может определять примитивные типы данных, кроме null:
    console.log(typeof 2) //number
    console.log(typeof 'hello') //string
    console.log(typeof null) //object
    console.log(typeof true)//boolean
    console.log(typeof undefined) //undefined
    console.log(typeof []) //object
  • Потому что из-за специального значения null считается ссылкой на пустой объект

instanceof

  • instanceofТип объекта может быть правильно оценен, потому что внутренний механизм заключается в оценке того, можно ли найти тип в цепочке прототипов объекта.prototype:

wWAKt1.png

    console.log([] instanceof Array) //true
    console.log({} instanceof Object)//true
    console.log(function(){} instanceof Function)//true
    console.log(1 instanceof Number)//false

constructor

  • constructorВ основном с использованием прототипаprototype.constructorУказание на конструктор экземпляра для суждения
    console.log((1).constructor === Number) //true
    console.log('1'.constructor===String)//true
    console.log((function(){}).constructor===Function) //true
    console.log([].constructor===Array) //true
    console.log(({}).constructor===Object) //true
  • Но одной из характеристик конструктора является то, что если я создаю объект и модифицирую его прототип, он становится менее надежным:
    function Func(){}

    Func.prototype=new Array();

    const f=new Func()

    console.log(f.constructor===Function)//false

Object.prototype.toString.call

  • Использование метода прототипа объекта ObjecttoString, возвращаемое значение — строка [тип объекта], этот метод может в основном оценивать все типы данных.
    var toString = Object.prototype.toString;
    console.log(toString.call(2)) //[object Number]
    console.log(toString.call(true)) //[object Boolean]
    console.log(toString.call(function(){})) //[object Function]

Объем и цепочка объемов

Расскажите о своем понимании масштаба, цепочки масштабов.

  • Область действия: Область действия – это область, в которой определяются переменные. Она имеет набор правил для доступа к переменным. В соответствии с этим набором правил механизм браузера управляет тем, как механизм браузера выполняет поиск переменных на основе переменных (идентификаторов) в текущей области. и вложенные области.

  • Цепочка областей действия: цепочка областей действия обеспечивает упорядоченный доступ среды выполнения ко всем переменным и функциям.Через цепочку областей действия мы можем получить доступ к переменным и функциям во внешней среде.

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

this

Расскажите о своем понимании этого и этого в различных контекстах.

  • В браузерах это указывает на объект окна в глобальной области видимости.

  • В функции это всегда указывает на объект, вызвавший его последним (за исключением стрелочных функций).

  • В конструкторе это указывает наnewпоявляются новые объекты.

  • Это в вызове, применении и привязке строго привязано к указанному объекту.

  • this стрелочной функции — это this родительской области, а не this вызова.

прототип, цепь прототипов

Расскажите о прототипе и цепочке прототипов в JavaScript, каковы характеристики

  • В js мы можем создать объект через конструктор, каждый конструктор будет иметьprototypeсвойство, значением которого является объект, содержащий свойства и методы, которые могут совместно использоваться всеми экземплярами этого конструктора. Когда мы получаем доступ к свойству объекта, если свойство не существует в объекте, то оно обращается к своему объекту-прототипу, чтобы найти это свойство, а у объекта-прототипа будет свой собственный прототип, поэтому мы продолжаем искать его. это концепция цепочки прототипов. Конец цепочки прототипов обычноObject.prototype.
    function Func(name){
        this.name=name
    };

    let tom=new Func('TOM');

    console.log(tom)


    console.log(tom.__proto__===Func.prototype) //true
    console.log(tom.__proto__.constructor==Func) //true

  • Еще картинка для лучшего понимания

w2zC4g.png

  • Роль объекта-прототипа:
    function Func(name){
        this.name=name;
        this.say=function(){
            console.log(this.name)
        }
    }

    let m=new Func('tom');
    let n=new Func('tom')

    console.log(m)
    console.log(n)

    console.log(m.say===n.say) //false 
  • каждый разnew, откроет новую область, что, очевидно, не очень хорошо, поэтому мы можем поместить общие методы в объект-прототип, чтобы избежать потери памяти:
    function Func(name){
        this.name=name;
    }
    Func.prototype.say=function(){
        console.log(this.name)
    }
    let m=new Func('tom');
    let n=new Func('tom')

    console.log(m)
    console.log(n)

    console.log(m.say===n.say) //true

Закрытие

Поговорите о понимании замыканий и сценариев использования

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

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

  • Другое использование — сохранить переменный объект в контексте функции, которая завершила работу в памяти, потому что функция закрытия сохраняет ссылку на переменный объект, поэтому переменный объект не будет повторно использован.

    function func(){
        let n=0;
        function add(){
            n++;
            console.log(n)
        }
        return add
    }

    let a=func();
    a() //1
    a()//2

модель событий

Что такое событие? Какие бывают события?

  • События относятся к взаимодействиям, которые происходят, когда пользователь управляет страницей или некоторыми операциями самой веб-страницы.В браузере есть три модели событий:

  • Модель уровня DOM0: эта модель не распространяется и не имеет концепции потока событий, но некоторые браузеры теперь поддерживают ее в виде пузырьков. Она может напрямую определять функцию прослушивателя на веб-странице или указывать функцию прослушивателя через атрибут js.

  • Модель событий IE: В этой модели событий есть два процесса для события,этап обработки событийа такжефаза всплытия события, фаза обработки события сначала выполнит событие слушателя, привязанное к целевому элементу. Затем следует фаза всплытия события, где всплытие относится к событию от всплытия кdocument, проверьте, привязан ли передающий узел к функции прослушивателя событий, и она будет выполняться по порядку.

  • Модель событий уровня DOM2: В этой модели события есть три процесса для события, первый процессэтап захвата событий, захват относится к событиям изdocumentРаспространитесь до целевого элемента, проверьте, привязан ли переданный узел к функции прослушивателя событий, и выполните его, если есть. Последние два этапа в основном такие же, как модель событий IE. В такой событийной модели функция привязки событийaddEventListener, где третий параметр может указывать, выполняется ли событие на этапе захвата.

    //DMO0
     element.onclick=function(){}

    //DOM2
    element.addEventListener('click',function(){},false)

    //DOM3 增加了鼠标事件,键盘事件
    element.addEventListener('keyup',function(){},false)

  • Процесс захвата событий DOM: окно--->документ--->html--->тело--->постепенно передается

  • Процесс всплытия событий DOM: целевой элемент ---> родительский элемент ---> тело ---> html ---> документ ---> окно

Общие применения объектов событий

  • event.preventDefault() // Предотвратить поведение по умолчанию, чем предотвратить нажатие на метку для перехода

  • event.stopPropagation() // Остановить всплытие событий

  • event.stoplmmediatePropagation() //Зарегистрируйте два события одновременно, чтобы определить приоритет события

  • event.currentTarget() //Прокси события, делегируем событие дочернего элемента родительскому элементу

  • event.target() // Текущий выбранный элемент

Асинхронное программирование

Давайте поговорим о решении для асинхронного программирования в js, что оно решает?

  • Когда мы писали код раньше, могут быть функции вложенности функций.Если есть несколько вложенных функций, структура будет очень беспорядочной и сложной в обслуживании, поэтому у нас есть концепция асинхронного программирования.

Promise

  • Promise— это решение для асинхронного программирования, более разумное и мощное, чем традиционные решения — функции обратного вызова и события. Впервые он был предложен и реализован сообществом, ES6 вписал его в стандарт языка, унифицированное использование и изначально предоставил объекты Promise.

  • Так называемый Promise — это просто контейнер, содержащий результат события (обычно асинхронной операции), которое завершится в будущем. Синтаксически Promise — это объект, из которого можно получить сообщение для асинхронной операции. Обещания предоставляют унифицированный API, и различные асинхронные операции могут обрабатываться одинаково.

  • На состояние объекта Promise не влияет внешний мир, он имеет три состояния,pending(в ходе выполнения),fulfilled(удалось),rejected(не удалось). Только результат асинхронной операции может определить текущее состояние, и никакая другая операция не может изменить это состояние. Это также происхождение названия Promise, что в переводе с английского означает «обещание», что означает, что другие средства не могут быть изменены. Его статус может быть изменен сpendingсталиfulfilled, или изpendingсталиrejected.

затем метод
  • Промисы могут только упростить способ написания обратных вызовов слой за слоем, но по сути, суть промиса — это «состояние». гибче, чем передача функции обратного вызова.
    const testPormise=new Promise((resovle,reject)=>{
       console.log("hi,Pormise");
       let test=true;
       if(test){
            resovle('成功~')
       }else{
           reject("失败了")
       }
    });
    testPormise.then((res)=>{
        console.log(res)
    }).catch((erro)=>{
        console.log(erro)
    })

rejected

  • только выполненоrejectedЭто можно зафиксировать в then, а затем выполнить обратный вызов в случае неудачи:
 let p = new Promise((resolve, reject) => {
        //做一些异步操作
      setTimeout(function(){
            var num = Math.ceil(Math.random()*10); //生成1-10的随机数
            if(num<=3){
                resolve(num);
            }
            else{
                reject('数字太大了');
            }
      }, 2000);
    });
    p.then((data) => {
            console.log('resolved',data);
        },(err) => {
            console.log('rejected',err);
        }
    ); 

catch

  • catch используется так же, как и тогда, и используется для указанияrejectобратный вызов:
    p.then((data) => {
        console.log('resolved',data);
    }).catch((err) => {
        console.log('rejected',err);
    });

all

  • all получает параметр массива, и значение в нем в конечном итоге вернется к объекту Promise.Тот, кто выполнит медленнее, выполнит обратный вызов:
    let Promise1 = new Promise(function(resolve, reject){})
    let Promise2 = new Promise(function(resolve, reject){})
    let Promise3 = new Promise(function(resolve, reject){})

    let p = Promise.all([Promise1, Promise2, Promise3])

    p.then(funciton(){
    // 三个都成功则成功  
    }, function(){
    // 只要有失败,则失败 
    })

race

  • Тот, кто работает быстрее, выполнит обратный вызов.Общий сценарий приложения — установить время ожидания запроса и выполнить соответствующий обратный вызов после истечения времени ожидания запроса.

Event Loop

Подскажите, каков механизм выполнения событий в js?

  • "JavaScript — это однопоточный, асинхронный, неблокирующий, интерпретируемый язык сценариев."Основной особенностью языка JavaScript является однопоточность, то есть одновременно может выполняться только одно действие. Чтобы координировать события, взаимодействие с пользователем, сценарии, рендеринг пользовательского интерфейса, сетевую обработку и другие виды поведения, Чтобы предотвратить блокировку основного потока, было рождено решение Event Loop.

  • В js задача попадает в стек выполнения, сначала определите тип задачи, а если это синхронная задача, то она напрямую входит в основной поток для выполнения. Если это асинхронная задача, задача будет помещена в асинхронную очередь.После выполнения синхронной задачи поток триггера события извлечет функцию, которая была только что добавлена ​​в очередь, из очереди сообщений.Если есть, она будут выполняться один за другим.

    console.log(1)

    setTimeout(() => {
        console.log(2)
    }, 1000);
    
    console.log(3)

    //1 3 2

микрозадачи

  • В js setTimeout — это задача макроса, напримерPromiseдля микрозадач,
    console.log(1)

    setTimeout(() => {
        console.log(2)
    }, 1000);

    let test=new Pormise((resolve)=>{
        console.log(3);
        resolve();
    })
    .then(=>console.log(4))


    console.log(5)
    1.3 5 4.2
  • Сначала он выведет 1, затем встретитsetTimeout, тогда задача регистрации встречаетPormise, сначала выведите 3, затем зарегистрируйте задачу, а затем выведите 5. В это время в стеке выполнения нет исполняемого файла, а затем он будет взят из очереди.В это время микрозадача будет вынесена на выполнение , введите затем и выведите 4. В это время Стек выполнения снова пуст.В это время задача продолжает браться из очереди, и в это время выводится 2.

наследовать

Как реализовать наследование? Как получить идеальное наследство?

  • Наследование конструктора с помощью конструктораcall applyИзменения указывают на наследование реализации, но у этого способа наследования есть и обратная сторона:Не может наследовать свойства объекта-прототипа родительского класса, но может наследовать свойства только в конструкторе.
    function Parent1(){
        this.name='Parent1'
    };

    Parent1.prototype.say=function(){
        console.log(this.name)
    }

    function Child1(){
        Parent1.call(this);//apply
        this.type='Child1'
    }

    let n=new Child1();
    console.log(n.say)//undefined
  • Цепочка прототипов реализует наследование, недостатки:Экземпляры являются общими.
   function Parent(){
        this.name='Parent1';
        this.arr=[1,2,3,4,5]
    };

    Parent.prototype.say=function(){
        console.log(this.name)
    }

    function Child(){
        this.type='Child1'
    }

    Child.prototype=new Parent();

    var s1=new Child();
    var s2=new Child();
    s1.arr.push(6)
    console.log(s1.arr) //[1,2,3,4,5,6]
    console.log(s2.arr) //[1,2,3,4,5,6]
    //他们俩是公用的
    console.log(s1.__proto__===s2.__proto__) //true
  • Комбинированное наследование (обучение преимуществам двух вышеперечисленных)
    function Parent(){
        this.name='tom';
    };

    Parent.prototype.say=function(){
        console.log(this.name)
    };

    function Child(){
        Parent.call(this)
        this.age=18;
    };

    Child.prototype=Object.create(Parent.prototype);

    Child.prototype.constructor=Child;

Vue

жизненный цикл

Сколько жизненных циклов у Vue? Какой жизненный цикл может получить настоящий DOM? Изменение данных в данных, какой жизненный цикл будет запущен? Почему данные компонента являются функцией?

  • Проще говоря, жизненный цикл Vue можно разделить на три категории: этап создания, этап выполнения и этап уничтожения.

создать сцену

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

  • created: Экземпляр создан в памяти, а также созданы данные и методы.

  • beforeMount: На данный момент шаблон скомпилирован, но не отображен на странице.

  • mounted: рендеринг шаблона, на этом этап создания заканчивается. В это время домом можно манипулировать.

этап выполнения

  • beforeUpdate: Данные в интерфейсе все еще старые, но данные данных обновлены, а данные на странице не синхронизированы. Изменение данных данных вызовет эту функцию.

  • updated: страница отображается повторно, и данные на странице согласуются с данными. Изменение данных данных вызовет эту функцию.

фаза разрушения

  • beforeDestroy: при выполнении этого метода жизненный цикл Vue вошел в стадию уничтожения, но различные данные об экземпляре все еще доступны.

  • destroyed: все компоненты были уничтожены, экземпляр Vue был уничтожен, и любые данные во Vue недоступны.

связь компонентов vue

Как взаимодействуют компоненты vue? Сколько существует способов?

  • В Vue взаимодействие компонентов можно разделить на взаимодействие компонентов родитель-потомок и взаимодействие компонентов, не являющихся родителем-потомком.

Взаимодействие компонентов родитель-потомок: реквизит;parent/parent / children; provide / inject ; ref ; attrs/attrs / listeners
Связь компонентов Brother: eventBus ;vuex
Межуровневая коммуникация: eventBus, Vuex, предоставление/внедрение,attrs/attrs / listeners
Вот несколько распространенных методов использования:

props / $emit

  • Родительский компонент передает данные дочернему компоненту через реквизиты, а дочерний компонент может взаимодействовать с родительским компонентом через $emit.
Родительские компоненты передают значения (реквизиты) дочерним компонентам

Prop может передаваться только от компонента верхнего уровня к компоненту нижнего уровня (родительско-дочерний компонент), так называемый односторонний поток данных. И реквизит доступен только для чтения и не может быть изменен, все модификации завершатся ошибкой и предупредят.

    <!-- section父组件 -->
    <template>
        <div class="section">
            <com-article :articles="articleList"></com-article>
        </div>
    </template>

    <script>
        import comArticle from './test/article.vue'
        export default {
        name: 'HelloWorld',
        components: { comArticle },
        data() {
            return {
            articleList: ['红楼梦', '西游记', '三国演义']
            }
        }
    }
     </script>

    // 子组件 article.vue
    <template>
        <div>
            <span v-for="(item, index) in articles" :key="index">{{item}}</span>
        </div>
    </template>

    <script>
    export default {
        props: ['articles']
    }
    </script>

Дочерний компонент передает значение родительскому компоненту ($ Emit)

$emit привязывает пользовательское событие, когда оператор выполняется, параметр arg передается родительскому компоненту, а родительский компонент слушает и получает параметры через v-on.

    <!-- // 父组件中 -->
    <template>
        <div class="section">
            <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
            <p>{{currentIndex}}</p>
        </div>
    </template>

    <script>
        import comArticle from './test/article.vue'
        export default {
            name: 'HelloWorld',
            components: { comArticle },
            data() {
                return {
                currentIndex: -1,
                articleList: ['红楼梦', '西游记', '三国演义']
                }
            },
            methods: {
                onEmitIndex(idx) {
                this.currentIndex = idx
                }
            }
        }
    </script>

    <!-- 子组件 -->
    <template>
        <div>
            <div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div>
        </div>
    </template>

    <script>
        export default {
            props: ['articles'],
            methods: {
                emitIndex(index) {
                  this.$emit('onEmitIndex', index)
                }
            }
        }
    </script>

children/children / parent

пройти черезparentа такжеродитель иДети могут получить доступ к экземпляру компонента, что представляет собой экземпляр? Делегат имеет доступ ко всем методам и данным этого компонента. Как в #приложениеparentполучить этоnewVue(), взять этот экземпляр еще разРодитель получает экземпляр new Vue(), а затем получает его в этом экземпляре.Родитель становится неопределенным, а подкомпонент внизу получаетchildrenявляется пустым массивом. также обратите вниманиедети - это пустой массив. также обратите вниманиеродитель иchildrenстоимость разная,Ценность детей разная,Значение Children представляет собой массив, иparentявляется объектом. существует**vue3.0**середина,**родитель является объектом. В **vue3.0**,**дети** удалены.

    <template>
        <div class="hello_world">
            <div>{{msg}}</div>

            <!-- child -->
            child
            <com-a></com-a>
            <button @click="changeA">点击改变子组件值</button>
        </div>
    </template>

    <script>
        import ComA from './child'
        export default {
            name: 'HelloWorld',
            components: { ComA },
            data() {
                return {
                msg: 'Welcome'
                }
            },

            methods: {
                changeA() {
                    // 获取到子组件A
                    console.log(this.$children)
                    this.$children[0].messageA = 'this is new value'
                }
            }
        }
    </script>


    <!-- 子组件中 -->
    <template>
        <div class="com_a">
            <span>{{messageA}}</span>
            <p>获取父组件的值为:  {{parentVal}}</p>
        </div>
    </template>

    <script>
        export default {
            data() {
                return {
                messageA: 'this is old'
                }
            },
            computed:{
                parentVal(){
                    return this.$parent.msg;
                }
            }
        }
    </script>

ref/refs

ref: при использовании с обычными элементами DOM ссылка указывает на элемент DOM; при использовании с подкомпонентами ссылка указывает на экземпляр компонента, и вы можете напрямую вызывать методы компонента или получать доступ к данным через экземпляр.

    <!-- //子组件 -->
    <template>
        <div >child</div>
    </template>
    <script>
        export default {
            data() {
                return {
                    name: 'this is child'
                }
            },
            methods: {
                sayHello(){
                    return 'say hello'
                }
            },
        }
    </script>

    <!-- 父组件 -->
    <template>
        <div >
            <com-a ref="child"></com-a>
        </div>
    </template>

    <script>
        import ComA from './child'
        export default {
        components: { ComA },
            data() {
                return {
                msg: 'Welcome'
                }
            },
            mounted() {
                const child = this.$refs.child;
                console.log(child.name) //this is child
                console.log(child.sayHello()) //say hello
                
            },
        }
    </script>

eventBus

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

vuex

Vuex — это шаблон управления состоянием, разработанный для приложений Vue.js. Он использует централизованное хранилище для управления состоянием всех компонентов приложения и имеет соответствующие правила, обеспечивающие предсказуемое изменение состояния.

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

Принцип двустороннего связывания

vue2Он использует метод захвата данных в сочетании с моделью «издатель-подписчик».Object.defineProperty()Чтобы захватить установщик и получатель каждого свойства, публикуйте сообщения подписчикам при изменении данных и запускайте соответствующие обратные вызовы прослушивателя.vue3используется вProxy, он может отслеживать изменения данных в массиве.

Почему данные в компоненте Vue должны быть функцией?

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

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

В чем разница между вычислением и просмотром в Vue

Вычисляемое свойство вычислено:

(1) Поддержка кэша, только при изменении зависимых данных функция расчета будет пересчитана;
(2) Асинхронные операции не поддерживаются в вычисляемых свойствах;
(3) В функции вычисляемого свойства есть метод get (по умолчанию получить вычисляемое свойство) и set (вручную добавить, установить вычисленное свойство);
(4) Вычисляемые свойства автоматически отслеживают изменения зависимых значений, тем самым динамически возвращая содержимое.

Прослушивание имущества смотреть:

(1) Кэш не поддерживается, пока данные изменяются, функция прослушивания будет выполняться;
(2) Асинхронные операции поддерживаются в свойстве прослушивания;
(3) значением свойства прослушивания может быть объект, получающий три атрибута обратного вызова обработчика: Deep, Immediate;
(3) Мониторинг — это процесс, который может инициировать обратный вызов и выполнять некоторые другие действия при изменении отслеживаемого значения.

конец

Для получения дополнительных статей по обучению, пожалуйста, нажмитеИнтерфейсный продвинутый класс, добро пожаловать, обратите внимание! Помните качество три подряд!