77777777777777777777777777777777777777777777777777777777777777777777777777
Одна, html и css часть
1. Как понять блочную модель CSS?
标准盒子模型:宽度=内容的宽度(content)+ border + padding
低版本IE盒子模型:宽度=内容宽度(content+border+padding)
2. БФК?
* 什么是 BFC
BFC(Block Formatting Context)格式化上下文,是 Web 页面中盒模型布局的 CSS 渲染模式,指一个独立的渲染区域或者说是一个隔离的独立容器。
* 形成 BFC 的条件
* 浮动元素,float 除 none 以外的值
* 定位元素,position(absolute,fixed)
* display 为以下其中之一的值 inline-block,table-cell,table-caption
* overflow 除了 visible 以外的值(hidden,auto,scroll)
* BFC 的特性
* 内部的 Box 会在垂直方向上一个接一个的放置。
* 垂直方向上的距离由 margin 决定
* bfc 的区域不会与 float 的元素区域重叠。
* 计算 bfc 的高度时,浮动元素也参与计算
* bfc 就是页面上的一个独立容器,容器里面的子元素不会影响外面元素。
3. Как очистить поплавок?
不清楚浮动会发生高度塌陷:浮动元素父元素高度自适应(父元素不写高度时,子元素写了浮动后,父元素会发生高度塌陷)
* clear清除浮动(添加空div法)在浮动元素下方添加空div,并给该元素写css样式: {clear:both;height:0;overflow:hidden;}
* 给浮动元素父级设置高度
* 父级同时浮动(需要给父级同级元素添加浮动)
* 父级设置成inline-block,其margin: 0 auto居中方式失效
* 给父级添加overflow:hidden 清除浮动方法
* 万能清除法 after伪类 清浮动(现在主流方法,推荐使用)
.float_div:after{
content:".";
clear:both;
display:block;
height:0;
overflow:hidden;
visibility:hidden;
}
.float_div{
zoom:1
}
4. Каков принцип создания треугольника с помощью чистого CSS?
span {
width: 0;
height: 0;
border-top: 40px solid transparent;
border-left: 40px solid transparent;
border-right: 40px solid transparent;
border-bottom: 40px solid #ff0000;
}
5. CSS3 обеспечивает тонкие линии толщиной 0,5 пикселя?
/* css */
.line {
position: relative;
}
.line:after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
background-color: #000000;
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
}
/* html */
<div class="line"></div>
6. CSS реализует трехколоночный макет
Левый и правый фиксированные, средний адаптивный.
- гибкий метод
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.box {
display: flex;
justify-content: center;
height: 200px;
}
.left {
width: 200px;
background-color: red;
height: 100%;
}
.content {
background-color: yellow;
flex: 1;
}
.right {
width: 200px;
background-color: green;
}
</style>
</head>
<body>
<div class="box">
<div class="left"></div>
<div class="content"></div>
<div class="right"></div>
</div>
</body>
</html>
- абсолютное позиционирование
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.box {
position: relative;
height: 200px;
}
.left {
width: 200px;
background-color: red;
left: 0;
height: 100%;
position: absolute;
}
.content {
background-color: yellow;
left: 200px;
right: 200px;
height: 100%;
position: absolute;
}
.right {
width: 200px;
background-color: green;
right: 0;
height: 100%;
position: absolute;
}
</style>
</head>
<body>
<div class="box">
<div class="left"></div>
<div class="content"></div>
<div class="right"></div>
</div>
</body>
</html>
- плавучий путь
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.box {
height: 200px;
}
.left {
width: 200px;
background-color: red;
float: left;
height: 100%;
}
.content {
background-color: yellow;
height: 100%;
}
.right {
width: 200px;
background-color: green;
float: right;
height: 100%;
}
</style>
</head>
<body>
<div class="box">
<div class="left"></div>
<div class="right"></div>
<div class="content"></div>
</div>
</body>
</html>
7. Отцентрируйте div по вертикали
- ширина и высота известны
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.box {
width: 400px;
height: 200px;
position: relative;
background: red;
}
.content {
width: 200px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
margin-left: -100px;
margin-top: -50px;
background: green;
}
</style>
</head>
<body>
<div class="box">
<div class="content"></div>
</div>
</body>
</html>
- ширина и высота неизвестны
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.box {
width: 400px;
height: 200px;
position: relative;
background: red;
}
.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: green;
}
</style>
</head>
<body>
<div class="box">
<div class="content"></div>
</div>
</body>
</html>
- гибкий макет
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.box {
width: 400px;
height: 200px;
background: red;
display: flex;
justify-content: center;
align-items: center;
}
.content {
width: 200px;
height: 100px;
background: green;
}
</style>
</head>
<body>
<div class="box">
<div class="content"></div>
</div>
</body>
</html>
2. JS
1. Закрытие
Концепция закрытия
能够读取其他函数内部变量的函数。
或简单理解为定义在一个函数内部的函数,内部函数持有外部函数内变量的引用。
Использование закрытия
1、读取函数内部的变量
2、让这些变量的值始终保持在内存中。不会再f1调用后被自动清除。
3、方便调用上下文的局部变量。利于代码封装。
原因:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,f2的存在依赖f1,因此f1也始终存在内存中,不会在调用结束后,被垃圾回收机制回收。
Недостатки закрытия
1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
Сценарии закрытия приложения
setTimeout сценариев закрытия приложений
//setTimeout传递的第一个函数不能带参数
setTimeout((param) => {
alert(param)
}, 1000);
//通过闭包可以实现传参效果
function func(param) {
return function() {
alert(param)
}
}
var f1 = func('汪某');
setTimeout(f1, 1000)//汪某
2. Выполнение функции в js
В ES5.1 функция выполняется так (use strict и некоторые частные случаи не обсуждаются, JS очень сложный), и выполняется в следующем порядке:
1. 确定“this”的值 (确切的来说,this在JS里面不是一个变量名而是一个关键字)
2. 创建一个新的作用域
3. 处理形参/实参(没有定义过才声明,无论如何都重新赋值,没有对应实参则赋值为"undefined"):
对于每一个传入的实参,按照从左往右的顺序依次执行:如果对应的形参在本作用域中还没有定义,则在本作用域中声明形参,并赋值。如果已经定义过了,则重新给其赋值。(没有对应实参则赋值为"undefined")(没有定义:就是“没有声明”的意思)
4. 处理函数定义(没有定义过才声明,无论如何都重新赋值):
对该函数中所有的定义的函数,按照代码写的顺序依次执行:如果这个变量名在本作用域中还没有定义,则在本作用域中声明这个函数名,并且赋值为对应的函数,如果定义了这个变量,在可写的情况下重新给这个变量赋值为这个函数,否则抛出异常。
5. 处理 "arguments"(没有定义过才声明和赋值):
如果在本作用域中没有定义 arguments,则在本作用域中声明arguments并给其赋值。
6. 处理变量声明(没有定义过才声明,不赋值):
对于所有变量声明,按照代码写的顺序依次执行:如果在本作用域中没有定义这个变量,则在本作用域中声明这个变量,赋值为undefined
7. 然后执行函数代码。(当然是去变量定义里面的 var 执行)
3. Что происходит в процессе создания нового объекта?
1. 创建空对象;
var obj = {};
2. 设置新对象的constructor属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象;
obj.__proto__ = ClassA.prototype;
3. 使用新对象调用函数,函数中的this被指向新实例对象:
ClassA.call(obj);//{}.构造函数();
4. 如果无返回值或者返回一个非对象值,则将新对象返回;如果返回值是一个新对象的话那么直接直接返回该对象。
4. Макрозадачи и микрозадачи
- макрозадача (макрозадача): включая общий код скрипта, setTimeout, setInterval
- микрозадача: Promise, process.nextTick
На этот раз полностью понять механизмы реализации JavaScript
5. Защита от сотрясений и дросселирование
Комплексные сценарии применения
- Отказ: Это означает, что функция может быть выполнена только один раз в течение n секунд после запуска события.Если событие будет запущено снова в течение n секунд, время выполнения функции будет пересчитано.
- Поиск Поиск Lenovo, когда пользователи постоянно вводят значения, использует защиту от сотрясений для экономии ресурсов запроса.
- Когда окно инициирует изменение размера, постоянное изменение размера окна браузера будет вызывать это событие постоянно, а использование защиты от сотрясений заставит его запускаться только один раз.
- Регулирование: относится к непрерывному запуску события, но выполнению функции только один раз в n секунд. Регулирование снижает частоту выполнения функции.
- Мышь непрерывно нажимается для срабатывания, mousedown (срабатывает только один раз в единицу времени)
- Слушайте события прокрутки, например, нужно ли скользить вниз, чтобы автоматически загрузить больше, использовать дроссель, чтобы судить Так называемый anti-shake означает, что функция может быть выполнена только один раз в течение n секунд после срабатывания события, если событие сработает снова в течение n секунд, время выполнения функции будет пересчитано.
Функция защиты от сотрясений делится на версию с немедленным выполнением и версию с немедленным выполнением.
- Версия без немедленного выполнения означает, что функция не будет выполняться сразу после срабатывания события, а будет выполнена через n секунд, при повторном срабатывании события в течение n секунд время выполнения функции будет пересчитано.
- Версия с немедленным выполнением означает, что функция будет выполняться сразу после срабатывания события, а затем эффект функции может продолжать выполняться, если событие не сработает в течение n секунд.
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
Так называемое регулирование относится к непрерывному запуску события, но выполнению функции только один раз в n секунд. Регулирование снижает частоту выполнения функции.
Для регулирования обычно есть два способа достижения, а именно версия с меткой времени и версия с таймером.
- Версия функции с меткой времени срабатывает, когда начинается период времени.
- Версия функции с таймером срабатывает по окончании периода времени.
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
function throttle(func, wait ,type) {
if(type===1){
var previous = 0;
}else if(type===2){
var timeout;
}
return function() {
let context = this;
let args = arguments;
if(type===1){
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}else if(type===2){
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}
6. Общие методы массивов
Как изменить исходный массив
- splice() добавить/удалить элементы массива
语法:arrayObject.splice(index,howmany,item1,.....,itemX)
参数:
1.index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
2.howmany:可选。要删除的项目数量。如果设置为 0,则不会删除项目。
3.item1, ..., itemX: 可选。向数组添加的新项目。
返回值: 如果有元素被删除,返回包含被删除项目的新数组。
- sort() сортировка массива
语法:arrayObject.sort(sortby)
参数:
1.sortby 可选。规定排序顺序。必须是函数。。
返回值: 返回包排序后的新数组。
- pop() удаляет последний элемент массива
语法:arrayObject.pop()
参数:无
返回值: 返回被删除的元素。
- shift() удаляет первый элемент массива
语法:arrayObject.shift()
参数:无
返回值: 返回被删除的元素。
- push() добавляет элемент в конец массива
语法:arrayObject.push(newelement1,newelement2,....,newelementX)
参数:
1.newelement1 必需。要添加到数组的第一个元素。
2.newelement2 可选。要添加到数组的第二个元素。
3.newelementX 可选。可添加若干个元素。
返回值: arrayObject 的新长度。
- unshift() добавляет один или несколько элементов в начало массива
语法:arrayObject.unshift(newelement1,newelement2,....,newelementX)
参数:
1.newelement1 必需。要添加到数组的第一个元素。
2.newelement2 可选。要添加到数组的第二个元素。
3.newelementX 可选。可添加若干个元素。
返回值: arrayObject 的新长度。
- reverse() меняет порядок элементов в массиве на обратный
语法:arrayObject.reverse()
参数:无
返回值: 颠倒后的新数组。
- copyWithin() копирует член из указанного места в другое место
语法: array.copyWithin(target, start = 0, end = this.length)
参数:
1.target(必需):从该位置开始替换数据。如果为负值,表示倒数。
2.start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
3.end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
返回值: 返回当前数组。
- fill() заполняет массив
语法: array.fill(value, start, end)
参数:
1.value 必需。填充的值。
2.start 可选。开始填充位置。
3.end 可选。停止填充位置 (默认为 array.length)
返回值: 返回当前数组。
Метод, который не изменяет исходный массив
- slice() поверхностно копирует элементы массива
语法: array.slice(begin, end);
参数:
1.begin(可选): 索引数值,接受负值,从该索引处开始提取原数组中的元素,默认值为0。
2.end(可选):索引数值(不包括),接受负值,在该索引处前结束提取原数组元素,默认值为数组末尾(包括最后一个元素)。
返回值: 返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象,且原数组不会被修改。
- массив join() в строку
语法:array.join(str)
参数:
1.str(可选): 指定要使用的分隔符,默认使用逗号作为分隔符。
返回值: 返回生成的字符串。
- concat() объединяет два или более массива
语法: var newArr =oldArray.concat(arrayX,arrayX,......,arrayX)
参数:
1.arrayX(必须):该参数可以是具体的值,也可以是数组对象。可以是任意多个。
返回值: 返回返回合并后的新数组。
- indexOf() определяет, существует ли элемент в массиве
语法:array.indexOf(searchElement,fromIndex)
参数:
1.searchElement(必须):被查找的元素
2.fromIndex(可选):开始查找的位置(不能大于等于数组的长度,返回-1),接受负值,默认值为0。
返回值: 返回下标
- lastIndexOf() находит последнюю позицию указанного элемента в массиве
语法:arr.lastIndexOf(searchElement,fromIndex)
参数:
1.searchElement(必须): 被查找的元素
2.fromIndex(可选): 逆向查找开始位置,默认值数组的长度-1,即查找整个数组。
返回值: 方法返回指定元素,在数组中的最后一个的索引,如果不存在则返回 -1。(从数组后面往前查找)
- include() определяет, содержит ли массив элемент
语法: array.includes(searchElement,fromIndex=0)
参数:
1.searchElement(必须):被查找的元素
2.fromIndex(可选):默认值为0,参数表示搜索的起始位置,接受负值。正值超过数组长度,数组不会被搜索,返回false。负值绝对值超过长数组度,重置从0开始搜索。
返回值: 返回布尔
7. Немедленно выполнить функцию
Объявите анонимную функцию и немедленно вызовите анонимную функцию. Цель состоит в том, чтобы защитить внутренние переменные от загрязнения.
(function(n1, n2) {
console.log("这是匿名函数的自执行的第一种写法,结果为:" + (n1 + n2))
})(10, 100);
(function start(n1, n2) {
console.log("这是函数声明方式的自执行的第一种写法,结果为:" + (n1 + n2))
})(10, 100);
(function(n1, n2) {
console.log("这是匿名函数的自执行的第二种写法,结果为:" + (n1 + n2))
}(10, 100));
(function start(n1, n2) {
console.log("这是函数声明方式的自执行的第二种写法,结果为:" + (n1 + n2))
}(10, 100));
8. js прототип и цепочка прототипов
Каждый объект будет инициализировать свойство внутри него, которое является прототипом (прототипом).Когда мы обращаемся к свойству объекта, если свойство не существует в объекте, то он переходит к прототипу, чтобы найти свойство, и У прототипа есть собственный прототип, поэтому я продолжаю его искать, что мы обычно и называем концепцией цепочки прототипов.
Отношение: instance.constructor.prototype = instance.proto
Особенности: Объекты JavaScript передаются по ссылке.Каждый новый объект, который мы создаем, не имеет копии собственного прототипа.Когда мы модифицируем прототип, связанные объекты также наследуют изменение. Когда нам нужно свойство, движок JavaScript сначала проверит, имеет ли текущий объект это свойство, если нет, то выяснит, имеет ли его объект-прототип это свойство, и так далее рекурсивно, и последовательно извлечет встроенный объект Object.
function Func(){}
Func.prototype.name = "汪某";
Func.prototype.getInfo = function() {
return this.name;
}
var person = new Func();
console.log(person.getInfo());//"汪某"
console.log(Func.prototype);//Func { name = "汪某", getInfo = function() }
Ссылаться на:js прототип и цепочка прототипов
9. позвонить, подать заявку, привязать в js
Ссылаться на:Сводка методов вызова, применения, привязки в JavaScript.
10. Обещания
Подытожим Promise одним предложением: объект Promise используется для асинхронной операции, он представляет собой асинхронную операцию, которая еще не завершена и ожидается, что она будет завершена в будущем.
Промисы используются для решения двух проблем:
- Ад обратного вызова, код сложно поддерживать, часто вывод первой функции является вводом второй функции
- Promise может поддерживать несколько одновременных запросов и получать данные из одновременных запросов.
Этот промис может решить проблему асинхронности, нельзя сказать, что промис асинхронный.
/*Promise 的简单实现*/
class MyPromise {
constructor(fn) {
this.resolvedCallbacks = [];
this.rejectedCallbacks = [];
this.state = "PADDING";
this.value = "";
fn(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value) {
if (this.state === "PADDING") {
this.state = "RESOLVED";
this.value = value;
this.resolvedCallbacks.forEach(cb => cb());
}
}
reject(value) {
if (this.state === "PADDING") {
this.state = "REJECTED";
this.value = value;
this.rejectedCallbacks.forEach(cb => cb());
}
}
then(resolve = function() {}, reject = function() {}) {
if (this.state === "PADDING") {
this.resolvedCallbacks.push(resolve);
this.rejectedCallbacks.push(reject);
}
if (this.state === "RESOLVED") {
resolve(this.value);
}
if (this.state === "REJECTED") {
reject(this.value);
}
}
}
11. асинхронно/ожидание
Как использовать асинхронные функции
async function timeout(ms) {
await new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
Приведенный выше код указывает, что hello world выводится через 50 миллисекунд. Кроме того, асинхронную функцию можно рассматривать как несколько асинхронных операций, упакованных в объект Promise, а команда await является синтаксическим сахаром внутренней команды then.
Быть добавленным. . .
12. Глубокое копирование, поверхностное копирование
И поверхностная, и глубокая копия предназначены только для ссылочных типов данных. Поверхностная копия копирует только указатель на объект, а не сам объект. Старый и новый объекты по-прежнему используют одну и ту же память, но глубокая копия создаст другой идентичный объект, новый 1. Объект не разделяет память с исходным объектом, и изменение нового объекта не изменит исходный объект;
Отличие: поверхностная копия копирует только атрибуты объекта первого уровня, а глубокая копия может рекурсивно копировать атрибуты объекта;
- пользовательская функция
function simpleCopy (initalObj) {
var obj = {};
for ( var i in initalObj) {
obj[i] = initalObj[i];
}
return obj;
}
- Object.assign() в ES6
let newObj = Object.assign({}, obj);
- Расширения объектов для ES6
let newObj = {...obj};
Реализация глубокого копирования
- JSON.stringify и JSON.parse
Используйте JSON.stringify для преобразования объекта в строку и JSON.parse для преобразования строки в новый объект.
let newObj = JSON.parse(JSON.stringify(obj));
- lodash
Используйте метод _.cloneDeep, предоставляемый библиотекой lodash, для реализации глубокого копирования.
var _ = require('lodash');
var newObj = _.cloneDeep(obj);
- самовывоз
function deepClone(obj) {
let objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === "object") {
// for...in 会把继承的属性一起遍历
for (let key in obj) {
// 判断是不是自有属性,而不是继承属性
if (obj.hasOwnProperty(key)) {
//判断ojb子元素是否为对象或数组,如果是,递归复制
if (obj[key] && typeof obj[key] === "object") {
objClone[key] = this.deepClone(obj[key]);
} else {
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
13. Междоменный
Междоменное взаимодействие следует понимать в соответствии с политикой браузера в отношении одного и того же источника. Политика одного и того же источника означает, что запрос должен быть отправлен на один и тот же порт, с одним и тем же протоколом, с одним и тем же доменным именем, а клиентские сценарии из разных источников не могут быть прочитаны без явной авторизации Запись на ресурсы друг друга.
Из-за политики браузера в отношении одного и того же источника сценарии, которые не относятся к одному и тому же источнику, не могут работать с объектами из других источников. Если вы хотите управлять объектами из другого источника, вам необходимо междоменное использование.
- jsonp
- iframe
- Совместное использование ресурсов между источниками (CORS)
- междоменный прокси nginx
14. Для в и для из
- for in
1.一般用于遍历对象的可枚举属性。以及对象从构造函数原型中继承的属性。对于每个不同的属性,语句都会被执行。
2.不建议使用for in 遍历数组,因为输出的顺序是不固定的。
3.如果迭代的对象的变量值是null或者undefined, for in不执行循环体,建议在使用for in循环之前,先检查该对象的值是不是null或者undefined
- for of
1.for…of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
перебирать объекты
var s = {
a: 1,
b: 2,
c: 3
}
var s1 = Object.create(s);
for (var prop in s1) {
console.log(prop); //a b c
console.log(s1[prop]); //1 2 3
}
for (let prop of s1) {
console.log(prop); //报错如下 Uncaught TypeError: s1 is not iterable
}
for (let prop of Object.keys(s1)) {
console.log(prop); // a b c
console.log(s1[prop]); //1 2 3
}
15. Как перестать пузыриться?
Всплывающие события: события запускаются в порядке от наиболее конкретного целевого объекта события к наименее специфичному целевому объекту события (объект документа).
Метод w3c — e.stopPropagation(), а IE использует e.cancelBubble = true.
//阻止冒泡行为
function stopBubble(e) {
//如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation )
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
else
//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
16. Как предотвратить события по умолчанию?
Метод w3c — e.preventDefault(), а IE использует e.returnValue = false
//阻止浏览器的默认行为
function stopDefault( e ) {
//阻止默认浏览器动作(W3C)
if ( e && e.preventDefault )
e.preventDefault();
//IE中阻止函数器默认动作的方式
else
window.event.returnValue = false;
return false;
}
17. вар, пусть, константа
//变量提升
console.log(a); // undefined
console.log(b); // 报错
console.log(c); // 报错
var a = 1;
let b = 2;
const c = 3;
// 全局声明
console.log(window.a) // 1
// 重复声明
let b = 200;//报错
На самом деле здесь легко понять, var можно продвигать как переменную. Let и const должны быть объявлены до того, как их можно будет вызвать. Для let и const это отложенная мертвая зона.
18. Класс
Новый класс es6 на самом деле является синтаксическим сахаром.В основе js нет понятия класса, но это также инкапсуляция прототипного наследования.
class People {
constructor(props) {
this.props = props;
this.name = '汪某';
}
callMyName() {
console.log(this.name);
}
}
class Name extends People { // extends 其实就是继承了哪个类
constructor(props) {
// super相当于 把类的原型拿过来
// People.call(this, props)
super(props)
}
callMyApple() {
console.log('我是汪某!')
}
}
let a = new Name('啊啊啊')
a.callMyName(); //汪某
a.callMyApple(); // 我是汪某!
19. Установить
Структура данных Set похожа на массив, но все члены имеют уникальные значения.
let a = new Set();
[1,2,2,1,3,4,5,4,5].forEach(x=>a.add(x));
for(let k of a){
console.log(k)
};
// 1 2 3 4 5
основное использование
let a = new Set([1,2,3,3,4]);
[...a]; // [1,2,3,4]
a.size; // 4
// 数组去重
[...new Set([1,2,3,4,4,4])];// [1,2,3,4]
метод
- add(value): добавить значение и вернуть саму структуру Set.
- удалить (значение): удалить значение и вернуть логическое значение, указывающее, было ли удаление успешным.
- has(value): возвращает логическое значение, указывающее, является ли значение членом набора.
- clear(): очищает все члены, без возвращаемого значения.
let a = new Set();
a.add(1).add(2); // a => Set(2) {1, 2}
a.has(2); // true
a.has(3); // false
a.delete(2); // true a => Set(1) {1}
a.clear(); // a => Set(0) {}
20. Карта
Структура Map обеспечивает соответствие «значение-значение» и является более полной реализацией структуры Hash.
let a = new Map();
let b = {name: 'leo' };
a.set(b,'my name'); // 添加值
a.get(b); // 获取值
a.size; // 获取总数
a.has(b); // 查询是否存在
a.delete(b); // 删除一个值
a.clear(); // 清空所有成员 无返回
основное использование
- Передайте массив в качестве параметра, указав массив пар ключ-значение.
let a = new Map([
['name','wzx'],
['age',23]
])
- Если вы назначите несколько назначений одной и той же клавише, более поздние значения перезапишут более ранние.
let a = new Map();
a.set(1,'aaa').set(1,'bbb');
a.get(1); // 'bbb'
- Возвращает значение undefined, если считывается неизвестный ключ.
new Map().get('asdsad'); // undefined
- Два экземпляра одного и того же значения рассматриваются как два ключа в структуре карты.
let a = new Map();
let a1 = ['aaa'];
let a2 = ['aaa'];
a.set(a1,111).set(a2,222);
a.get(a1); // 111
a.get(a2); // 222
метод
- keys(): возвращает обходчик имен ключей.
- values(): возвращает итератор ключевых значений.
- entry(): возвращает обход всех членов.
- forEach(): выполняет итерацию по всем элементам карты.
let a = new Map([
['name', 'leo'],
['age', 18]
])
for (let i of a.keys()) {
console.log(i)
};
//name
//age
for (let i of a.values()) {
console.log(i)
};
//leo
//18
for (let i of a.entries()) {
console.log(i)
};
//["name", "leo"]
a.forEach((v, k, m) => {
console.log(`key:${k},value:${v},map:${m}`)
})
//["age", 18]
Три, ручной код
1. Реализовать новый оператор
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return;
ret;
}
return;
res;
}
var obj = New(A, 1, 2);
// equals to
var obj = new A(1, 2);
2. Реализовать призыв или подать заявку
- call
Function.prototype.call2 = function (context) {
var context = context || window;
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')');
delete context.fn
return result;
}
- apply
Function.prototype.apply2 = function (context, arr) {
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
}
else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn
return result;
}
Ссылаться на:Углубленный вызов JavaScript и реализация имитационного моделирования
3. Реализуйте Function.bind
Function.prototype.bind2 = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};
var fbound = function () {
self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
}
fNOP.prototype = this.prototype;
fbound.prototype = new fNOP();
return fbound;
}
Ссылаться на:Имитационная реализация глубокой привязки JavaScript
4. Реализовать наследование
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log('parent name:', this.name);
}
function Child(name, parentName) {
Parent.call(this, parentName);
this.name = name;
}
function create(proto) {
function F() {}
F.prototype = proto;
return new F();
}
Child.prototype = create(Parent.prototype);
Child.prototype.sayName = function() {
console.log('child name:', this.name);
}
Child.prototype.constructor = Child;
var parent = new Parent('汪某');
parent.sayName();// parent name: 汪某
var child = new Child('son', '汪某');
5. Напишите обещание от руки (требуется для среднего и продвинутого уровня)
достаточно для интервью
function myPromise(constructor) {
let self = this;
self.status = "pending"
//定义状态改变前的初始状态
self.value = undefined;
//定义状态为resolved的时候的状态
self.reason = undefined;
//定义状态为rejected的时候的状态
function resolve(value) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.value = value;
self.status = "resolved";
}
}
function reject(reason) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.reason = reason;
self.status = "rejected";
}
}
//捕获构造异常
try {
constructor(resolve, reject);
} catch (e) {
reject(e);
}
}
//同时,需要在 myPromise的原型上定义链式调用的 then方法:
myPromise.prototype.then = function(onFullfilled, onRejected) {
let self = this;
switch (self.status) {
case "resolved":
onFullfilled(self.value);
break;
case "rejected":
onRejected(self.reason);
break;
default:
}
}
//测试一下:
var p = new myPromise(function(resolve, reject) {
resolve(1)
});
p.then(function(x) {
console.log(x)
})
Для расширенной версии, пожалуйста, обратитесь к:Самый подробный учебник Promise, написанный от руки.
6. Устранение дребезга и дросселирование
Смотрите полную версию выше, а вот версия интервью
// 防抖函数
function debounce(fn, wait) {
let timer;
return function() {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, wait)
}
}
// 节流函数
function throttle(fn, wait) {
let prev = new Date();
return function() {
const args = arguments;
const now = new Date();
if (now - prev > wait) {
fn.apply(this, args);
prev = new Date();
}
}
}
7, написанная от руки глубокая копия JS
Интервью
function deepCopy(obj) {
//判断是否是简单数据类型,
if (typeof obj == "object") {
//复杂数据类型
var result = obj.constructor == Array ? [] : {};
for (let i in obj) {
result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
}
} else {
//简单数据类型 直接 == 赋值
var result = obj;
}
return result;
}
4. ВУЭ
1. Каков принцип двусторонней привязки данных в Vue2.0?
Vue.js использует метод захвата данных в сочетании с режимом издатель-подписчик, перехватывает установщик и получатель каждого свойства через Object.defineProperty(), публикует сообщения подписчикам при изменении данных и запускает соответствующий обратный вызов мониторинга.
//vue实现数据双向绑定的原理就是用Object.defineproperty()重新定义(set方法)对象设置属性值和(get方法)获取属性值的操纵来实现的。
//Object.property()方法的解释:Object.property(参数1,参数2,参数3) 返回值为该对象obj
//其中参数1为该对象(obj),参数2为要定义或修改的对象的属性名,参数3为属性描述符,属性描述符是一个对象,主要有两种形式:数据描述符和存取描述符。这两种对象只能选择一种使用,不能混合使用。而get和set属于存取描述符对象的属性。
//这个方法会直接在一个对象上定义一个新属性或者修改对象上的现有属性,并返回该对象。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="myapp">
<input v-model="message" /><br>
<span v-bind="message"></span>
</div>
<script type="text/javascript">
var model = {
message: ""
};
var models = myapp.querySelectorAll("[v-model=message]");
for (var i = 0; i < models.length; i++) {
models[i].onkeyup = function() {
model[this.getAttribute("v-model")] = this.value;
}
}
// 观察者模式 / 钩子函数
// defineProperty 来定义一个对象的某个属性
Object.defineProperty(model, "message", {
set: function(newValue) {
var binds = myapp.querySelectorAll("[v-bind=message]");
for (var i = 0; i < binds.length; i++) {
binds[i].innerHTML = newValue;
};
var models = myapp.querySelectorAll("[v-model=message]");
for (var i = 0; i < models.length; i++) {
models[i].value = newValue;
};
this.value = newValue;
},
get: function() {
return this.value;
}
})
</script>
</body>
</html>
Vue3.0 заменит Object.defineProperty собственным прокси.
Зачем заменять Object.defineProperty?
- Во Vue Object.defineProperty не может отслеживать изменение индекса массива, что приводит к установке значения массива напрямую через индекс массива, и не может реагировать в реальном времени.
- Object.defineProperty может только перехватывать свойства объектов, поэтому нам нужно перебирать каждое свойство каждого объекта.
что такое прокси
- Прокси — это новая функция в ES6, которая переводится как «прокси» и используется здесь для обозначения «прокси» некоторых операций. Прокси позволяет нам контролировать внешний доступ к объектам лаконичным и понятным способом. Его функциональность очень похожа на шаблон прокси в шаблонах проектирования.
- Прокси можно понимать как настройку уровня «перехвата» перед целевым объектом, и доступ к объекту из внешнего мира должен сначала пройти этот уровень перехвата, поэтому он обеспечивает механизм фильтрации и перезаписи доступа к внешнему миру. .
- Основное преимущество использования Proxy заключается в том, что он может обрабатывать некоторую неосновную логику (например: ведение журнала перед чтением или установкой некоторых свойств объекта; перед установкой значений некоторых свойств объекта требуется аутентификация; контроль доступа к некоторым свойства) Подождите). Таким образом, объекту нужно сосредоточиться только на основной логике, чтобы добиться разделения задач и уменьшить сложность объекта.
2. Пожалуйста, уточните, как вы понимаете жизненный цикл vue?
Всего он разделен на 8 этапов: до/после создания, до/после загрузки, до/после обновления, до/после уничтожения.
- Перед созданием BEFORECREATE (элементы монтирования экземпляра Vue $EL и объекты данных DATA не определены, не инициализированы)
- created Завершить создание (завершить инициализацию data data, el не инициализирован)
- beforeMount перед загрузкой ($el и данные экземпляра vue инициализируются, но перед монтированием это все еще виртуальный узел dom, и data.message не был заменен.)
- После монтирования html отрисовывается (экземпляр vue монтируется и data.message успешно отрисовывается).
- beforeUpdate Состояние до обновления (до изменения данных в слое представления, а не до изменения данных в данных)
- обновляется после обновления состояния
- Бефореестров разрушен
- После уничтожения (после выполнения метода уничтожения изменения в данных не будут запускать периодическую функцию, указывая на то, что экземпляр vue в это время выпустил мониторинг событий и привязку к dom, но структура dom все еще существует)
Расскажите о том, что вы можете сделать на каждом этапе
- beforeCreate: здесь вы можете добавить событие загрузки, которое будет запускаться при загрузке экземпляра.
- Created: Здесь пишется событие завершения инициализации, если здесь заканчивается событие загрузки, то сюда же вызывается асинхронный запрос.
- смонтировано: повесить элемент, получить узел DOM
- update: Здесь написаны функции для обработки данных.
- beforeDestroy: вы можете написать окно подтверждения, подтверждающее событие остановки.
Прикрепите карту китайского анализа
3. Определение и получение динамического маршрута
В файле index.js в каталоге маршрутизатора добавьте /:id к атрибуту пути.
Получите его, используя params.id объекта маршрутизатора.
4. Какие навигационные крючки есть у vue-router?
три
- Глобальный навигационный хук (оценка и перехват перед прыжком)
- router.beforeEach(to, from, next),
- router.beforeResolve(to, from, next),
- router.afterEach(to, from ,next)
- Крючки внутри компонента
- beforeRouteEnter
- beforeRouteUpdate
- beforeRouteLeave
- Индивидуальная маршрутизация эксклюзивных компонентов
- beforeEnter
5. Обмен данными между компонентами?
- Родительские компоненты передают значения дочерним компонентам:
- Дочерний компонент создает свойство в свойствах для получения значения, переданного родительским компонентом;
- Зарегистрируйте дочерний компонент в родительском компоненте;
- Добавьте свойства, созданные в реквизитах дочернего компонента, в тег дочернего компонента;
- Присвойте этому свойству значение, которое необходимо передать дочернему компоненту
- Дочерние компоненты передают значения родительским компонентам:
- Дочерний компонент должен каким-то образом инициировать пользовательское событие (например, событие щелчка);
- Используйте значение, которое будет передано в качестве второго параметра $emit, которое будет передано в качестве фактического параметра методу, реагирующему на событие;
- Зарегистрируйте дочерний компонент в родительском компоненте и привяжите пользовательские прослушиватели событий к метке дочернего компонента.
6. векс
Это плагин, который может облегчить передачу данных экземплярами Vue и их компонентами.Удобно передавать данные в виде библиотеки для общедоступного хранения данных.
штат: государственный центр
мутации: изменение состояния, синхронные
действия: асинхронное изменение состояния
геттеры: получить статус
модули: разделите состояние на несколько модулей для удобства управления
Сценарий приложений: в одностраничном приложении состояние между компонентами. Воспроизведение музыки, Состояние входа в систему, Добавить в корзину.
Простой для понимания пример vuex, найденный в Интернете
Компания имеет склад
1.Государственный (склад компании)
2. Добытчик (может только достать предмет, упаковать его, но не может изменить какие-либо свойства предмета)
3. Мутация (администратор склада, только он может хранить напрямую на склад)
4.Действие (материальный покупатель компании, ответственный за покупку и получение товаров извне, хранить вещи на складе, и говорить администратору склада, что хранить)
Очень важный момент: пока вы обновляете или выходите из браузера, склад будет пуст.
7. Разница между маршрутизацией хэшей Vue и маршрутизацией истории
В URL-адресе режима хеша всегда есть знак #. Мы используем этот режим по умолчанию в разработке. Итак, когда использовать режим истории? Если пользователь рассматривает спецификацию URL-адреса, то необходимо использовать режим истории, потому что режим истории не имеет знака #, это обычный URL-адрес, подходящий для продвижения. Конечно, его функции также различаются. Например, когда мы разрабатываем приложение, есть страница обмена, затем эта общая страница создается с помощью vue или react. Мы делимся этой страницей со сторонним приложением. URL-адрес в некоторых Приложения не могут иметь знак #, поэтому, если вы хотите удалить знак #, вы должны использовать режим истории, но есть еще одна проблема с использованием режима истории.Вам необходимо сотрудничать с бэк-энд человеком и позвольте ему настроить перенаправление URL-адресов apache или nginx, и все будет в порядке для перенаправления на маршрут вашей домашней страницы.
Маршрутизатор имеет два режима: хеш-режим (по умолчанию), режим истории (необходимо настроить режим: «история»).
| hash | history | |
|---|---|---|
| отображение URL | Есть #, очень низкий | Нет #, хорошо |
| Введите, чтобы обновить | Может загружаться на страницу, соответствующую значению хеша | Обычно 404 капли |
| Поддерживаемая версия | Поддержка браузеров с низкими версиями и браузеров IE | Поддержка браузеров с низкими версиями и браузеров IE |
8. Алгоритм сравнения
Ссылаться на:Подробно объясните алгоритм сравнения vue.
5. Компьютер
1. Подробный процесс разрешения DNS
Когда мы вводим URL-адрес в браузере, например «www.google.com», этот адрес не является реальным адресом веб-сайта Google. Уникальной идентификацией каждого компьютера в Интернете является его IP-адрес, поэтому введенный URL-адрес необходимо сначала преобразовать в IP-адрес. Этот процесс называется разрешением DNS.
Разрешение DNS — это процесс рекурсивного запроса. Например, когда нам нужно разрешить "www.google.com", мы выполним следующие шаги:
- IP-адрес запрошен на локальном сервере доменных имен, но доменное имя не найдено;
- Локальный сервер доменных имен отправляет запрос обратно на корневые серверы имен, доменное имя не найдено;
- Локальный сервер доменных имен отправляет запрос на сервер доменных имен верхнего уровня .com, но доменное имя не найдено;
- Локальный сервер доменных имен отправляет запрос на сервер доменных имен .google.com, находит доменное имя и возвращает соответствующий IP-адрес локальному серверу доменных имен.
2. Кратко опишите трехстороннее рукопожатие
Протокол HTTP использует протокол TCP в качестве протокола транспортного уровня.После получения IP-адреса сервера клиент браузера установит TCP-соединение с сервером. Процесс состоит из трех рукопожатий:
- Первое рукопожатие: при установлении соединения клиент отправляет запрос на сервер
- Второе рукопожатие: после того, как сервер получает сообщение с запросом, если он согласен на подключение, он отправляет клиенту подтверждающее сообщение.
- При третьем рукопожатии после того, как клиент получает подтверждение от сервера, он снова отправляет подтверждающее сообщение на сервер для завершения соединения.
Трехстороннее рукопожатие в основном предназначено для предотвращения отправки неверных полей сообщения запроса на сервер, что приводит к трате ресурсов.
3. Помашите четыре раза
Клиент и сервер четыре раза сигнализируют об отключении TCP-соединения.
- Первая волна: клиент хочет разойтись и отправляет сообщение на сервер
- Вторая волна: сервер сообщает клиенту, что запрос на разрыв принят, но он не готов к разрыву
- Третье восстановление: сервер готов к развалу, уведомить клиента
- Четвертая волна: клиент отправляет серверу сообщение, подтверждающее разрыв, и сервер закрывает соединение.