Не до конца разобрался, надеюсь меня все простят, и в дальнейшем будет постепенно оптимизироваться.
Нативные манипуляции с DOM
- Чтобы заменить элемент в HTML DOM, используйте метод replaceChild(newnode,oldnode)
- Удалить дочерний элемент из родительского элемента parent.removeChild(child);
- insertBefore(newItem,existingItem) вставляет новый дочерний узел перед указанным существующим дочерним узлом
- appendChild(newListItem добавляет к элементу новый дочерний узел как последний дочерний узел
модель события
Распространение событий относится к процессу распространения событий, когда они происходят. Он разделен на следующие три этапа по порядку.
Первый этап этап захвата: процесс проведения от оконного объекта к целевому узлу (сверху вниз), до целевого элемента, обеспечивающий возможность перехвата событий
Целевой этап второго этапа: в процессе, инициированном текущей целью, цель принимает событие
Третий этап пузырькового этапа: процесс перехода от целевого узла обратно к оконному объекту (снизу вверх) и реагирование на события на этом этапе.
Объект события:
Общие свойства объектов событий в событийной модели DOM:
- type используется для получения типа события
- цель получает цель события
- stopPropagation() останавливает всплытие события
preventDefault() предотвращает поведение события по умолчанию
Общие свойства объектов событий в модели событий IE:
- type используется для получения типа события
- srcElement получает цель события
- cancelBubble предотвращает всплывающие всплывающие окна событий
- returnValue предотвращает поведение события по умолчанию
Делегат/делегация мероприятия:
«Прокси событий» предназначен для делегирования событий, которые изначально должны быть привязаны к родительскому элементу, и позволяет родительскому элементу играть роль мониторинга событий. Принцип делегирования событий — всплытие событий DOM-элементов.
Преимущества использования брокеров событий:
- может улучшить производительность
Может сэкономить много памяти
- Уменьшить количество регистраций на мероприятия
<ul id="parent">
<li class="child">one</li>
<li class="child">two</li>
<li class="child">three</li>
</ul>
<script type="text/javascript">
//父元素
var dom= document.getElementById('parent');
//父元素绑定事件,代理子元素的点击事件
dom.onclick= function(event) {
var event= event || window.event;
var curTarget= event.target || event.srcElement;
if (curTarget.tagName.toLowerCase() == 'li') {
//事件处理
}
}
</script>
Шаблон публикации-подписки и шаблон наблюдателя
Ссылка на ссылку https://segmentfault.com/a/1190000019722065
Шаблон наблюдателя:
Режим наблюдателя: определяет зависимость между объектами «один ко многим».При изменении состояния целевого объекта «Субъект» все объекты, зависящие от него, «Наблюдатель», будут уведомлены.
Будьте проще: у богини есть парень, опубликуйте фотографию в кругу друзей и сделайте приятное заявление: «Моя мама успешно избавилась от заказа, надеюсь, вы счастливы». Все вы разлюбили спрятанные запаски, можете себя только утешать, что вы не один такой.
Особенности шаблона
1) Целевой объект Subject, с методами: добавить/удалить/уведомить Observer;
2) Несколько объектов-наблюдателей Наблюдатель с методами: Получать и обрабатывать уведомления об изменении состояния Субъекта;
3) Уведомлять всех Наблюдателей об изменении состояния целевого объекта Субъект.
Субъект добавляет серию Наблюдателей, Субъект отвечает за поддержание связи с этими Наблюдателями, "Вы заинтересованы во мне, я буду уведомлять вас об обновлениях".
// 目标者类
class Subject {
constructor() {
// 观察者列表
this.observers = [];
}
// 添加
add(observer) {
this.observers.push(observer);
}
// 删除
remove(observer) {
let idx = this.observers.findIndex(item => item === observer);
idx > -1 && this.observers.splice(idx, 1);
}
// 通知
notify() {
for (let observer of this.observers) {
observer.update();
}
}
}
// 观察者类
class Observer {
constructor(name) {
this.name = name;
}
// 目标对象更新时触发的回调
update() {
console.log(`目标者通知我更新了,我是:${this.name}`);
}
}
// 实例化目标者
let subject = new Subject();
// 实例化两个观察者
let obs1 = new Observer('前端开发者');
let obs2 = new Observer('后端开发者');
// 向目标者添加观察者
subject.add(obs1);
subject.add(obs2);
// 目标者通知更新
subject.notify();
// 输出:
// 目标者通知我更新了,我是前端开发者
// 目标者通知我更新了,我是后端开发者
Преимущество
- Цель и наблюдатель имеют уменьшенную функциональную связь и сосредоточены на своей собственной функциональной логике;
- Наблюдатель пассивно получает обновления, разделенные по времени, и получает статус обновления цели в режиме реального времени.
не идеально
Хотя шаблон наблюдателя обеспечивает низкую связь зависимостей между объектами, он не может разделить управление уведомлениями о событиях, такими как «уведомления о просмотре», «уведомления о событиях в указанной теме».
Как и в приведенном выше примере, уведомлять только «разработчиков внешнего интерфейса»? Как объект-наблюдатель может получать только те уведомления об обновлениях, которые ему нужны? В приведенном выше примере после того, как два наблюдателя получили уведомление об изменении целевого состояния, они оба выполняютupdate(), разницы нет.
Модель публикации-подписки (издатель и подписчик)
Режим публикации-подписки: в зависимости от канала события (темы) подписчик, который хочет получать уведомления, подписывается на тему с помощью настраиваемого события, а объект, который активируется событием, издатель уведомляет каждый объект-подписчик, который подписывается на тему, публикация тематического события.
Отличие режима публикации-подписки от режима наблюдателя в том, что появляется «третья сторона» (центр событий). Целевой объект не уведомляет наблюдателя напрямую, а отправляет уведомление через центр событий. В модели публикации-подписки издатель не уведомляет подписчика напрямую, другими словами, издатель и подписчик не знают друг друга.
// 事件中心
let pubSub = {
// 缓存列表
list: {},
/*
* 添加订阅者(订阅函数),将订阅的类型与回调函数加入缓存列表
* key: 消息的类型
* fn: 订阅的回调函数
*/
subscribe: function (key, fn) {
if (!this.list[key]) {
this.list[key] = [];
}
this.list[key].push(fn);
},
//发布消息(发布函数), 依次通知订阅者
publish: function(key, ...arg) {
for(let fn of this.list[key]) {
fn.call(this, ...arg);
}
},
// 取消订阅
unSubscribe: function (key, fn) {
let fnList = this.list[key];
if (!fnList) return false;
if (!fn) {
// 不传入指定取消的订阅方法,则清空所有key下的订阅
fnList && (fnList.length = 0);
} else {
fnList.forEach((item, index) => {
if (item === fn) {
fnList.splice(index, 1);
}
})
}
}
}
// 订阅
pubSub.subscribe('onwork', time => {
console.log(`上班了:${time}`);
})
pubSub.subscribe('offwork', time => {
console.log(`下班了:${time}`);
})
pubSub.subscribe('launch', time => {
console.log(`吃饭了:${time}`);
})
// 发布
pubSub.publish('offwork', '18:00:00');
pubSub.publish('launch', '12:00:00');
// 输出
// 下班了:18:00:00
// 吃饭了:12:00:00
Режим наблюдателя и режим публикации-подписки Отличия:
аналогичная точка
Оба определяют отношения зависимости «один ко многим» и выполняют соответствующие уведомления при изменении соответствующего состояния.
разница
Режим публикации-подписки является более гибким и представляет собой расширенную версию режима наблюдателя с указанием соответствующего распределения.
- Шаблон наблюдателя поддерживает одно событие, соответствующее нескольким объектным отношениям, которые зависят от события;
- Публикация и подписка для поддержания связи между несколькими событиями (темами) и объектами, которые зависят от каждого события (темы);
- Шаблон наблюдателя заключается в том, что целевой объект напрямую инициирует уведомление (все уведомления), а объект наблюдателя вынужден получать уведомление. Модель публикации-подписки имеет дополнительный средний уровень (центр событий), который управляет широковещательной рассылкой уведомлений (уведомляются только объекты, подписавшиеся на соответствующее событие);
- Режим наблюдателя имеет сильные зависимости между объектами и реальную развязку между объектами в режиме публикации-подписки.
Прототипы и наследование
Цепь прототипа:
__proto__), указывая на объект-прототип своего конструктора (prototype) - «объект-прототип своего конструктора» также имеет собственный объект-прототип, и так далее, пока объект-прототип объекта не будетnull.nullнет прототипа,nullЭто последнее звено в цепочке прототипов.Нам нужно помнить о двух вещах:
①__proto__ и свойства конструктора уникальны для объектов;
② Свойство прототипа уникально для функции, поскольку функция также является объектом, поэтому функция также имеет свойства __proto__ и конструктор.
Функция атрибута __proto__ заключается в том, что при доступе к атрибуту объекта, если атрибут не существует в объекте, он переходит к объекту (родительскому объекту), на который указывает его атрибут __proto__, и продолжает искать до тех пор, пока _ конечная точка атрибута _proto__ имеет значение null, и дальнейший поиск эквивалентен получению значения null, и будет сообщено об ошибке. Ссылка, соединяющая объекты через свойство __proto__, — это то, что мы называем цепочкой прототипов.
Роль свойства прототипа состоит в том, чтобы позволить объектам, созданным функцией, находить общие свойства и методы, то есть f1.__proto__ === Foo.prototype. Значение атрибута конструктора состоит в том, чтобы указывать на конструктор объекта, а окончательный конструктор всех функций (которые в настоящее время считаются объектами) указывает на функцию.
function Child(){
this.name = 'lili'
}
const child = new Child()
console.log(child.__proto__ === Child.prototype) // true
console.log(Child.__proto__ === Function.prototype) // true
console.log(child.__proto__.__proto__.__proto__) // null
1 Чему равно child.__proto__?
Ответ: Ребенок.прототип
2 Чему равно Child.__proto__?
Ответ: Function.prototype
Решение: свойство __proto__ (прототип) экземпляра равно свойству прототипа его конструктора. Конструктором дочернего экземпляра является Child, а конструктором Child — функция, и результат ясен с первого взгляда.
Унаследованная реализация
Наследование композиции ES5
//定义一个父类:人
function Person(cai) {
this.cai = cai;
this.emotion = ['喜', '怒', '哀', '乐']; //人都有喜怒哀乐
}
//定义原型类方法 将 Person 类中需共享的方法放到 prototype 中,实现复用
Person.prototype.eat = function () {
console.log('吃' + this.cai);
}
//定义子类:学生,继承了“人”这个类
function Student(cai, studentID) {
//先调用父类构造器 子类继承父类的属性 需要将this指向父类中的cai
Person.call(this, cai);
this.studentID = studentID; // studentID是子类自己的属性
}
Student.prototype = new Person(); //子类继承父类的方法此时 Student.prototype 中的 constructor 被重写了,会导致 stu1.constructor === Person
Student.prototype.constructor = Student; //将 Student 原型对象的 constructor 指针重新指向 Student 本身
//创建子类的实例
var stu1 = new Student('西兰花', 1001);
console.log(stu1.emotion); //['喜', '怒', '哀', '乐']
console.log(stu1.cai); // 西兰花
stu1.eat(); //吃西兰花
console.log(stu1.constructor); //Student
Сочетание наследования цепочки прототипов и наследования заимствования конструктора, то есть наследование композиции — наиболее часто используемый паттерн наследования в javascript, однако и у него есть свои недостатки: в любом случае наследование композиции вызовет конструктор родительского класса дважды.
Один раз при создании прототипа подкласса, а другой раз внутри конструктора подкласса.Подкласс в конечном итоге будет содержать все свойства экземпляра объекта суперкласса, но мы должны переопределить эти свойства при вызове конструктора подкласса.
Существенные различия в наследовании:
**ES5:** Сначала создайте экземпляр объекта this подкласса, а затем добавьте к нему метод родительского класса (Parent.apply(this)).
**ES6:** Сначала создайте объект экземпляра this родительского класса (поэтому сначала должен быть вызван суперметод), а затем используйте конструктор подкласса, чтобы изменить его.
Наследование классов ES6
Es6 представляет новую реализацию ключевых словclass,КромеclassКроме того, естьconstructor,static,extends,super.
class Person {
constructor(cai) {
this.cai = cai;
this.emotion = ['喜', '怒', '哀', '乐']; //人都有喜怒哀乐
}
eat() {
console.log('吃' + this.cai);
}
}
class Student extends Person {
constructor(cai, studentID) {
// 指向父类的构造函数
super(cai);
this.studentID = studentID;
}
showStudentID() {
console.log(this.studentID)
}
}
var stu1 = new Student('西兰花', 1001);
console.log(stu1.emotion);
stu1.eat(); //吃西兰花
stu1.showStudentID() //1001
Примечание:
Класс в ES6 реализует наследование через ключевое слово extends.
Подкласс должен вызывать метод super в методе конструктора.Ключевое слово super здесь указывает на конструктор родительского класса, который используется для создания объекта this родительского класса.
У подкласса нет своего объекта this, ему нужно вызвать метод super для наследования объекта this родительского класса, а затем обработать его, поэтому известно, что ключевое слово this можно использовать только после вызова super, в противном случае будет сообщено об ошибке.
Оптимизация производительности:
1) Используйте несколько доменных имен для хранения ресурсов сайта:
cdn: сеть распространения контента, основная идея заключается в том, чтобы избежать узких мест и ссылок в Интернете, которые могут повлиять на скорость и стабильность передачи данных, чтобы передача контента была более быстрой и стабильной.
причина:
- Кэширование CDN удобнее
- Преодолеть ограничение параллелизма браузера
- Сохранить пропускную способность файлов cookie
- Сохранить количество подключений основного доменного имени и оптимизировать скорость отклика страницы
- Предотвращение ненужных проблем с безопасностью
Что такое Repaint и Reflow? Как оптимизировать?
- Перерисовка — это когда узлу необходимо изменить внешний вид, не влияя на макет, например, изменение цвета называется перекрашиванием.
- Перекомпоновка — это когда необходимо изменить макет или геометрические свойства, и это называется перекомпоновкой. Перекомпоновка должна происходить при перерисовке, а перерисовка не обязательно приводит к перерисовке. Стоимость перекомпоновки намного выше, чем стоимость перерисовки, и изменение дочерних узлов в родительском узле, скорее всего, вызовет серию перекомпоновок родительского узла.
- Оптимизация:
- Используйте преобразование вместо верха
- Используйте visibility вместо display: none , потому что первое вызывает только перерисовку, второе вызывает перекомпоновку (меняет макет)
- Не помещайте значение свойства узла в цикл как переменную в цикле.
- Не используйте макет таблицы, небольшое изменение может привести к перестановке всей таблицы.
- Выбор скорости реализации анимации, чем быстрее скорость анимации, тем больше время перекомпоновки, также можно выбрать использование requestAnimationFrame
- Селекторы CSS сопоставляются и ищутся справа налево, чтобы избежать слишком большого количества уровней узлов.
- Установите узел, который часто перерисовывается или перекомпоновывается как слой, слой может предотвратить влияние поведения рендеринга этого узла на другие узлы. Например, для тега видео браузер автоматически превратит узел в слой.
Разница между for in и for of
for in
1 подходит для обхода объектов
2 Пересечение – это ключ
3 Перебрать все свойства перечислимого (включая свойства прототипа)
4 может правильно реагировать на перерыв продолжить
Итерация по объектам:
Object.prototype.method = function(){
}
var myObject={
a:1,
b:2,
c:3
}
for(var key in myObject) {
console.log(key);
//a
//b
//c
//method
}
for in может перейти к методу метода прототипа myObject. Если вы не хотите проходить метод прототипа и свойства, вы можете судить внутри цикла. Метод hasOwnPropery может определить, является ли свойство свойством экземпляра объекта
Первым выводом является имя свойства объекта, а затем свойства и методы в прототипе объекта. Если вы не хотите, чтобы он выводил свойства и методы в прототипе, вы можете использовать метод hasOwnProperty для фильтрации
Object.prototype.method = function(){
}
var myObject={
a:1,
b:2,
c:3
}
for (var key in myObject) {
if(myObject.hasOwnProperty(key)){
console.log(key); // a b c
}
}
Перебрать массив:
Array.prototype.sayHello = function(){
}
Array.prototype.str = 'world';
var myArray = [1,2,10,30,100];
myArray.name='数组';
for(let index in myArray){
console.log(index);
// 0,1,2,3,4,name,str,sayHello
}
Примечание: for in больше подходит для перебора объектов, не используйте for in для перебора массивов. Использование for in также может пройти по массиву, но есть следующие проблемы:
Индекс индекса — это строковое число, которое нельзя использовать непосредственно для геометрических операций.
Использование for in перебирает все перечисляемые свойства массива, включая прототипы. Например, способ-прототип метода и атрибуты имени верхнего каштана.
Возможно, порядок обхода не соответствует внутреннему порядку фактического массива.
for in проходит индекс массива (т.е. имя ключа)
for of
Подходит для обхода коллекций с помощью объектов итераторов.
пройденное значение
не входит в прототип
Также правильно реагируйте на прерывание продолжения
Итерация по объектам:
Object.prototype.method = function(){
}
var myObject={
a:1,
b:2,
c:3
}
for (var key of myObject) {
console.log(key); // TypeError: myObject is not iterable
}
Перебрать массив:
Array.prototype.sayHello = function(){
console.log("Hello");
}
var myArray = [1,200,3,400,100];
for(let key of myArray){
console.log(key);
// 1 200 2 400 400
}
Примечание: for in проходит по индексу (т.е. имени ключа) массива, а for of проходит по значению элемента массива. Таким образом, for in больше подходит для перебора объектов, не используйте for in для перебора массивов.
механизм загрузки модуля nodejs
Оценка того, равны ли две переменные
При сравнении двух значений в js вы можете использовать оператор равенства == или оператор строгого равенства ===
==выражатьабстрактное равенство, когда типы значений на обеих сторонах разные, это будет сделано первымнеявное преобразование типов, а затем сравните значения;===выражатьстрогое равенство, преобразование типов выполняться не будет, и типы с обеих сторон не должны совпадать. Но в === случае NaN не равно NaN, +0 равно -0
console.log(NaN === NaN) //false
console.log(+0 === -0 ) // true
Object.is() в ES6 принимает два параметра и возвращает true, когда значения двух равны.В этом случае типы данных и значения двух должны быть одинаковыми.
console.log( Object.is(NaN, NaN)) //true
console.log(Object.is(+0, -0)) //false
принцип:
if (!Object.is) {
Object.is = function(x, y) {
if (x === y) { // Steps 1-5, 7-10
// 针对 +0不等于-0
return x !== 0 || 1 / x === 1 / y;
} else {
// 针对 NaN等于NaN
return x !== x && y !== y;
}
};
}
Глубокое копирование и поверхностное копирование (начальное базовое собеседование, часто задаваемые вопросы на собеседовании)
Ссылка на ссылку https://juejin.cn/post/6844903493925371917#heading-2
Введение:
В JS есть два типа данных: примитивные типы данных и ссылочные типы данных. Глубокое копирование и мелкое копирование обычно предназначены для ссылочных типов данных.
Основные типы данных в основном:undefined,boolean,number,string,null
var a = 1;
var b = a;
a = 2;
console.log(a); // 2
console.log(b); // 1var arr1 = [1,2,3,4];
var arr2 = arr1;
arr1.push(5);
console.log(arr1); // [1,2,3,4,5]
console.log(arr2); // [1,2,3,4,5]
arr2.push(6);
console.log(arr1); // [1,2,3,4,5,6]
console.log(arr2); // [1,2,3,4,5,6]Однако для присваивания ссылочным типам данных arr2 просто копирует ссылку на arr1 (которую также можно назвать ссылкой на адрес памяти arr1).указатель). Проще говоря, arr1 и arr2 указывают на одно и то же пространство памяти.
Мелкая копия:
Если свойство является примитивным типом, копируется значение примитивного типа; если свойство является адресом памяти (ссылочным типом), копируется адрес памяти, поэтому, если один объект изменит этот адрес, это повлияет на другой объект.
function shallowCopy(copyTarget) {
var obj = {};
for (var key in copyTarget) {
obj[key] = copyTarget[key];
}
return obj;
}
var json1 = {
'name': '张三',
'family': {
'children': '张三三',
'wife': '李四'
}
}
var json2 = shallowCopy(json1);
// before
console.log(json2);
// after
json1.family['father'] = '张一'
console.log(json1);
console.log(json2);
Видно, что неглубокая копия копирует только данные базового типа.Для данных ссылочного типа он указывает на скопированный адрес памяти.Если объект в исходном адресе изменится, поверхностно скопированный объект также изменится соответственно.
Глубокая копия:
Глубокое копирование можно резюмировать следующим образом: создание отдельного пространства памяти для члена данных ссылочного типа для реализации копии реального содержимого.
function deepCopy(copyTarget) {
var obj = {};
for(var key in copyTarget) {
// 先判断obj[key]是否为对象
if(typeof copyTarget[key] === "object"){
// 递归
obj[key] = deepCopy(copyTarget[key]);
} else {
// 如果不是对象,直接赋值即可
obj[key] = copyTarget[key];
}
}
return obj;
}
var json1 = {
'name': '张三',
'family': {
'children': '张三三','wife': '李四'
}
}
var json2 = deepCopy(json1);
// before
console.log(json2);
// after
json1.family['father'] = '张一'
console.log(json1);
console.log(json2);
расширять
Глубокое копирование можно выполнить в формате JSON:JSON.parse(JSON.stringify(obj))
Но репликация JSON игнорирует неопределенные и функциональные выражения.
var obj = {
a: 1,
b: 2,
c: undefined,
sum: function() { return a + b; }
};
var obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); //Object {a: 1, b: 2}
Фронтенд модульный AMD, CMD, CommonJS и ES6
Ссылка на ссылкуnuggets.capable/post/684490…
Спецификация CommonJS:
CommonJS — это спецификация для серверных модулей, и Node.js использует эту спецификацию. Модули загрузки спецификаций CommonJS синхронны, то есть только после завершения загрузки могут быть выполнены следующие операции.
В спецификации CommonJS цель раскрытия объекта модуля достигается путем присвоения свойств module.exports или exports. CommonJS — модуль синхронной загрузки, в браузере будет блокировка, поэтому не применим
AMD:
Спецификация AMD заключается в том, чтобы загружать модули асинхронно, и необходимо определить метод определения обратного вызова AMD уважает спецификацию, которая появляется в процессе использования предварительных требований и --requireJS.
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) {
// 等于在最前面声明并初始化了要用到的所有模块
if (false) {
// 即便没用到某个模块 b,但 b 还是提前执行了
b.foo()
}
});
CMD
CMD: CMD похож на AMD, разница в том, что AMD соблюдает предварительное доверие, спецификацию, появившуюся в процессе продвижения --requireJS. CMD учитывает ближайшую зависимость. --Спецификации, которые появляются при продвижении sea.js.
Однако из-за того, что AMD&CMD используется на стороне браузера и использует асинхронную загрузку, на самом деле CMD все равно нужно запрашивать то, что ему нужно в начале, но так удобнее писать. (для получения имени файла js используется обычное сопоставление, поэтому закомментированное все равно будет запрошено, и можно писать только строки, выражения использовать нельзя)
/** AMD写法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) {
// 等于在最前面声明并初始化了要用到的所有模块
a.doSomething();
if (false) {
// 即便没用到某个模块 b,但 b 还是提前执行了
b.doSomething()
}
});
/** CMD写法 **/
define(function(require, exports, module) {
var a = require('./a'); //在需要时申明
a.doSomething();
if (false) {
var b = require('./b');
b.doSomething();
}
});
/** sea.js **/
// 定义模块 math.js
define(function(require, exports, module) {
var $ = require('jquery.js');
var add = function(a,b){
return a+b;
}
exports.add = add;
});
// 加载模块
seajs.use(['math.js'], function(math){
var sum = math.add(1+2);
});
es6
На уровне языковых стандартов ES6 реализует модульную функцию, и реализация достаточно проста, чтобы стать общим модульным решением для браузеров и серверов. Его функция модуля в основном состоит из двух команд: экспорта и импорта. Команда экспорта используется для указания внешнего интерфейса модуля, а команда импорта используется для импорта функций, предоставляемых другими модулями.
Примечание. Модуль es6 — это независимый файл, и все переменные внутри файла нельзя получить извне. Если вы хотите, чтобы снаружи можно было прочитать переменную внутри модуля, вы должны использовать ключевое слово export для вывода переменной.ES6 также может экспортировать классы и методы, которые автоматически применяют строгий режим
/** 定义模块 math.js **/
var basicNum = 0;
var add = function (a, b) {
return a + b;
};
export { basicNum, add };
/** 引用模块 **/
import { basicNum, add } from './math';
function test(ele) {
ele.textContent = add(99 + basicNum);
}
Как показано в приведенном выше примере, при использовании команды импорта пользователю необходимо знать имя загружаемой переменной или функции. На самом деле, ES6 также предоставляет команду экспорта по умолчанию, которая указывает выходные данные модуля по умолчанию, а соответствующий оператор импорта не требует использования фигурных скобок. Это также ближе к стилю цитирования ADM.
/** export default **/
//定义输出
export default { basicNum, add };
//引入
import math from './math';
function test(ele) {
ele.textContent = math.add(99 + math.basicNum);
}
Модули ES6 не являются объектами,importКоманда будет статически проанализирована движком JavaScript, и код модуля будет введен во время компиляции, а не загружаться во время выполнения кода, поэтому условная загрузка не может быть достигнута. Именно благодаря этому возможен статический анализ.
Различия между модулями ES6 и модулями CommonJS
1. Модуль CommonJS выводит копию значения, а модуль ES6 выводит ссылку на значение.
- Модули CommonJS выводят копию значения, то есть после вывода значения изменения внутри модуля не повлияют на значение.
- Модули ES6 работают иначе, чем CommonJS. Когда движок JS статически анализирует скрипт, он встречает команду загрузки модуля
import, создается ссылка только для чтения. Когда скрипт действительно выполняется, в соответствии с этой ссылкой только для чтения перейдите к загруженному модулю, чтобы получить значение. Другими словами, ES6importВроде как "символическая ссылка" Unix-систем, исходное значение изменилось,importЗагруженное значение также изменится соответствующим образом. Таким образом, на модули ES6 ссылаются динамически и они не кэшируют значения, а переменные в модулях привязаны к модулю, в котором они находятся.
-
Загрузка во время выполнения: модули CommonJS являются объектами, то есть при вводе сначала загружается весь модуль, генерируется объект, а затем из этого объекта считываются методы, такая загрузка называется «загрузка во время выполнения».
-
Загрузка во время компиляции: модули ES6 не являются объектами, а передаются через
exportКоманда явно указывает код для вывода,importв виде статической команды. то естьimportВместо того, чтобы загружать весь модуль, вы можете указать загружать выходное значение, эта загрузка называется «загрузкой во время компиляции».
CommonJS загружает объект (т.е.module.exportsсвойство), объект не будет создан, пока скрипт не завершит работу. Модуль ES6 не является объектом, его внешний интерфейс — это просто статическое определение, которое будет сгенерировано на этапе статического анализа кода.
Кольцо событий (лично я думаю, что это относительно сложный вопрос для интервью)
Ссылка на ссылкуnuggets.capable/post/684490…
Цикл событий в браузере:
В браузере поток движка js будет считывать события из очереди задач и выполнять их в цикле Этот механизм работы называется Event Loop (цикл событий).
Для каждой среды браузера существует не более одного цикла событий. Цикл событий может иметь одну или несколько очередей задач (очередей задач).
Сначала выполните синхронный код, затем js запустится в очередь сообщений для выполнения асинхронного кода, после асинхронного завершения это будет функция обратного вызова, а затем перейдет к следующему циклу событий для выполнения setTimeout
Он запускает первый цикл из скрипта (общий код). Затем глобальный контекст попадает в стек вызовов функций. Пока стек вызовов не опустеет (остался только глобал), то выполняем все микрозадачи(微任务). Когда все исполняемые микрозадачи(微任务)После завершения выполнения. снова цикл из макрозадачи宏任务Запустите, найдите одну из очередей выполняемых задач, затем выполните все микрозадачи, которые зацикливаются.
С точки зрения спецификации setTimeout имеет минимальное время 4 мс, что означает, что независимо от того, сколько вы установите, он будет запускать обратный вызов с интервалом не менее 4 мс. И асинхронный Promise не имеет этой проблемы. Асинхронная очередь, в которой находится промис, имеет более высокий приоритет. Промис является асинхронным, что относится к его методам then() и catch(). Сам промис по-прежнему является синхронным промисом. Задача будет выполнена в конце очереди. текущий цикл событий, а setTimeout в задаче выполняется в следующем цикле событий
Суммировать:
setTimeout、onClickДождитесь каких-то операций, результаты его выполнения мы поставим в очередь, а основной поток не будет блокироваться в этот периодevent loopВозьмите его с самого начала в очереди и выполните его в стеке исполненияevent loopникогда не останавливатьсяEvent Loop(механизм цикла событий)Пополнить:
Задачи макроса: блоки кода, выполняемые синхронно с помощью js, setTimeout, setInterval, XMLHttprequest и т. д.
Микрозадачи: promise, process.nextTick (среда узла) и т.д.- выполнить основной блок кода
- Если вы столкнулись с Promise, поместите содержимое после этого в очередь микрозадач.
- После завершения выполнения макрозадачи проверьте, есть ли задачи в очереди микрозадач.
- Если у вас есть, все micrasure
- После завершения выполнения запустите следующий макрос.
setTimeout(function(){
console.log(4)
},0);
new Promise(function(resolve){
console.log(1)
for( var i=0 ; i<10000 ; i++ ){
i===9999 && resolve()
}
console.log(2)
}).then(function(){
console.log(5)
});
console.log(3);
//依次输出 1 2 3 5 4
setTimeout(() => {
console.log(1);
}, 0);
new Promise((resolve) => {
console.log(2);
resolve();
}).then(() => {
console.log(3);
});
console.log(4);
// 输出最后的结果 2 4 3 1
анализировать:
среда узла
Механизм событий в среде узла намного сложнее, чем в браузере.Опрос событий узла имеет концепцию этапов. Все микрозадачи, такие как process.nextTick, выполняются при переключении каждого этапа.
этап таймера
Выполнить все запланированные события, время которых истекло
этап peding callbacks
Этот этап будет выполнять все обратные вызовы операций ввода / вывода, которые не были выполнены на последнем этапе опроса, обычно сообщается об ошибке.
idle.prepare
Можно игнорировать
этап опроса
Этот этап особенно сложен
- Заблокируйте все операции ввода-вывода, выполните все обратные вызовы.
- После того, как все обратные вызовы ввода-вывода выполнены, проверьте, есть ли таймер, который нужно выполнить, и вернитесь к этапу таймера, если он есть.
- Если таймера нет, войдите в фазу проверки.
этап проверки
Выполнить setImmediate
закрыть этап обратных вызовов
Выполняет все события обратного вызова закрытия, такие как отключение сокета.
каррирование функций
Техника сначала заполнения нескольких параметров в функции, а затем возврата новой функции называется каррированием функции. Обычно может использоваться для написания функций для функций без вторжения в них.Предустановленные общие параметры, для нескольких повторных вызовов.
const add = function add(x) {
return function (y) {
return x + y
}
}
const add1 = add(1)
add1(2) === 3
add1(20) === 21
HTTP-связанный
Что происходит с момента ввода URL до загрузки страницы?
- 1. Введите URL-адрес в адресную строку браузера и нажмите Enter.
- 2. Браузер проверяет, существует ли текущий URL-адрес в кеше, и сравнивает, истек ли срок действия кеша.
- 3. DNS разрешает IP-адрес, соответствующий URL-адресу.
- 4. Установите TCP-соединение в соответствии с IP (трехстороннее рукопожатие).
- 5. HTTP инициирует запрос.
- 6、服务器处理请求,浏览器接收HTTP响应。
- 7. Визуализируйте страницу и постройте DOM-дерево.
- 8. Закройте соединение TCP (четыре раза).
AST
Абстрактное синтаксическое дерево — это форма разбора кода на древовидные объекты буква за буквой. Это основа для преобразования между языками, проверки синтаксиса кода, проверки стиля кода, форматирования кода, выделения кода, подсказок об ошибках кода, автоматического завершения кода и многого другого. Например:
function square(n){
return n * n
}
AST, преобразованный путем синтаксического анализа, выглядит следующим образом:
Принцип компиляции Babel:
Babylon анализирует код ES6/ES7 в AST
babel-traverse проходит и транслирует AST, чтобы получить новый AST
Новый AST конвертируется в ES5 через babel-генератор
О вьюексе
На самом деле, при изучении vuex лучше всего имитировать работу с данными.
Данные моделирования:
const fs = require('fs')
// Koa 为一个class
const Koa = require('koa')
const path = require('path')
// koa 路由中间件
const Router = require('koa-router');
const app = new Koa()
// 实例化路由
const router = new Router();
// 处理post请求,把 koa2 上下文的表单数据解析到
const bodyParser = require('koa-bodyparser');
app.use(bodyParser())
router.get('/', async (ctx, next) => {
ctx.response.body = 'hello koa !'
})
// 加前缀
//router.prefix('/api');
router.get('/api/news', async (ctx, next) => {
ctx.response.body = {
result: "这是一条新闻!!!!"
}
})
app
.use(router.routes())
.use(router.allowedMethods());
app.listen(4000)
store/index.js
import Vue from 'vue'
import 'es6-promise/auto' //引用依赖
import Vuex from 'vuex'
import http from '@/http/index.js'
Vue.use(Vuex) //使用vuex插件
//state
export const state = {
news: ''
}
//action
// Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
export const actions = {
//异步操作都在这里
async getNews(context, grade) {
//所有在此的方法第一个参数都是context
let newsResult = await http.get('/api/news', {})
context.commit('SET_NEWS', newsResult)
}
}
//mutations
export const mutations = {
SET_NEWS(state, data) {
state.news = data.data.result
}
}
export default new Vuex.Store({
state,
mutations,
actions
})
передача
<template>
<div>{{news}}</div>
</template>
<script>
/* 辅助函数 */
import {
mapState,
mapGetters,
mapMutations,
mapActions
} from 'vuex'
export default {
data() {
return {
}
},
computed: {
...mapState(['news'])
},
methods: {
...mapActions(['getNews'])
},
mounted() {
this.getNews()
//或者
//this.$store.dispatch('getNews')
}
}
</script>
Ссылка на ссылку https://www.yuque.com/testdog/dev/zuphei
vue параметры маршрутизации
Передачу параметров через Vue можно разделить на два способа:
параметр params
параметр запроса
Есть два способа передать параметры params: (1) Перейти через router-link (2) Переход по маршруту через навигацию по программированию
значение передачи параметров
<div
v-for="item in list"
@click="getDescribe(item)"
>
{{item}}
</div>data() {
return {
list: ['101','102','103']
}
}
Конфигурация маршрутизации соответствующего маршрута выглядит следующим образом:
{
path: '/two/:id',
name: 'two',
component: () => import('@/components/two.vue'),
meta: {
title: 'two'
}
}
За push может следовать объект или строка:
Объект:
getDescribe(item) {
this.$router.push({
path: `/two/${item}`
})
}
нить:
getDescribe(item) {
this.$router.push(`/two/${item}`)
}
Именованные маршруты:
getDescribe(item) {
this.$router.push({ name: 'two', params: { id: `${item}` }})
}
Примечание. Следует отметить, что использование params должно использоваться вместе с атрибутом name, иначе целевая страница маршрутизации, на которую нужно перейти, не сможет получить переданные параметры через params. params: Эквивалент почтового запроса, параметры запроса не будут отображаться в адресной строке.
Этот подход имеет следующие проблемы:
Если подстраница нажмет кнопку [Обновить], только что переданные параметры не будут синхронизированы. Потому что параметры не синхронизируются со строкой веб-адреса. Но если вы хотите, чтобы он отражался в адресной строке, вы можете прописать его в атрибуте пути при настройке маршрута. Следующее может решить проблему обновления:
{
path: '/two/:id',
name: 'two',
component: () => import('@/components/two.vue'),
meta: {
title: 'two'
}
}
Чтение параметров:
console.log(this.$route.params)
значение прохода запроса. Аналогично получению проходного значения
запрос: Эквивалент запроса на получение, параметры запроса будут отражены в адресной строке.
this.$router.push({
path: `/two`,
query: {
id:item
}
})
http://localhost:8888/#/two?id=101
console.log(this.$route.query)
В чем разница между this.$router и this.$route?
В упомянутой выше программной навигации используйте this.$router.push() для изменения маршрута и используйте this.$route.params для получения значения параметра.
1. $router — это экземпляр VueRouter. Если вы хотите перейти к другому URL-адресу, используйте метод $router.push.
2. $route — это текущий объект перехода маршрутизатора, который может получить имя, путь, запрос, параметры и т. д.
смотреть&&вычислять в vue
вычисленные функции
1. расчетное значение,
2. Применение: для упрощения вычисления {{}} в tempalte и для обработки значения props или $emit
3. Кешируется, значение повторного рендеринга страницы не меняется, а вычисляемое свойство немедленно вернет предыдущий результат вычисления без необходимости повторного выполнения функции
Примечание: значение вычисляемого будет кэшировано после выполнения геттера.Только после того, как значение атрибута, от которого он зависит, изменится, соответствующий геттер будет вызван снова для вычисления в следующий раз, когда будет получено значение вычисленного.
функция часов
1. это акт наблюдения,
2. Приложение: отслеживайте реквизиты, $emit или значение этого компонента для выполнения асинхронных операций.
3. Без кэширования, значение будет выполнено при повторном рендеринге страницы без изменения
Примечание: watch будет выполнять обратный вызов каждый раз при изменении отслеживаемого значения. Фактически, с этой точки зрения, обратный вызов выполняется после изменения зависимого значения.
Резюме: если значение зависит от нескольких свойств (многие к одному), определенно удобнее использовать вычисляемое. Если изменение значения вызовет серию операций или изменение значения вызовет серию изменений значения (один ко многим), удобнее использовать watch.
Обратный вызов watch будет передавать старое и новое значения свойства мониторинга, и через эти два значения могут выполняться некоторые специфические операции. вычисляется обычно простое вычисление.
Нет нижнего уровня между watch и вычисляемым.Внутренний вызов watch — vm.$watch.Общим для них является то, что каждое определенное свойство создает отдельный объект Watcher.
Vue.js предоставляет метод watch, который используется для наблюдения за изменениями данных в экземпляре Vue.
<template>
<div>
<input
type="text"
v-model="age"
>
</div>
</template>
<script>
export default {
data() {
return {
age:18
}
},
watch: {
age: (newAge,oldAge) => {
console.log('新值为:'+newAge+',旧值为:'+oldAge);
}
},
methods: {
},
components: {
},
computed: {
},
mounted() {
}
}
Как понять виртуальный DOM
1. Что такое вдом?
vdom — это аббревиатура Virtual DOM (Virtual DOM), которая относится к структуре DOM, моделируемой JS, и сравнение изменений DOM выполняется на уровне JS. Другими словами, vdom — это JS-объект.
Следующий реальный DOM
<ul id="list">
<li class="item">Item1</li>
<li class="item">Item2</li>
</ul>
Отображение в виртуальный DOM выглядит следующим образом:
{
tag: "ul",
attrs: {
id: "list"
},
children: [
{
tag: "li",
attrs: { className: "item" },
children: ["Item1"]
}, {
tag: "li",
attrs: { className: "item" },
children: ["Item2"]
}
]
}
2. Зачем использовать вдом?
Используя метод моделирования объектов JS, операция сравнения DOM размещается в слое JS, что уменьшает ненужную перерисовку браузера и повышает эффективность.
Конечно, некоторые люди говорят, что виртуальный DOM не быстрее реального DOM, что тоже верно. Когда каждый фрагмент данных в таблице изменяется, реальная операция DOM, очевидно, выполняется быстрее, потому что виртуальный DOM также имеет процесс сравнения алгоритма diff в js. Таким образом, выигрыш в производительности применяется только при рендеринге большого объема данных и изменении лишь небольшой части данных.
Преимущества виртуального DOM:
1. Он открывает дверь для функционального программирования пользовательского интерфейса, то есть пользовательский интерфейс = f (данные), способ создания пользовательского интерфейса.
2. Объекты JS можно рендерить в среды, отличные от DOM браузера, то есть поддерживается кроссплатформенная разработка, например ReactNative.
Три, алгоритм сравнения
Связь между компонентами vue
1. Родительский компонент взаимодействует с дочерним компонентом
С реквизитами родительские компоненты могут использовать реквизиты для передачи данных дочерним компонентам.
father.vue
<template>
<div>
<Child :name="msg"></Child>
</div>
</template>
<script>
import Child from '@/components/child.vue'
export default {
components: {
Child
},
data() {
return {
msg: 'feixuan'
}
},
computed: {
},
mounted() {
},
methods: {
}
}
</script>
child.vue
<template>
<div>
{{name}}
</div>
</template>
<script>
export default {
props:{
name:{
type:String,
default:''
}
},
data() {
return {
}
},
components: {
},
computed: {
},
mounted() {
},
methods: {
}
}
</script>
2. Дочерний компонент взаимодействует с родительским компонентом
Способ 1: используйте события vue
Родительский компонент передает метод события дочернему компоненту, дочерний компонент запускает событие через $emit и вызывает обратно родительский компонент.
father.vue
<template>
<div>
<Child @msgFunc="msgEvent"></Child>
{{message}}
</div>
</template>
<script>
import Child from '@/components/child.vue'
export default {
components: {
Child
},
data() {
return {
message: ''
}
},
methods: {
msgEvent(msg) {
console.log(msg)
this.message = msg
}
},
computed: {
},
mounted() {
}
}
</script>
child.vue
<template>
<div>
<button @click="handleClick">点我</button>
</div>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
handleClick() {
this.$emit('msgFunc','我是来自子组件的消息');
}
},
components: {
},
computed: {
},
mounted() {
}
}
</script>
3. Взаимодействие между компонентами, не являющимися родительскими и дочерними.
Для двух компонентов, которые не находятся в отношениях родитель-потомок, как реализовать связь? В случае небольшого проекта вполне возможно использовать центральную шину событийEventBusПуть. Если размер вашего проекта средний или большой, вы можете использовать управление состоянием vuex.
EventBusпутем создания новогоVueмероприятиеbusобъект, а затем передатьbus.$emitтриггерное событие,bus.$onСлушайте триггерные события.
Стратегия асинхронного обновления DOM Vue.js и nextTick
При использовании vue.js иногда из-за некоторых конкретных бизнес-сценариев вам приходится манипулировать DOM, например:
<template>
<div>
<div ref="test">{{test}}</div>
<button @click="handleClick">点击</button>
</div>
</template>
<script>
export default {
data() {
return {
test: 'begin'
}
},
methods: {
handleClick () {
this.test = 'end';
console.log(this.$refs.test.innerText);//打印“begin”
}
},
components: {
},
computed: {
},
mounted() {
}
}
</script>
Напечатанный результат — начало.Почему мы явно устанавливаем тесту «конец», но innerText реального узла DOM получает не ожидаемый «конец», а предыдущее значение «начало»?
причина
Посмотрите реализацию исходного кода Vue.js. Когда реагирующие данные изменяются, его функция установки уведомляет Dep в замыкании, и Dep вызывает все объекты Watch, которыми он управляет. Запустите реализацию обновления объекта Watch. Давайте посмотрим на реализацию update.
update () {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true
} else if (this.sync) {
/*同步则执行run直接渲染视图*/
this.run()
} else {
/*异步推送到观察者队列中,下一个tick时调用。*/
queueWatcher(this)
}
}
Двусторонняя привязка данных для Vue
Vue — это инфраструктура MVVM, Проще говоря, привязка данных означает, что при изменении данных соответствующее представление будет обновлено, а при обновлении представления данные также будут изменены.
Существуют примерно следующие способы реализации привязки данных:
- 1、发布者-订阅者模式(backbone.js)
- 2、脏值检查(angular.js)
- 3、数据劫持(vue.js)
Vue.js реализован путем перехвата данных и объединения издатель-подписчик.Перехват данных использует ES5 Object.defineProperty(obj, key, val) для захвата установщика и получателя каждого свойства и публикации его, когда данные изменяют сообщение подписчику, которое запускает соответствующий обратный вызов для обновления представления.
Восемь, десять, шестнадцатеричное преобразование
двоичный → десятичный
Метод: двоичное число вычисляется от младшего к старшему (то есть справа налево), вес 0-й цифры равен 2 в 0-й степени, вес 1-й цифры равен 2 в 1-й степени, а вес второй цифры. Вторая степень числа 2 увеличивается по очереди, и значение, добавляемое к конечному результату, является десятичным значением.
例:将二进制的(101011)B转换为十进制的步骤如下:
1. 第0位 1 x 2^0 = 1;
2. 第1位 1 x 2^1 = 2;
3. 第2位 0 x 2^2 = 0;
4. 第3位 1 x 2^3 = 8;
5. 第4位 0 x 2^4 = 0;
6. 第5位 1 x 2^5 = 32;
7. 读数,把结果值相加,1+2+0+8+0+32=43,即(101011)B=(43)D。
восьмеричный → десятичный
Метод: восьмеричное число вычисляется от младшего к старшему (то есть справа налево), вес 0-й цифры равен 8 в 0-й степени, вес 1-й цифры равен 8 в 1-й степени, а вес второй цифры равно 8 в степени 2, увеличиваясь в свою очередь, значение, добавленное к конечному результату, является десятичным значением.
Восьмеричное означает, что каждая 8 вводится в 1, а восьмеричное число использует восемь цифр от 0 до 7 для выражения числа.
例:将八进制的(53)O转换为十进制的步骤如下:
1. 第0位 3 x 8^0 = 3;
2. 第1位 5 x 8^1 = 40;
3. 读数,把结果值相加,3+40=43,即(53)O=(43)D。
десятичный → двоичный
Метод: разделите на 2 и возьмите метод остатка, то есть целую часть делите на 2 каждый раз, остаток - это число на вес бита, а частное продолжает делить на 2, а остаток - это число по весу предыдущего бита этот шаг продолжается до тех пор, пока частное не станет равным 0, и при последнем чтении считывается от последнего остатка до первого остатка.
例:将十进制的(43)D转换为二进制的步骤如下:
1. 将商43除以2,商21余数为1;
2. 将商21除以2,商10余数为1;
3. 将商10除以2,商5余数为0;
4. 将商5除以2,商2余数为1;
5. 将商2除以2,商1余数为0;
6. 将商1除以2,商0余数为1;
7. 读数,因为最后一位是经过多次除以2才得到的,因此它是最高位,读数字从最后的余数向前读,101011,即(43)D=(101011)B。
Функция дросселирования и анти-встряски
Функция debounce (дебаунс)
Функция debounce debounce относится к функции, которая выполняется только в последний раз, независимо от того, сколько обратных вызовов запускается в течение определенного периода времени. Если мы установим функцию с временем ожидания 3 секунды, если в течение этих 3 секунд будет обнаружен запрос на вызов функции, таймер будет переустановлен на 3 секунды, пока в течение новых 3 секунд не будет запроса на вызов функции, затем функция в это время будет выполняться, иначе будет выводиться и т. д. Retime.
Сценарии применения:
Пользователям необходимо постоянно вводить значения, например, заполнять форму ввода или вводить что-то в поле поиска.
Когда пользователь постоянно выполняет операции переключения страниц вкладок.
Принцип и реализация:
Принцип реализации заключается в использовании таймера, при первом выполнении функции устанавливается таймер, при последующем вызове функции обнаруживается, что таймер был установлен, а предыдущий таймер очищается, и новый таймер сбрасывается.Опустошенный таймер запускает выполнение функции, когда таймер истекает.
function debounce(fn,delay) {
let timer;
return function () {
var context = this; //保存当前this指向当前对象
var args = arguments; //获取隐式传入的参数
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
}
}
функция дроссельной заслонки
规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效,
即每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作
Сценарии применения
Прокрутите вверх, чтобы загрузить, прокрутите вниз, чтобы обновить.
негабаритный, mousemove, mousehover.
Есть также события перетаскивания и так далее.
function throttle(fn,delay) {
let timer = null;
return function () {
var context = this; //保存当前this指向当前对象
var args = arguments; //获取隐式传入的参数
if(timer == null){
timer = setTimeout(() => {
fn.apply(context,args)
}, delay);
}
}
}
Суммировать :
- Anti-shake — это превращение нескольких исполнений в последнее исполнение
- Дросселирование — это преобразование нескольких выполнений в обычные выполнения.
Последовательность Фибоначчи
Последовательность Фибоначчи также называют последовательностью золотого сечения, также известной как последовательность кролика.
Принцип: Предположим, что пара больших крольчат может рождать пару маленьких крольчат каждый месяц, и каждая пара новорожденных маленьких крольчат может вырасти в пару больших крольчат через месяц Сколько существует пар крольчат?
| месяц | Ситуация с кроликом | Всего |
|---|---|---|
| Месяц 0 | а (маленький кролик) | 1 |
| 1-й месяц | а (с репродуктивной способностью) | 1 |
| 2-й месяц | б (Шэн Ла Шэн Ла) + а (его родители) | 2 |
| 3-й месяц | б (2 рожденных в мае обладают способностью к размножению, это чешется) + б2 (его родители родили второго ребенка) + а (его родители) | 3 |
| 4-й месяц | c (кролик b в феврале счастлив быть отцом) + b (кролик, родившийся в феврале) + b2 (второй ребенок оплодотворен и готов родить) + a (его родители) + d (у a есть третий ребенок) | 5 |
| … | … | … |
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89...
Итак, правило такое: fn(n)=fn(n-1)+fn(n-2)
Итеративный способ
/*
*i 月份
*/
function fn(i){
var a=[];
/*0个月什么都不存在*/
a[0]=0;
a[1]=1;
for(var j = 2; j<= i;j++){
a[j]=a[j-1] + a[j-2];
}
return a[i]
}
рекурсивный путь
/*
* i 月份
*/
function fn(i){
if(i < 2){return i === 0 ? 0 : 1;}
return fn(i-1)+fn(i-2)
}
Резюме: в этом примере рекурсия будет делать слишком много вызовов (больше, чем итерация), поэтому производительность приносится в жертву краткости.
Принцип реализации Vue-маршрутизатора
Это вопрос интервью от Али
Основная причина: обновить представление без повторного запроса страницы.
Vue-router реализует одностраничные переходы маршрутизации и предоставляет три метода: хэш-режим, режим истории и абстрактный режим.Какой метод использовать, определяется в соответствии с параметром режима.
режим маршрутизации
vue-router предоставляет три режима работы:
hash: Используйте хеш-значение URL-адреса для маршрутизации. Режим по умолчанию.
история: зависит от HTML5 History API и конфигурации сервера. Проверьте режим истории HTML5.
abstract: поддерживает все среды выполнения JavaScript, такие как серверная часть Node.js.
Хэш-режим:
Хэш — это содержимое после # в URL-адресе браузера, включая #. Хэш — это точка привязки в URL-адресе, представляющая позицию на веб-странице. Если часть после # изменится, браузер загрузит только содержимое соответствующей позиции и не перезагрузит страницу.
то есть
То есть # используется для управления действиями браузера и совершенно бесполезен для серверной части HTTP-запрос не содержит #.
Каждый раз, когда вы меняете часть после #, в историю доступа браузера будет добавляться запись, и вы сможете вернуться на предыдущую позицию с помощью кнопки «назад».
Поэтому режим Hash отображает разные данные в указанном месте DOM в соответствии с разными значениями, изменяя значение привязки.
Режим истории:
API истории HTML5 предоставляет функцию, которая позволяет разработчикам изменять URL-адрес сайта без обновления всей страницы, то есть использовать API history.pushState для завершения перехода по URL-адресу без перезагрузки страницы;
Поскольку режим хеширования будет иметь свой собственный # в URL-адресе, если мы не хотим уродливого хэша, мы можем использовать режим маршрутизации истории, просто добавьте «режим:« история »» при настройке правил маршрутизации, этот режим полностью использует истории .pushState API для выполнения перехода по URL-адресу без перезагрузки страницы.
Иногда также возникает проблема в режиме истории:
например:
В режиме хеширования: xxx.com/#/id=5 Адрес запроса xxx.com, проблем нет.
В режиме истории: xxx.com/id=5 Адрес запроса xxx.com/id=5, если на бэкенде нет соответствующей обработки маршрутизации, будет возвращена ошибка 404;
Чтобы справиться с этой ситуацией, требуется поддержка конфигурации бэкэнда:
Добавьте ресурс-кандидат, который охватывает все случаи на стороне сервера: если URL-адрес не соответствует ни одному из статических ресурсов, он должен возвращать ту же страницу index.html, от которой зависит ваше приложение.
абстрактный режим:
Абстрактный режим заключается в использовании независимого от браузера виртуального управления историей просмотров.
В соответствии с различиями платформ в среде Weex поддерживается только абстрактный режим. Однако vue-router сам проверит среду.Если он обнаружит, что API браузера отсутствует, vue-router автоматически заставит его войти в абстрактный режим, поэтому при использовании vue-router, пока вы не напишете режим, он будет просматривать по умолчанию.Хеш-режим используется в серверной среде, а абстрактный режим используется в мобильной среде. (Конечно, вы также можете явно указать, что абстрактный режим используется во всех случаях).
Шаблон наблюдателя
Асинхронное программирование
Асинхронно и ждать
async — сделать метод асинхронным.
await — дождаться завершения выполнения асинхронного метода.
Примечание: await необходимо использовать в асинхронных методах, потому что сам доступ к await приведет к остановке и блокировке программы, поэтому его необходимо использовать в асинхронных методах.
При использовании синтаксиса ожидания следующая функция должна возвращать объект Promise.
async test1() {
let result = await this.$http.get('/api/job',{})
console.log(result)
}
10 лучших классических алгоритмов сортировки
Пузырьковая сортировка:
Сравните два элемента, больший расположен сзади, как пузырьки в воде, больший плавает на поверхности воды.
Ссылаться на:nuggets.capable/post/684490…
function bubble(arr) {
for(var i = 0; i < arr.length; i++) {
for(var j = 0; j < arr.length - 1- i; j++) {
if(arr[j] > arr[j + 1]) {
var max = arr[j];
arr[j] = arr[j+1];//交换数据
arr[j+1] = max;//交换数据
}
}
}
console.log(arr)
}
bubble([1,4,6,2,7,2])// [1, 2, 2, 4, 6, 7]
Быстрая сортировка:
Возьмите элемент в качестве эталона, разделите последовательность на две части, поместите тот, который меньше эталона, слева от него, и поместите тот, который больше или равен ему, справа, а затем разделите подпоследовательность слева и справа, как описано выше. до тех пор, пока подпоследовательность не может быть снова разделена (менее 2 элементов), и, наконец, добиться порядка всей последовательности
function quickSort(arr) {
if(arr.length < 2) {
return arr;
} else {
const pivot = arr[0]; // 基准值
const pivotArr = []; // 一样大的放中间
const lowArr= []; // 小的放左边
const hightArr = []; // 大的放右边
arr.forEach(current => {
if(current === pivot) pivotArr.push(current);
else if(current > pivot) hightArr.push(current);
else lowArr.push(current);
})
return quickSort(lowArr).concat(pivotArr).concat(quickSort(hightArr));
}
}
console.log(quickSort([4,6,2,3,1,5,7,8])) // [1, 2, 3, 4, 5, 6, 7, 8]
Простая сортировка выбором:
Сначала найдите наименьший (самый большой) элемент в несортированной последовательности и сохраните его в начале отсортированной последовательности.
Продолжайте находить наименьший (самый большой) элемент из оставшихся несортированных элементов и помещать его в конец отсортированной последовательности.
Повторяйте шаг 2, пока все элементы не будут отсортированы.
const selectionSort = array => {
const len = array.length;
let minIndex, temp;
for (let i = 0; i < len - 1; i++) {
minIndex = i;
for (let j = i + 1; j < len; j++) {
if (array[j] < array[minIndex]) {
// 寻找最小的数
minIndex = j; // 将最小数的索引保存
}
}
temp = array[i];
array[i] = array[minIndex];
array[minIndex] = temp;
console.log('array: ', array);
}
return array;
};
selectionSort([6,4,3,8])//[3, 4, 6, 8]
асинхронно и отложить
Существует три вида асинхронной загрузки js: defer, async, динамическое создание тегов script, асинхронная загрузка js по запросу.
async : загружать файлы сценариев параллельно, интерпретировать и выполнять код сразу после загрузки и не будет выполняться в порядке выполнения сценариев на странице.
defer : параллельно загружается js, он будет выполняться в порядке следования тегов скрипта на странице, а затем скрипт будет выполняться после парсинга документа
Тот же момент между отсрочкой и асинхронностью заключается в том, что используется параллельная загрузка, и в процессе загрузки нет блокировки. Разница заключается во времени выполнения: Async выполняется автоматически после загрузки, а defer должен дождаться завершения страницы.
Разобрать:
<script src="script.js"></script>
Без отсрочки или асинхронности браузер загрузит и выполнит указанный скрипт немедленно. «Немедленно» означает, что перед рендерингом элемента документа под тегом script, то есть он не ждет следующего загруженного элемента документа, а загружает его как как только он будет прочитан и выполнен.
<script async src="script.js"></script>
При использовании асинхронности процесс загрузки и рендеринга последующих элементов документа будет происходить параллельно (асинхронно) с загрузкой и выполнением script.js.
<script defer src="myscript.js"></script>
С defer процесс загрузки последующих элементов документа будет выполняться параллельно (асинхронно) с загрузкой script.js, но выполнение script.js будет завершено после парсинга всех элементов и до запуска события DOMContentLoaded.
Событие Load запускается, чтобы указать, что DOM, CSS, JS и изображения на странице загружены. Событие DOMContentLoaded запускается, чтобы указать, что исходный HTML-код полностью загружен и проанализирован без ожидания загрузки CSS, JS и изображений.
Использование методов call, apply, bind
call и apply, похоже, динамически изменяют это.Когда у объекта нет определенного метода, но есть у других, мы можем использовать call или apply для работы с методами других объектов.
知乎简单易懂答案:
猫吃鱼狗吃肉,奥特曼打怪兽
有一天,狗想吃鱼了
猫.吃鱼.call(狗,鱼)
狗就吃到鱼了
猫成精了,想打怪兽
奥特曼.打怪兽.call(猫,小怪兽)
obj.call(thisObj, arg1, arg2, ...)
obj.apply(thisObj, [arg1, arg2, ...])
两者作用一致,都是把obj(即this)绑定到thisObj,这时候thisObj具备了obj的属性和方法。
或者说thisObj继承了obj的属性和方法。唯一区别是apply接受的是数组参数,call接受的是连续参数。
пример:
var obj1 = {
value: 1
}
function say() {
console.log(this.value)
}
say() // 输出undefined
say.call(obj1) // 输出1
Обратите внимание на два момента:
вызов меняет точку этого, на этот раз указывает на obj1
говорят, что функция выполняется
Специфика метода связывания:
Причина, по которой метод привязки выпускается отдельно, заключается в том, что метод привязки сильно отличается от двух предыдущих, хотя оба динамически изменяют значение this, например
var obj = {
x: 81,
};
var foo = {
getX: function() {
return this.x;
}
}
console.log(foo.getX.bind(obj)()); //81
console.log(foo.getX.call(obj)); //81
console.log(foo.getX.apply(obj)); //81
Вы заметили, что при использовании метода bind необходимо добавить пару круглых скобок, потому что использование bind только возвращает соответствующую функцию, а не выполняет ее сразу, в то время как методы call и apply выполняются сразу
Существует разница между связыванием, вызовом и применением. Когда функция вызывается, она вызывается напрямую, но связывание возвращает функцию. Когда функция выполняется, первый параметр связывания () будет использоваться в качестве времени ее выполнения. это.
Вручную реализовать метод привязки
Ссылка на ссылкусегмент fault.com/ah/119000001…
Полное имя метода привязки: Function.prototype.bind().
Давайте сначала посмотримbindОпределение метода:
bindметод создает новую функцию. Когда эта новая функция вызывается,bindПервый аргумент будет использоваться в качестве времени выполнения.this(Этот параметр нельзя переопределить), следующая последовательность параметров будет передана в качестве аргументов перед переданными аргументами.
Также можно использовать новые функцииnewоператора для создания объекта: такое поведение похоже на обращение к исходной функции как к конструктору, обеспечивающемуthisзначение игнорируется.
Что вы наделали:
- возвращает новую функцию
- привязать ключевое слово this (переданный параметр) к объединению параметров функции,
- Объедините параметры функции привязки с исходными параметрами функции и передайте их в качестве параметров новой созданной функции.
- вернуть функцию
предварительные идеи
- потому что
bindМетод не является функцией немедленного выполнения, он должен возвращать функцию для выполнения, здесь вы можете использовать замыкание:return function(){}; - Привязки с ограниченной областью: вы можете использовать
applyилиcallметод достижения; - Передача параметров: Из-за неопределенности параметров необходимо использовать
applyпередать массив;
Function.prototype.mybind = function(context){
//只能对函数执行bind方法
if (typeof this !== "function") {
throw new TypeError(this + ' must be a function');
}
let self = this;
/**
* 由于参数的不确定性,我们用 arguments 来处理
* 这里的 arguments 只是一个类数组对象,可以用数组的 slice 方法转化成标准格式数组
* 除了作用域对象 self 以外,后面的所有参数都需要作为数组进行参数传递
* 获取除第一个以外的参数,第一个参数是上下文,其它才是真正的参数。
*/
var args = Array.prototype.slice.call(arguments, 1);
// 利用一个空函数作为中转
let tempFn = function() {};
var resultFn = function () {
// 将新函数执行时的参数 arguments 全部数组化,然后与绑定时传参 arg 合并
var innerArgs = Array.prototype.slice.call(arguments);
// 如果 返回函数被当做构造函数后,生成的对象是 tempFn 的实例,此时应该将 this 的指向指向创建的实例。
// 如果是new操作符实例出来对象,则为this。
// 如果是直接执行方法,则为context
if (this instanceof tempFn) {
return self.apply(this, args.concat(innerArgs));
} else {
return self.apply(context, args.concat(innerArgs))
}
}
// 中转原型链
// 让返回函数拥有bind函数的原型。
// 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值
tempFn.prototype = self.prototype;
resultFn.prototype = new tempFn();
return resultFn;
}
var testFn = function(obj, arg) {
console.log('作用域对象属性值:' + this.value);
console.log('绑定函数时参数对象属性值:' + obj.value);
console.log('调用新函数参数值:' + arg);
}
var testObj = {
value: 1
};
var newFn = testFn.mybind(testObj, {value: 2});
newFn('hello world');
// 作用域对象属性值:1
// 绑定函数时参数对象属性值:2
// 调用新函数参数值:hello world
Произнесите следующую распечатку
let a = {a: 10};
let b = {b: 10};
let obj = {
a: 10
};
obj[b] = 20;
obj["c"] = 20;
console.log(obj[a]);
console.log(obj)
// 20
//{a: 10, [object Object]: 20, c: 20}
obj[b] = 20После операции присваивания ,objФактически, это стало{a: 10, [object Object]: 20}, это связано с тем, что если выражение имени свойства является объектом, оно автоматически преобразует объект в строку по умолчанию.[object Object], последний шаг, чтобы получитьobj[a], сам по себе также является объектом, поэтому он будет преобразован для полученияobj['[object Object]']То есть 20 назначенных на предыдущем шагеЖизненный цикл Vue
beforeCreate:
Элемент монтирования el экземпляра vue и данные объекта данных не определены и не были инициализированы.
created:
Создание экземпляра завершено, данные объекта данных экземпляра vue доступны, а el еще нет. И были завершены следующие конфигурации: наблюдатель данных, операции со свойствами и методами, обратные вызовы событий наблюдения/события.
На этом этапе вы можете вызывать методы, определенные в методах, изменять данные данных и запускать ответные изменения, пересчитывать вычисленные значения, следить за изменениями и т. д.
Он не был смонтирован в DOM, атрибут $el недоступен, а содержимое атрибута $ref представляет собой пустой массив.
beforeMount:
$el и данные экземпляра vue инициализируются, но до монтирования они остаются виртуальными узлами dom, а data.message не заменяется.
mounted:
Экземпляр монтируется в DOM. В это время DOM-узел можно получить через DOM API, получить доступ к атрибуту $ref и успешно отобразить data.message.
beforeUpdate:
Объектом обновления здесь является шаблон, то есть виртуальный DOM необходимо перерендерить и исправить.
Если в шаблоне не используются измененные данные (в том числе прямые и непрямые, непрямые: например, в шаблоне используется вычисляемое свойство, которое зависит от данных), процесс обновления не будет инициирован! ! !
updated:
Хук будет вызываться после рендеринга виртуального DOM и исправления, вызванного изменениями данных.
Когда этот хук вызывается, компонент DOM был обновлен, и операции, зависящие от DOM, могут выполняться.
beforeDestroy:
Вызывается перед уничтожением экземпляра. На этом этапе экземпляр все еще полностью доступен, и он все еще может получить экземпляр.
Как правило, этот шаг выполняется: уничтожение таймеров, отвязка глобальных событий, уничтожение объектов плагинов и т. д.
destroyed:
Вызывается после уничтожения экземпляра Vue. После вызова все, на что указывает экземпляр Vue, будет развязано, все прослушиватели событий будут удалены, а все дочерние экземпляры будут уничтожены.
Закрытие
Ссылаться на https://segmentfault.com/a/1190000000652891
Замыкания — это функции, которые могут читать переменные внутри других функций. Поскольку в языке Javascript только подфункции внутри функций могут читать локальные переменные, замыкания можно просто понимать как «функции, определенные внутри функции».
Чтобы понять замыкания, вы должны сначала понять область действия специальных переменных JavaScript.
Область видимости переменных не более чем две: глобальные переменные и локальные переменные.
Особенность языка Javascript в том, что глобальные переменные можно читать непосредственно внутри функции.
var n = 999;
function f() {
console.log(n)
}
f(); // 999
С другой стороны, локальные переменные внутри функции не могут быть естественным образом прочитаны вне функции.
function f() {
var n= 999;
}
console(n); //Uncaught ReferenceError: n is not defined
Здесь следует отметить одну вещь: при объявлении переменных внутри функции обязательно используйте команду var. Если вы ее не используете, вы фактически объявляете глобальную переменную!
function f() {
n = 999;
}
f();
console.log(n); // 999
По разным причинам нам иногда нужно получить локальные переменные внутри функции. Однако, как было сказано ранее, в обычных условиях это невозможно и может быть достигнуто только с помощью обходных путей.
То есть внутри функции определите другую функцию.
function f1() {
var n = 999;
function f2(){
console.log(n); // 999
}
}
В приведенном выше коде функция f2 включена в функцию f1, и все локальные переменные внутри f1 видны f2. Но не наоборот, локальные переменные внутри f2 невидимы для f1. Это уникальная структура «цепной области» языка Javascript,
Дочерний объект поднимается на один уровень вверх в поисках всех переменных родительского объекта. Поэтому все переменные родительского объекта видны дочернему объекту, но не наоборот.
Поскольку f2 может читать локальные переменные в f1, пока f2 используется в качестве возвращаемого значения, не можем ли мы прочитать его внутренние переменные вне f1!
function f1() {
n = 999;
function f2(){
console.log(n);
}
return f2;
}
var result=f1();
result();// 999
Затворы можно использовать во многих местах. У него есть два основных применения: одно — чтение переменных внутри упомянутой выше функции, а другое — сохранение значений этих переменных в памяти.
function f1() {
var n = 999;
nAdd = function() {
n += 1
}
function f2() {
console.log(n);
}
return f2;
}
var result = f1();
result(); // 999
nAdd();
result(); // 1000
В этом коде результатом является замыкающая функция f2. Он запускался дважды, первый раз со значением 999 и второй со значением 1000. Это доказывает, что локальная переменная n в функции f1 хранится в памяти и не очищается автоматически после вызова f1.
Почему это так? Причина в том, что f1 является родительской функцией f2, а f2 присваивается глобальной переменной, из-за чего f2 всегда находится в памяти, а существование f2 зависит от f1, поэтому f1 всегда находится в памяти, а не после вызова заканчивается. , собранный механизмом сборки мусора (garbage collection).
Еще одним примечательным местом в этом коде является строка "nAdd=function(){n+=1}" Прежде всего, ключевое слово var не используется перед nAdd, поэтому nAdd является глобальной, а не локальной переменной. Во-вторых, значение nAdd является анонимной функцией, и это
Сама анонимная функция также является замыканием, поэтому nAdd эквивалентен сеттеру, который может работать с локальными переменными внутри функции вне функции.
Функции:
1. Вложенная функция функции
2. Функции могут ссылаться на внешние параметры и переменные
3. Параметры и переменные не будут перерабатываться механизмом сборки мусора
Недостатком замыканий является то, что они находятся в памяти, что увеличивает объем используемой памяти, а неправильное использование может легко привести к утечке памяти.
Зачем использовать замыкания:
Чтобы спроектировать частные методы и переменные, избегайте загрязнения глобальных переменных. Надейтесь, что переменная находится в памяти в течение длительного времени.
Дедупликация массива
Воспользуйтесь преимуществом свойства indexOf массива
let arr = [5,7,8,8]
console.log(arr.indexOf(5))//0
console.log(arr.indexOf(8))//2
console.log(arr.indexOf(9))//-1
function unique(origin) {
var result = [];
for (var i = 0; i < origin.length; i++) {
var item = origin[i];
if (result.indexOf(item) === -1) {
result.push(item);
}
}
return result;
}
console.log(unique(arr))//[5, 7, 8]
Фильтр массива и свойства indexOf
let arr = [5,7,8,8]
function unique(origin) {
var result = origin.filter(function(item, index, array) {
// 获取元素在源数组的位置,只返回那些索引等于当前元素索引的值。
return array.indexOf(item) === index;
});
return result;
}
console.log(unique(arr))//[5, 7, 8]
Используйте наборы ES6
ES6 предоставляет новую структуру данных Set, которая похожа на массив, но значения членов уникальны и в них нет повторяющихся значений. При добавлении значений в Set преобразование типов не происходит, поэтому 5 и ‘5’ — это два разных значения. Set внутренне определяет, являются ли два значения одинаковыми, используя алгоритм, аналогичный "===", но разница в том, что NaN считается равным NaN внутри набора
let arr = [5,7,8,8]
function unique(origin) {
return Array.from(new Set(origin));
}
console.log(unique(arr))//[5, 7, 8]
коробочная модель
Во-первых, блочная модель состоит из четырех частей: содержимого, заполнения, границы и поля.
Категория: стандартная блочная модель и т.е. блочная модель
разница:
- В стандартной блочной модели ширина и высота относятся к ширине и высоте области содержимого. Увеличение заполнения, границ и полей не повлияет на размер области содержимого, но увеличит общий размер блока элемента.
- В блочной модели IE ширина и высота относятся к ширине и высоте области содержимого + границы + заполнения.
Но теперь он унифицирован
<!DOCTYPE html>
CSS3 предоставляет свойство, которое может переключать режим модели блока: box-sizing, который имеет 2 значения, content-box и border-box.
поле содержимого:
Пусть элемент поддерживает стандартную блочную модель W3C. Ширина/высота элемента определяется шириной/высотой границы + отступа + содержимого.Установка атрибута ширины/высоты относится к ширине/высоте части содержимого.
border-box:
Пусть элемент поддерживает традиционную блочную модель IE (IE6 и ниже и странный режим IE6~7). Установка свойства ширины/высоты относится к границе + отступу + содержимому
Что происходит после того, как браузер вводит URL-адрес и нажимает Enter
Ссылаться на Если сломался.top/2019/04/11/…
1. Выполните преобразование доменного имени DNS на веб-сайте www.baidu.com, чтобы получить соответствующий IP-адрес.
2. По этому IP найти соответствующий сервер и инициировать трехстороннее рукопожатие TCP
3. После установления TCP-соединения инициируйте HTTP-запрос.
4. Сервер отвечает на HTTP-запрос, и браузер получает html-код
5. Браузер анализирует html-код и запрашивает ресурсы в html-коде (такие как js, css картинки и т. д.) (html-код может быть найден до того, как эти ресурсы могут быть найдены)
6. визуализация страницы браузера, представленная пользователю
Три основных процесса:
- разрешение DNS
- TCP-соединение
- HTTP-запрос/ответ
Последний шаг важен для внешнего интерфейса. Как браузер отображает страницу?
a: разобрать html-файл, чтобы сформировать дерево DOM,
b: анализ файлов CSS для формирования дерева рендеринга,
c: синтаксический анализ, рендеринг,
d: JS работает в одном потоке, и JS может изменять структуру DOM, что означает, что нет необходимости загружать все последующие ресурсы до завершения выполнения JS, поэтому JS является одним потоком и будет блокировать последующие загрузки ресурсов.
Чем именно занимается новый оператор?
function Animal(name) {
this.name = name;
}
Animal.prototype.run = function() {
console.log(this.name + 'can run...');
}
var cat = new Animal('cat');
cat.run() //catcan run...
console.log(cat.__proto__ === Animal.prototype); // true
newВсего было испытано четыре процесса.
var fn = function () { };
var fnObj = new fn();
1. Создайте пустой объект
var obj = new object();
2. Настройте цепочку прототипов
obj._proto_ = fn.prototype;
3. Пусть this функции fn указывает на obj и выполняет тело функции fn.
var result = fn.call(obj);
4. Определите тип возвращаемого значения fn.Если это тип значения, верните obj. Если это ссылочный тип, возвращается объект этого ссылочного типа.
if (typeof(result) == "object"){
fnObj = result;
} else {
fnObj = obj;
}
Символы, карты и наборы
Ссылаться на blog.CSDN.net/Xiaozhuzhu2222/art…
Зачем вам Символ:
Введение нового правила должно быть связано со спросом. Люди, знакомые с ES5, знают, что имена свойств объектов в ES5 являются строками. Если вам нужно использовать объект, предоставленный другими, вы не очень уверены в свойствах этого объекта. Ясно, но вы хотите добавить некоторые свойства к этому объекту, тогда новое имя свойства, вероятно, будет конфликтовать с исходным именем свойства, очевидно, мы не хотим, чтобы это произошло. Поэтому нам необходимо убедиться, что каждое имя свойства уникально, чтобы предотвратить конфликты имен свойств. Поэтому Symbol был представлен в ES6 и использовался для создания уникального значения.
Что такое Символ:
Символ на самом деле является примитивным типом данных, представленным ES6.В дополнение к символу, JavaScript имеет пять других типов данных, а именно: Undefined, Null, Boolean, String и Number.Все эти пять типов данных доступны в ES5.
Как сгенерировать значение типа Symbol:
Теперь, когда мы знаем, что Symbol — это примитивный тип данных, как нам генерировать значения этого типа данных? Значение Symbol генерируется функцией Symbol следующим образом:
let s = Symbol();
console.log(s); // Symbol()
typeof s; // "symbol"В приведенном выше коде s — это уникальное значение типа Symbol.
new нельзя использовать перед функцией Symbol
Функция Symbol не является конструктором, и перед ней нельзя использовать оператор new. Таким образом, значение типа Symbol не является объектом, не может добавлять никаких свойств, это просто тип данных, аналогичный символьному типу. Если вы принудительно добавите новый оператор перед функцией Symbol, будет сообщено об ошибке следующим образом:
let s = new Symbol();// Uncaught TypeError: Symbol is not a constructor(…)
Параметры функции Символ
1. Строка как параметр
Значение символа, сгенерированное вышеуказанным методом, нелегко отличить.Функция символа также может принимать строковый параметр для описания сгенерированного значения символа, что нам удобно для различения разных значений символа.
let s1 = Symbol('s1');
let s2 = Symbol('s2');
console.log(s1); // Symbol(s1)
console.log(s2); // Symbol(s2)
s1 === s2; // false
let s3 = Symbol('s2');
s2 === s3; // false
Как видно из кода выше:
- После добавления параметров в функцию Symbol вывод консоли может различать, какое это значение;
- Параметр функции Symbol является только описанием текущего значения Symbol, поэтому возвращаемое значение функции Symbol с тем же параметром не равно;
2. Объект как параметр
Если параметр функции Symbol является объектом, вызывается метод объекта toString для преобразования его в строку, а затем генерируется значение Symbol. Так ведь параметры функции Symbol могут быть только строками.
установить сбор данных: аналогично массиву
set: это набор, похожий на массив, основное отличие массива в том, что в нем нет повторяющихся элементов. Основную роль может играть дедупликация.
Ключевой момент: одно свойство, четыре метода
1. Свойство size: возвращает длину заданного массива, аналогичную длине.
2. Четыре метода: добавить, удалить, очистить, имеет
let set =new Set([1,2,3,4,1]);
console.log(set.size); //4
//添加元素
set.add(7);
console.log(set); // {1, 2, 3, 4, 7}
//删除数组中的某个元素
set.delete(3);
console.log(set); // {1, 2, 4, 7}
//检测数组中是否含有某个元素,返回值为布尔
console.log(set.has(2)); //true
//清空数组
set.clear();
console.log(set) //{}
сбор картографических данных: аналогично объектам
let obj={a:1};
const map = new Map([
['name','java'],
['feel','今天天气贼好'],
['jieguo','适合看帅哥'],
[obj,'是!']
]);
console.log(map);//{"name" => "java", "feel" => "今天天气贼好", "jieguo" => "适合看帅哥", {…} => "是!"}
Разница между картой и объектом
1. Атрибут размера карты может напрямую получить количество пар ключ-значение.
2. Оба являются соответствующими парами ключ-значение,
Но ключи объекта могут быть только строками или символами,
Ключ Map может быть любым значением, таким как массив, объект и т.д.
Резюме: Объекты карты содержат пары ключ-значение. Ключи объекта могут быть только строками или символами, но ключи карты могут быть любыми значениями. Объект Set позволяет хранить уникальные значения любого типа. Объект Set представляет собой набор значений. Элемент в наборе появляется только один раз. Символ — это специальный неизменяемый тип данных, который можно использовать в качестве идентификатора. для свойства объекта (Символ(Символ([описание]) )
Классы в JavaScript
Объявление класса:
Используйте ключ класса, чтобы объявить класс
class Person {
// 相当于Person构造函数
constructor (name) {
this.name = name
}
// 相当于Person.prototype.sayName
sayName () {
console.log(this.name)
}
}
const person = new Person('AAA')
person.sayName() // AAA
console.log(person instanceof Person) // true
console.log(person instanceof Object) // true
Экспорт класса как части модуля ES2015
синтаксис по умолчанию
export default class Person {
// The body of class
}
или именованный экспорт
export class Person {
// The body of class
}
анализировать:
1) конструктор (): мы видим, что метод конструктора () эквивалентен конструктору Person, который мы написали выше, В методе конструктора () мы определяем собственное свойство имени. Так называемые собственные свойства — это свойства экземпляра класса.Он не отображается в прототипе и может быть создан только в конструкторе или методе класса..
2) sayName(): метод sayName() эквивалентен описанному выше Person.prototype.sayName. Следует отметить особый момент: в отличие от функций, свойствам класса нельзя присваивать новые значения, например, Person.prototype является таким свойством класса, доступным только для чтения.
статический элемент статический
Как следует из названия, это означает статический метод, а класс эквивалентен прототипу экземпляра, все методы, определенные в классе, будут унаследованы экземпляром. Если ключевое слово static добавлено перед методом, это означает, что метод не будет унаследован экземпляром, а будет вызываться непосредственно через класс, который называется «статическим методом». Вызовы статических методов выполняются непосредственно в классе и не могут вызываться в экземплярах класса. Статические методы часто используются для создания служебных/служебных функций. В ES6 синтаксис класса упрощает процесс создания статических членов за счет использования формальной статической аннотации static перед именем метода или свойства средства доступа.
Примечание. Доступ к статическим членам возможен только в классе, а не в экземпляре.
class Person {
constructor (name) {
this.name = name
}
sayName () {
console.log(this.name)
}
static create (name) {
return new Person(name)
}
}
const person = Person.create('AAA')
person.sayName() // AAA
Наследовать расширения
class Person {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name)
}
}
class Child extends Person {
constructor(name) {
super(name); // 相当于 Person.call(this)
this.name = name;
}
}
let c1 = new Child("aaa")
c1.speak(); // aaa
Как написать эс5
function Person(name){
this.name = name
}
Person.prototype.speak = function(){
console.log(this.name);
}
function Child(name){
Person.call(this);
this.name = name;
}
Child.prototype = Object.create(Person.prototype);
Child.prototype.constructor = Child;//因为上一步造成constructor为Animal
//或者可以把上边的两行改成下面这样的写法
Child.prototype = Object.create(Person.prototype, {
constructor: Child,
});
Уведомление
Существует два варианта использования super в наследовании классов.
- Используется как функция, как super() в приведенном выше примере.
- Когда super используется как объект, в обычных методах он указывает на объект-прототип родительского класса; в статических методахуказать на родительский класс.
Использовать как функцию:
class Child extends Person {
constructor(name) {
super(name);
this.name = name;
}
}
Использовать в качестве объекта:
class Person {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name)
}
}
Person.prototype.name ="bbbb"
class Child extends Person {
constructor(name) {
super();
this.name = name;
console.log(super.name) // bbb
}
}
let c1 = new Child("aaa")
c1.speak(); // aaa
Укажите на родительский класс в статическом методе
class Person {
constructor(name) {
this.name = name;
}
static speak() {
console.log(111)
}
}
class Child extends Person {
constructor() {
super();
}
static say(name) {
super.speak()
}
}
let c1 = new Child();
Child.say(111); // 111
Обработка массива Vue
<template>
<div>
{{list[2]}}
</div>
</template>
<script>
export default {
data() {
return {
list: [1,3,5]
}
},
methods: {
},
components: {
},
computed: {
},
mounted() {
this.list[2] = 8 // 没有效果
this.$set(this.list, 2, 8); //有效果
}
}
</script>
Объяснение метода set:
this.$set(массив или объект, измененный индекс или имя свойства объекта, измененное значение)
GET,POST,PUT,Delete
Запрос GET будет получать информацию из базы данных, он используется только для запроса данных и не будет изменять или добавлять данные. Используйте URL для передачи параметров, существует ограничение на количество отправляемых, как правило, 2000 символовРазница между GET и POST:
1.GET использует URL или Cookie для передачи параметров, в то время как POST помещает данные в BODY, это связано с соглашением об использовании протокола HTTP. Не их собственное отличие.
2. Данные, отправляемые методом GET, имеют ограничение по длине, а данные POST могут быть очень большими из-за разницы, вызванной разными операционными системами и настройками браузера, которые они используют. И это не разница между GET и POST как таковыми.
3. POST безопаснее, чем GET, потому что данные не видны в адресной строке.В этом утверждении нет ничего плохого, но это все же не разница между GET и POST.
4. Самая большая разница между GET и POST заключается в том, что запросы GET являются идемпотентными, а запросы POST — нет. (Идемпотентность: несколько запросов к одному и тому же URL-адресу должны возвращать один и тот же результат.) Поскольку запросы на получение являются идемпотентными, в туннелях с плохими сетями будут предприняты повторные попытки. Если вы используете запрос на получение для увеличения данных, существует риск повторения операции, и эта повторяющаяся операция может вызвать побочные эффекты.
Функция ловушки vue router
1. Глобальные хуки
beforeEach (to, from, next) (глобальная передняя защита) Перед загрузкой страницы
- to: цель, которая вот-вот войдет
- from: маршрут, по которому уходит текущая навигация
- далее: функция функция, должна быть вызвана
Выполнять переходы между страницами, например, определять, нужно ли перехватывать страницу входа.
afterEach(to, from, next) (глобальный после гвардии) После загрузки страницы есть два параметра: to/from.Глобальные пост-хуки вызываются в конце всех роутинг-джампов.Эти хуки не будут принимать следующую функцию и не изменят саму навигацию.
Vue Mar Router.beeforeresolve (Глобальная охрана разрешения)Примечание: beforeEach и afterEach являются свойствами объекта экземпляра vue-router, перед каждым переходом будут выполняться beforeEach и afterEach.
2. Хуки навигации в компоненте:
beforeRouteEnter, beforeRouteUpdate, beforeRouteLeave, определенные непосредственно внутри компонента маршрутизации
beforeRouteEnter(to, from, next) :
Соответствующий маршрут, который отображает компонент,确认Перед вызовом использование и параметры аналогичны beforeEach,следующий должен быть активно вызван
Уведомление:
- На данный момент экземпляр компонента не создан и не может получить доступ к этому
- Доступ к экземплярам компонента можно получить, передав обратный вызов next. Выполните обратный вызов, когда навигация будет подтверждена, и передайте экземпляр компонента в качестве параметра метода обратного вызова.
beforeRouteEnter (to, from, next) {
// 这里还无法访问到组件实例,this === undefined
next( vm => {
// 通过 `vm` 访问组件实例
})
}
- Вы можете запросить у сервера получение данных в этом гарде, когда он будет успешно получен и сможет войти в маршрут, вызовите next и передайте его в обратном вызове
vmДоступ к экземплярам компонентов для назначения и других операций - beforeRouteEnter срабатывает перед подтверждением навигации и созданием экземпляра компонента: до beforeCreate; а вызов функции в next выполняется после монтирования: для обеспечения полного доступа к экземпляру компонента
beforeRouteUpdate (to, from, next) :
Вызывается при изменении текущего маршрута и повторном использовании компонента, через него можно получить доступ к экземпляру,next должен быть вызван активно, обратный вызов не может быть передан
- Для пути /foo/:id с динамическими параметрами при переходе между /foo/1 и /foo/2 будет повторно использоваться экземпляр компонента и будет вызываться защита
- Когда текущий запрос маршрута изменится, будет вызван охранник
beforeRouteLeave (to, from, next) :
Вызывается, когда навигация покидает соответствующий маршрут компонента, вы можете получить доступ к экземпляру компонентаthis,next должен быть вызван активно, обратный вызов не может быть переданЦель: очистить таймер в текущем компоненте, чтобы не занимать память; когда на странице есть незакрытые окна или несохраненный контент, предотвратить переход страницы; сохранить соответствующий контент в Vuex или Session
3. Навигационные крючки в маршрутах
В основном используется для написания логики, которая должна выполняться при переходе по указанному маршруту.beforeEnter
Есть три параметра: to/from/next
{
path:'/',
name:'Login',
component:Login,
beforeEnter:(to,from,next)=>{
consloe.log("即将进入Login");
next();
}
}