предисловие
Пришло время начать волну основ JS, и если вы знакомы с ним, вы можете получить предложение в Silver Ten Speed;
В этой статье делается выбор не из традиционного метода вопросов и ответов, а из аспекта знаний, чтобы сформировать сеть знаний;
Включает в себя функции, массивы, объекты, структуры данных, алгоритмы, шаблоны проектирования и http.
1. Функция
1.1 3 способа определения функций
1.1.1 Описание функции
//ES5
function getSum(){}
function (){}//匿名函数
//ES6
()=>{}//如果{}内容只有一行{}和return关键字可省,
1.1.2 Функциональные выражения (функциональные литералы)
//ES5
var sum=function(){}
//ES6
let sum=()=>{}//如果{}内容只有一行{}和return关键字可省,
1.1.3 Конструктор
const sum = new Function('a', 'b' , 'return a + b')
1.1.4 Сравнение трех методов
1. Объявления функций предварительно анализируются, и объявления функций имеют более высокий приоритет, чем переменные; 2. Способ использования конструктора Function для определения функции — это функциональное выражение, которое приводит к двойному синтаксическому анализу кода и влияет на производительность. Первый анализирует обычный код JavaScript, второй анализирует строку, переданную в конструктор.
1.2 Четыре типа вызовов функций в ES5
В ES5 указатель this содержимого функции связан с вызывающим методом.
1.2.1 Режим вызова функции
Включая имя функции () и анонимные вызовы функций, это указывает на окно
function getSum() {
console.log(this) //这个属于函数名调用,this指向window
}
getSum()
(function() {
console.log(this) //匿名函数调用,this指向window
})()
var getSum=function() {
console.log(this) //实际上也是函数名调用,window
}
getSum()
1.2.2 Вызов метода
Объект.Имя метода(), это указывает на объект
var objList = {
name: 'methods',
getSum: function() {
console.log(this) //objList对象
}
}
objList.getSum()
1.2.3 Вызов конструктора
новое имя конструктора(), это указывает на созданный объект
function Person() {
console.log(this); //是构造函数调用,指向实例化的对象personOne
}
var personOne = new Person();
1.2.4 Косвенные вызовы
Для этого используйте вызов и применение. Это первый параметр, соответствующий вызову и применению. Если значение не передано или первое значение равно нулю, это указывает на окно, когда оно не определено. Через call/apply, если первый параметр является строкой, числом, логическим значением, call вызовет соответствующий конструктор String, Numer, Boolean, чтобы преобразовать его в соответствующий объект экземпляра.
function foo() {
console.log(this);
}
foo.apply('我是apply改变的this值');//我是apply改变的this值
foo.call('我是call改变的this值');//我是call改变的this值
1.3 Вызов функции в ES6
Стрелочные функции нельзя использовать в качестве конструкторов, то есть объект нельзя создать с помощью новой команды, иначе будет выброшена ошибка this функции стрелки связано с определением и не имеет ничего общего с вызовом Вызов — это шаблон вызова функции.
(() => {
console.log(this)//window
})()
let arrowFun = () => {
console.log(this)//window
}
arrowFun()
let arrowObj = {
arrFun: function() {
(() => {
console.log(this)//this指向的是arrowObj对象
})()
}
}
arrowObj.arrFun();
1.4.звоните, обращайтесь и связывайтесь
1. IE5 не поддерживает вызов и применение, привязка взята из ES5; 2.call и apply могут вызывать функции, изменять это и реализовывать методы наследования и заимствования других объектов;
1.4.1 Определение вызова и применения
Вызвать метод, который заменяет один объект другим (этот) object.call(новый этот объект, аргумент 1, аргумент 2, аргумент 3...) object.apply(новый этот объект, [параметр 1, параметр 2, параметр 3...])
1.4.2 вызов и применение
1. Косвенно вызовите функцию и измените это значение области видимости. 2. Методы захвата других объектов
var foo = {
name:"张三",
logName:function(){
console.log(this.name);
}
}
var bar={
name:"李四"
};
foo.logName.call(bar);//李四
实质是call改变了foo的this指向为bar,并调用该函数
3. Две функции реализуют наследование
function Animal(name){
this.name = name;
this.showName = function(){
console.log(this.name);
}
}
function Cat(name){
Animal.call(this, name);
}
var cat = new Cat("Black Cat");
cat.showName(); //Black Cat
4. Добавьте методы массива push, pop в массивы классов (arguments и nodeList)
(function(){
Array.prototype.push.call(arguments,'王五');
console.log(arguments);//['张三','李四','王五']
})('张三','李四')
5. Слияние массивов
let arr1=[1,2,3];
let arr2=[4,5,6];
Array.prototype.push.apply(arr1,arr2); //将arr2合并到了arr1中
6. Найдите максимальное значение массива
Math.max.apply(null,arr)
7. Определите тип персонажа
Object.prototype.toString.call({})
1.4.3 bind
bind - это метод расширения функции,
После привязки код перепривязывает указатель this внутри func, возвращает функцию, не вызывает метод и несовместим с IE8.
var name = '李四'
var foo = {
name: "张三",
logName: function(age) {
console.log(this.name, age);
}
}
var fooNew = foo.logName;
var fooNewBind = foo.logName.bind(foo);
fooNew(10)//李四,10
fooNewBind(11)//张三,11 因为bind改变了fooNewBind里面的this指向
1.4.4 Собственная реализация вызова, применения и привязки
реализация вызова:
Function.prototype.newCall = function(context, ...parameter) {
if (typeof context === 'object' || typeof context === 'function') {
context = context || window
} else {
context = Object.create(null)
}
let fn = Symbol()
context[fn] = this
const res =context[fn](...parameter)
delete context.fn;
return res
}
let person = {
name: 'Abiel'
}
function sayHi(age,sex) {
console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男
применить реализацию:
Function.prototype.newApply = function(context, parameter) {
if (typeof context === 'object' || typeof context === 'function') {
context = context || window
} else {
context = Object.create(null)
}
let fn = Symbol()
context[fn] = this
const res=context[fn](...parameter);
delete context[fn]
return res
}
let person = {
name: "Abiel"
};
function sayHi(age, sex) {
console.log(this.name, age, sex);
}
sayHi.newApply (person,[ 25, '男']) //Abiel 25 男
Вызовите и примените сравнение инкапсуляции. Фактически, основной код такой же, за исключением того, что при вызове необходимо деконструировать второй параметр.
связать реализацию:
Function.prototype.bind = function (context,...innerArgs) {
var me = this
return function (...finnalyArgs) {
return me.call(context,...innerArgs,...finnalyArgs)
}
}
let person = {
name: 'Abiel'
}
function sayHi(age,sex) {
console.log(this.name, age, sex);
}
let personSayHi = sayHi.bind(person, 25)
personSayHi('男')
1.4.5 Сходства и различия между тремя
То же самое: оба меняют эту точку, и оба могут получать параметры Отличия: bind и call получают один параметр, apply — получение массива
1.5 Функция троттлинга и антитряски
Типы | концепция | заявление |
---|---|---|
дросселирование | После запуска события оно запускается один раз через равные промежутки времени и может запускаться несколько раз. | события прокрутки, изменения размера запускаются несколько раз в течение определенного периода времени |
Стабилизатор | Запускается один раз через период времени после того, как событие запускает действие для завершения | Событие прокрутки, изменения размера срабатывает через определенный период времени |
1.5.1 Дросселирование
// html 部分
<style>
*{padding:0;margin:0;}
.scroll-box{
width : 100%;
height : 500px;
background:blue;
overflow : auto;
}
.scroll-item{
height:1000px;
width:100%;
}
</style>
<body>
<div class="scroll-box">
<div class="scroll-item"></div>
</div>
</body>
// js 部分
let throttle = function (func, delay) {
let timer = null;
return function(){
if (!timer) {
timer = setTimeout(() => {
func.apply(this, arguments);
// 或者直接 func()
timer = null;
}, delay);
}
};
};
// 处理函数
function handle() {
console.log(arguments)
console.log(Math.random());
}
// 测试用例
document.getElementsByClassName('scroll-box')[0].addEventListener("scroll", throttle(handle,3000));
1.5.2 Защита от сотрясений
// html 部分同上
// js 部分
let debounce = function (fn, wait) {
let timeout = null;
return function () {
if (timeout !== null) clearTimeout(timeout);//如果多次触发将上次记录延迟清除掉
timeout = setTimeout(() => {
fn.apply(this, arguments);
// 或者直接 fn()
timeout = null;
}, wait);
};
}
// 处理函数
function handle() {
console.log(arguments)
console.log(Math.random());
}
// 测试用例
document.getElementsByClassName('scroll-box')[0].addEventListener("scroll", debounce(handle, 3000));
1.6 Цепочка прототипов
1.6.1 Определения
Цепочка свойств наследования объекта
1.6.2 Связь между конструктором, экземпляром и объектом-прототипом
var Person = function (name) { this.name = name; }//person是构造函数
var o3personTwo = new Person('personTwo')//personTwo是实例
Объекты-прототипы имеют свойство конструктора по умолчанию, указывающее на конструктор.
1.6.3 Методы создания экземпляров
1. Буквальный
let obj={'name':'张三'}
2. Создание конструктора объектов
let Obj=new Object()
Obj.name='张三'
3. Используйте фабричный шаблон для создания объектов
function createPerson(name){
var o = new Object();
o.name = name;
return o;
}
var person1 = createPerson('张三');
4. Используйте конструктор для создания объектов
function Person(name){
this.name = name;
}
var person1 = new Person('张三');
1.6.4 Новый оператор
1. Создайте новый объект;
2. это указывает на конструктор;
3. Если конструктор вернется, он заменит новый объект, если нет, то это будет новый объект
4. Вручную инкапсулировать новый оператор
var new2 = function (func) {
var o = Object.create(func.prototype);//创建对象
var k = func.call(o);//改变this指向,把结果付给k
if (k && k instanceof Object) {//判断k的类型是不是对象
return k; //是,返回k
} else {
return o;//不是返回返回构造函数的执行结果
}
}
1.6.5 Цепочка прототипов объектов
1.7 Способ наследования
JS — слабо типизированный динамический язык, инкапсуляция и наследование — его две основные характеристики.
1.7.1 Наследование цепочки прототипов
Использовать экземпляр родительского класса в качестве прототипа дочернего класса 1. Реализация кода Определите родительский класс:
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
Подкласс:
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);//cat
console.log(cat.eat('fish'));//cat正在吃:fish undefined
console.log(cat.sleep());//cat正在睡觉! undefined
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
2. Преимущества и недостатки Просто и легко реализовать, но если вы хотите добавить свойства и методы к подклассам, вы должны выполнить их после операторов, таких как new Animal(), которые не могут обеспечить множественное наследование.
1.7.2 Конструктивное наследование
Суть в том, чтобы использовать вызов для изменения этой точки в Cat 1. Реализация кода Подкласс:
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
2. Преимущества и недостатки Множественное наследование может быть достигнуто, но свойства/методы прототипа не могут быть унаследованы
1.7.3 Наследование экземпляра
Добавьте новые свойства в экземпляр родительского класса и верните его как экземпляр дочернего класса. 1. Реализация кода Подкласс
function Cat(name){
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}
2. Преимущества и недостатки Не ограничивает вызывающий метод, но не может обеспечить множественное наследование
1.7.4 Наследование копирования
Скопируйте свойства и методы родительского класса в дочерний класс 1. Подкласс:
function Cat(name){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || 'Tom';
}
2. Преимущества и недостатки Поддерживает множественное наследование, но неэффективно и занимает память
1.7.5 Композиционное наследование
Вызывая структуру родительского класса, наследуйте свойства родительского класса и сохраняйте преимущества передачи параметров, а затем реализуйте повторное использование функций, используя экземпляр родительского класса в качестве прототипа дочернего класса. 1. Подкласс:
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
1.7.6 Наследование паразитарного состава
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
(function(){
// 创建一个没有实例方法的类
var Super = function(){};
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new Super();
})();
1.7.7 ES6 расширяет наследование
Механизм наследования ES6 заключается в том, чтобы сначала создать объект экземпляра this родительского класса (поэтому сначала должен быть вызван суперметод), а затем использовать конструктор подкласса для изменения этого объекта.
//父类
class Person {
//constructor是构造方法
constructor(skin, language) {
this.skin = skin;
this.language = language;
}
say() {
console.log('我是父类')
}
}
//子类
class Chinese extends Person {
constructor(skin, language, positon) {
//console.log(this);//报错
super(skin, language);
//super();相当于父类的构造函数
//console.log(this);调用super后得到了this,不报错,this指向子类,相当于调用了父类.prototype.constructor.call(this)
this.positon = positon;
}
aboutMe() {
console.log(`${this.skin} ${this.language} ${this.positon}`);
}
}
//调用只能通过new的方法得到实例,再调用里面的方法
let obj = new Chinese('红色', '中文', '香港');
obj.aboutMe();
obj.say();
1.8 Функции высшего порядка
1.8.1 Определения
Аргумент функции является функцией или возвращает функцию
1.8.2 Общие функции высшего порядка
map,reduce,filter,sort
1.8.3 Каррирование
1. Определение: передайте только часть параметров функции для ее вызова и позвольте ей вернуть функцию для обработки остальных параметров.
fn(a,b,c,d)=>fn(a)(b)(c)(d)
2. Реализация кода:
const currying = fn => {
const len = fn.length
return function curr (...args1) {
if (args1.length >= len) {
return fn(...args1)
}
return (...args2) => curr(...args1, ...args2)
}
}
1.8.4 Защита от каррирования
1. Определение:
obj.func(arg1, arg2)=>func(obj, arg1, arg2)
2. Реализация кода:
Function.prototype.uncurrying = function() {
var that = this;
return function() {
return Function.prototype.call.apply(that, arguments);
}
};
function sayHi () {
return "Hello " + this.value +" "+[].slice.call(arguments);
}
let sayHiuncurrying=sayHi.uncurrying();
console.log(sayHiuncurrying({value:'world'},"hahaha"));
1.8.5 Частичные функции
1. Определение: укажите некоторые параметры, чтобы вернуть форму новой пользовательской функции. 2. Пример:
function foo(a, b, c) {
return a + b + c;
}
function func(a, b) {
return foo(a,b,8);
}
2. Объект
2.1 Метод объявления объекта
2.1.1 Литералы
var test2 = {x:123,y:345};
console.log(test2);//{x:123,y:345};
console.log(test2.x);//123
console.log(test2.__proto__.x);//undefined
console.log(test2.__proto__.x === test2.x);//false
2.1.2 Конструктор
var test1 = new Object({x:123,y:345});
console.log(test1);//{x:123,y:345}
console.log(test1.x);//123
console.log(test1.__proto__.x);//undefined
console.log(test1.__proto__.x === test1.x);//false
Роль новых: 1. Создайте новый объект; 2. это указывает на конструктор; 3. Если конструктор вернется, он заменит новый объект, если нет, то это будет новый объект
2.1.3 Встроенные методы
Obejct.create(obj, descriptor), obj — это объект, описание свойства дескриптора (необязательно)
let test = Object.create({x:123,y:345});
console.log(test);//{}
console.log(test.x);//123
console.log(test.__proto__.x);//123
console.log(test.__proto__.x === test.x);//true
2.1.4 Преимущества и недостатки трех методов
1. Функция: может реализовать объявление объекта, а также может присваивать и принимать значения.
2. Наследование: объекты, созданные встроенными методами, наследуют от свойства __proto__.
3. Скрытые свойства: три метода объявления будут генерировать некоторые скрытые свойства для каждого внутреннего члена (свойства или метода) по умолчанию. Эти скрытые свойства доступны для чтения и настройки. См. классификацию свойств ниже.
4. Чтение свойства: Object.getOwnPropertyDescriptor() или getOwnPropertyDescriptor()
5. Настройки свойств: Object.definePropertype или Object.defineProperties
2.2 Свойства объекта
2.2.1 Классификация атрибутов
1. Атрибуты данных имеют 4 характеристики: configurable (настраиваемый), enumerable (перечисляемый), writable (модифицируемый), value (значение свойства)
2. Характеристики свойства 2 аксессуара: получить (получить), установить (установить)
3. Внутренние свойства Свойства, используемые внутри движка JavaScript; Невозможно получить доступ напрямую, но можно получить косвенный доступ через встроенный метод объекта, например: [[Prototype]] можно получить через Object.getPrototypeOf(); Внутреннее свойство представлено [[]], что является абстрактной операцией, и нет имени свойства, соответствующего строковому типу, например [[Prototype]].
2.2.2 Дескрипторы свойств
1. Определение: закодируйте все свойства атрибута в объект и верните его. 2. Атрибуты дескриптора: атрибуты данных и атрибуты доступа. 3. Область применения: В качестве второго параметра методов Object.defineProperty, Object.getOwnPropertyDescriptor, Object.create,
2.2.3 Значения по умолчанию для дескрипторов атрибутов
1. Доступ к свойствам существования объекта
имя функции | По умолчанию |
---|---|
value | соответствующее значение атрибута |
get | соответствующее значение атрибута |
set | undefined |
writable | true |
enumerable | true |
configurable | true |
Таким образом, свойства, которые уже существуют через три вышеуказанных метода объявления, имеют эти дескрипторы по умолчанию. | |
2. Доступ к свойствам объектов, которых не существует | |
имя функции | По умолчанию |
- | - |
value | undefined |
get | undefined |
set | undefined |
writable | false |
enumerable | false |
configurable | false |
2.2.3 Правила использования атрибутов дескриптора
get, set и wriable, value являются взаимоисключающими, если есть параметр пересечения, будет сообщено об ошибке
2.2.4 Определение атрибута
1. Есть две функции для определения свойств: Object.defineProperty и Object.defineProperties, например: Object.defineProperty(obj, propName, desc)
2. Внутри движка он будет преобразован в вызов метода следующим образом: obj.[[DefineOwnProperty]](propName, desc, true)
2.2.5 Назначение атрибута
1. Оператор присваивания (=) вызывает [[Put]].Например: obj.prop = v;
2. Внутри движка он будет преобразован в вызов метода следующим образом: obj.[[Put]]("prop", v, isStrictModeOn)
2.2.6 Оценка свойств объекта
имя | имея в виду | Применение |
---|---|---|
in | Если указанное свойство находится в указанном объекте или его цепочке прототипов, оператор в операторе возвращает true | 'name' in test //true |
hasOwnProperty() | судить только о своих свойствах | test.hasOwnProperty('name') //true |
.или[] | Если свойство не существует в цепочке объектов или прототипов, оно вернет неопределенное значение. | test.name //"lei" test["name"] //"lei" |
## 2.3.Symbol | ||
### 2.3.1 Концепция | ||
является типом данных; | ||
Не ново, потому что Symbol — это примитивное значение, а не объект. | ||
### 2.3.2 Определение методов | ||
Symbol(), может передавать параметры |
var s1 = Symbol();
var s2 = Symbol();
s1 === s2 // false
// 有参数的情况
var s1 = Symbol("foo");
var s2 = Symbol("foo");
s1 === s2 // false
2.3.3 Использование
1. Не может работать с другими типами значений; 2. Как имя свойства
let mySymbol = Symbol();
// 第一种写法
var a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
var a = {
[mySymbol]: 'Hello!'
};
// 第三种写法
var a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
3. В качестве имени атрибута объекта нельзя использовать оператор точки, можно использовать []
let a = {};
let name = Symbol();
a.name = 'lili';
a[name] = 'lucy';
console.log(a.name,a[name]);
4. Обход не будет получать свойство по for...in, for...of и Object.keys(), Object.getOwnPropertyNames()
2.3.4 Symbol.for
1. Определение: Найдите в глобальном масштабе значение символа с этим параметром в качестве имени, если он есть, верните значение символа, в противном случае создайте новый и верните значение символа со строкой в качестве имени. 2. Пример:
var s1 = Symbol.for('foo');
var s2 = Symbol.for('foo');
s1 === s2 // true
2.3.5 Symbol.keyFor
1. Определение: возвращает ключ зарегистрированного значения типа символа. 2. Пример:
var s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
var s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
2.4. Обход
2.4.1 Метод обхода объекта первого уровня
метод | характеристика |
---|---|
for ... in | Проход через собственные и унаследованные перечисляемые свойства объекта (за исключением свойств Symbol) |
Object.keys(obj) | Возвращает массив всех перечисляемых свойств самого объекта (без наследования) (без свойств Symbol) |
Object.getOwnPropertyNames(obj) | Возвращает массив, включающий все перечисляемые и необработанные свойства самого объекта (за исключением свойств Symbol) |
Object.getOwnPropertySymbols(obj) | Возвращает массив, который содержит все свойства символов самого объекта |
Reflect.ownKeys(obj) | Возвращает массив, содержащий все (неперечислимые, перечисляемые и символьные) свойства самого объекта. |
Reflect.enumerate(obj) | Возвращает объект Iterator, который проходит через все перечисляемые свойства самого объекта и наследуется (за исключением свойств Symbol) |
Резюме: 1. Только Object.getOwnPropertySymbols(obj) и Reflect.ownKeys(obj) могут получить свойство Symbol | |
2. Только Reflect.ownKeys(obj) может получить неперечисляемые свойства |
2.4.2 Многоуровневый обход объекта
Модель данных:
var treeNodes = [
{
id: 1,
name: '1',
children: [
{
id: 11,
name: '11',
children: [
{
id: 111,
name: '111',
children:[]
},
{
id: 112,
name: '112'
}
]
},
{
id: 12,
name: '12',
children: []
}
],
users: []
},
];
рекурсия:
var parseTreeJson = function(treeNodes){
if (!treeNodes || !treeNodes.length) return;
for (var i = 0, len = treeNodes.length; i < len; i++) {
var childs = treeNodes[i].children;
console.log(treeNodes[i].id);
if(childs && childs.length > 0){
parseTreeJson(childs);
}
}
};
console.log('------------- 递归实现 ------------------');
parseTreeJson(treeNodes);
2.5. Глубокое копирование
2.5.1 Object.assign
1. Определение: Скопируйте все перечисляемые свойства исходного объекта (источника) в целевой объект (цель). 2. Использование:
合并多个对象
var target = { a: 1, b: 1 };
var source1 = { b: 2, c: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
3. Примечание: Это псевдоглубокая копия, копировать можно только первый слой
2.5.2 JSON.stringify
1. Принцип: Преобразование объектов в строки, а строки — это простые типы данных.
2.5.3 Рекурсивное копирование
function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
for(let keys in source){ // 遍历目标
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{ // 如果不是,就直接赋值
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
2.6 Перехват данных
Определение: используйте встроенный метод объекта для установки свойства, а затем измените значение свойства объекта.
2.6.1 Object.defineProterty
1. Метод из ES5; 2. Три параметра: объект (обязательно), значение атрибута (обязательно), дескриптор (необязательно); 3.defineProterty свойство дескриптора
数据属性:value,writable,configurable,enumerable
访问器属性:get,set
注:不能同时设置value和writable,这两对属性是互斥的
4. Два случая перехвата объектов:
let obj = {name:'',age:'',sex:'' },
defaultName = ["这是姓名默认值1","这是年龄默认值1","这是性别默认值1"];
Object.keys(obj).forEach(key => {
Object.defineProperty(obj, key, {
get() {
return defaultName;
},
set(value) {
defaultName = value;
}
});
});
console.log(obj.name);
console.log(obj.age);
console.log(obj.sex);
obj.name = "这是改变值1";
console.log(obj.name);
console.log(obj.age);
console.log(obj.sex);
let objOne={},defaultNameOne="这是默认值2";
Object.defineProperty(obj, 'name', {
get() {
return defaultNameOne;
},
set(value) {
defaultNameOne = value;
}
});
console.log(objOne.name);
objOne.name = "这是改变值2";
console.log(objOne.name);
5. Перехват изменений массива
let a={};
bValue=1;
Object.defineProperty(a,"b",{
set:function(value){
bValue=value;
console.log("setted");
},
get:function(){
return bValue;
}
});
a.b;//1
a.b=[];//setted
a.b=[1,2,3];//setted
a.b[1]=10;//无输出
a.b.push(4);//无输出
a.b.length=5;//无输出
a.b;//[1,10,3,4,undefined];
Вывод: defineProperty не может определить присвоение индекса массива и изменить длину массива; Но работа с методами массива может обнаружить
Многоуровневый мониторинг вложенных объектов
let info = {};
function observe(obj) {
if (!obj || typeof obj !== "object") {
return;
}
for (var i in obj) {
definePro(obj, i, obj[i]);
}
}
function definePro(obj, key, value) {
observe(value);
Object.defineProperty(obj, key, {
get: function() {
return value;
},
set: function(newval) {
console.log("检测变化", newval);
value = newval;
}
});
}
definePro(info, "friends", { name: "张三" });
info.friends.name = "李四";
6. Проблемы
不能监听数组索引赋值和改变长度的变化
必须深层遍历嵌套的对象,因为defineProterty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历,如果属性值也是对象那么需要深度遍历,显然能劫持一个完整的对象是更好的选择
2.6.2 proxy
1. Метод из ES6 по сути является перехватом объекта и предоставляет 13 методов обработки
2. Два параметра: объект и функция поведения
let handler = {
get(target, key, receiver) {
console.log("get", key);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log("set", key, value);
return Reflect.set(target, key, value, receiver);
}
};
let proxy = new Proxy(obj, handler);
proxy.name = "李四";
proxy.age = 24;
Включает многоуровневые объекты или многоуровневые массивы
//传递两个参数,一个是object, 一个是proxy的handler
//如果是不是嵌套的object,直接加上proxy返回,如果是嵌套的object,那么进入addSubProxy进行递归。
function toDeepProxy(object, handler) {
if (!isPureObject(object)) addSubProxy(object, handler);
return new Proxy(object, handler);
//这是一个递归函数,目的是遍历object的所有属性,如果不是pure object,那么就继续遍历object的属性的属性,如果是pure object那么就加上proxy
function addSubProxy(object, handler) {
for (let prop in object) {
if ( typeof object[prop] == 'object') {
if (!isPureObject(object[prop])) addSubProxy(object[prop], handler);
object[prop] = new Proxy(object[prop], handler);
}
}
object = new Proxy(object, handler)
}
//是不是一个pure object,意思就是object里面没有再嵌套object了
function isPureObject(object) {
if (typeof object!== 'object') {
return false;
} else {
for (let prop in object) {
if (typeof object[prop] == 'object') {
return false;
}
}
}
return true;
}
}
let object = {
name: {
first: {
four: 5,
second: {
third: 'ssss'
}
}
},
class: 5,
arr: [1, 2, {arr1:10}],
age: {
age1: 10
}
}
//这是一个嵌套了对象和数组的数组
let objectArr = [{name:{first:'ss'}, arr1:[1,2]}, 2, 3, 4, 5, 6]
//这是proxy的handler
let handler = {
get(target, property) {
console.log('get:' + property)
return Reflect.get(target, property);
},
set(target, property, value) {
console.log('set:' + property + '=' + value);
return Reflect.set(target, property, value);
}
}
//变成监听对象
object = toDeepProxy(object, handler);
objectArr = toDeepProxy(objectArr, handler);
//进行一系列操作
console.time('pro')
objectArr.length
objectArr[3];
objectArr[2]=10
objectArr[0].name.first = 'ss'
objectArr[0].arr1[0]
object.name.first.second.third = 'yyyyy'
object.class = 6;
object.name.first.four
object.arr[2].arr1
object.age.age1 = 20;
console.timeEnd('pro')
3. Проблемы и преимущества объект Reflect не имеет конструктора Вы можете следить за назначением индекса массива, изменять длину массива, Это прямой мониторинг изменений объекта без глубокого обхода
2.6.3 Сравнение defineProterty и прокси
1. defineProterty — стандарт es5, прокси — стандарт es6;
2. Прокси может следить за присвоением индекса массива и изменять длину массива;
3.proxy — прослушивающий объект, без глубокого обхода, defineProterty — слушающее свойство;
3. Используйте defineProterty для реализации двусторонней привязки данных (ядро, используемое vue2.x) 4. Используйте прокси для двусторонней привязки данных (будет использоваться vue3.x)
3. Массив
Массивы в основном исследуют методы массива немного больше, поэтому здесь мы просто вводим методы общих массивов сцен, и есть много сцен, которые будут добавлены позже;
В этой статье в основном рассказывается о некоторых хитрых операциях API массива из приложения;
Такие как строка кода, сглаживающая n-мерные массивы, дедупликация массива, нахождение максимального значения массива, суммирование массива, сортировка, преобразование объекта и массива и т. д.;
Можете ли вы реализовать приведенные выше сценарии приложений с помощью одной строки кода?
3.1 Сглаживание n-мерных массивов
1. Последняя глава
[1,[2,3]].flat(1) //[1,2,3]
[1,[2,3,[4,5]]].flat(2) //[1,2,3,4,5]
[1,[2,3,[4,5]]].toString() //'1,2,3,4,5'
[1[2,3,[4,5[...]].flat(Infinity) //[1,2,3,4...n]
Array.flat(n) — это API плоского массива ES10, n представляет размерность, а размерность бесконечна, когда значение n равно Infinity.
2. Начало
function flatten(arr) {
while(arr.some(item=>Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
flatten([1,[2,3]]) //[1,2,3]
flatten([1,[2,3,[4,5]]) //[1,2,3,4,5]
Суть в том, чтобы использовать рекурсию и метод слияния массивов concat для достижения выравнивания
3.2 Дедупликация
1. Последняя глава
Array.from(new Set([1,2,3,3,4,4])) //[1,2,3,4]
[...new Set([1,2,3,3,4,4])] //[1,2,3,4]
set — это новый тип данных в ES6, определяющий неповторяющиеся массивы. Array.from должен преобразовать массив классов в массив ...является оператором распространения, который преобразует значение в наборе в строку 2. Начало
Array.prototype.distinct = function() {
const map = {}
const result = []
for (const n of this) {
if (!(n in map)) {
map[n] = 1
result.push(n)
}
}
return result
}
[1,2,3,3,4,4].distinct(); //[1,2,3,4]
Получите новое значение массива и сравните два значения массива в цикле
3.3 Сортировка
1. Последняя глава
[1,2,3,4].sort((a, b) => a - b); // [1, 2,3,4],默认是升序
[1,2,3,4].sort((a, b) => b - a); // [4,3,2,1] 降序
sort — встроенный в js метод сортировки, параметр — функция 2. Начало Пузырьковая сортировка:
Array.prototype.bubleSort=function () {
let arr=this,
len = arr.length;
for (let outer = len; outer >= 2; outer--) {
for (let inner = 0; inner <= outer - 1; inner++) {
if (arr[inner] > arr[inner + 1]) {
//升序
[arr[inner], arr[inner + 1]] = [arr[inner + 1], arr[inner]];
console.log([arr[inner], arr[inner + 1]]);
}
}
}
return arr;
}
[1,2,3,4].bubleSort() //[1,2,3,4]
сортировка выбором
Array.prototype.selectSort=function () {
let arr=this,
len = arr.length;
for (let i = 0, len = arr.length; i < len; i++) {
for (let j = i, len = arr.length; j < len; j++) {
if (arr[i] > arr[j]) {
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
}
return arr;
}
[1,2,3,4].selectSort() //[1,2,3,4]
3.4 Максимум
1. Последняя глава
Math.max(...[1,2,3,4]) //4
Math.max.apply(this,[1,2,3,4]) //4
[1,2,3,4].reduce( (prev, cur,curIndex,arr)=> {
return Math.max(prev,cur);
},0) //4
Math.max() — это встроенный метод объекта Math, а параметр — это строка; reduce — это массив api ES5, параметры имеют функции и начальные значения по умолчанию; Функция имеет четыре параметра: pre (последнее возвращаемое значение), cur (текущее значение), curIndex (индекс текущего значения), arr (текущий массив).
2. Начало Сначала сортируйте, затем оценивайте
3.5 Подведение итогов
1. Последняя глава
[1,2,3,4].reduce(function (prev, cur) {
return prev + cur;
},0) //10
2. Начало
function sum(arr) {
var len = arr.length;
if(len == 0){
return 0;
} else if (len == 1){
return arr[0];
} else {
return arr[0] + sum(arr.slice(1));
}
}
sum([1,2,3,4]) //10
Используйте срез для перехвата и изменения массива, а затем используйте рекурсивное суммирование
3.6 Слияние
1. Последняя глава
[1,2,3,4].concat([5,6]) //[1,2,3,4,5,6]
[...[1,2,3,4],...[4,5]] //[1,2,3,4,5,6]
let arrA = [1, 2], arrB = [3, 4]
Array.prototype.push.apply(arrA, arrB))//arrA值为[1,2,3,4]
2. Начало
let arr=[1,2,3,4];
[5,6].map(item=>{
arr.push(item)
})
//arr值为[1,2,3,4,5,6],注意不能直接return出来,return后只会返回[5,6]
3.7 Определить, содержит ли он значение
1. Последняя глава
[1,2,3].includes(4) //false
[1,2,3].indexOf(4) //-1 如果存在换回索引
[1, 2, 3].find((item)=>item===3)) //3 如果数组中无值返回undefined
[1, 2, 3].findIndex((item)=>item===3)) //2 如果数组中无值返回-1
include(), find(), findIndex() — это API ES6.
2. Начало
[1,2,3].some(item=>{
return item===3
}) //true 如果不包含返回false
3.8 Преобразование массива классов
1. Последняя глава
Array.prototype.slice.call(arguments) //arguments是类数组(伪数组)
Array.prototype.slice.apply(arguments)
Array.from(arguments)
[...arguments]
Подобный массиву: указывает, что он имеет свойство длины, но не имеет метода массива.
вызов, применение: изменить это в срезе, чтобы указать на аргументы, поэтому аргументы также могут вызывать метод массива
Array.from предназначен для создания массива или итерируемого объекта в виде массива.
... состоит в том, чтобы расширить массив классов в строку, а затем определить его как массив
2. Начало
Array.prototype.slice = function(start,end){
var result = new Array();
start = start || 0;
end = end || this.length; //this指向调用的对象,当用了call后,能够改变this的指向,也就是指向传进来的对象,这是关键
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
}
3.9 Каждое значение настройки
1. Последняя глава
[1,2,3].fill(false) //[false,false,false]
fill — это метод ES6. 2. Начало
[1,2,3].map(() => 0)
3.10 Удовлетворен ли каждый пункт
[1,2,3].every(item=>{return item>2}) //false
каждый является API ES5, и каждый элемент удовлетворяется и возвращает true
3.11 Есть тот, который удовлетворяет
[1,2,3].some(item=>{return item>2}) //true
some - это API ES5, есть один элемент, который возвращает true
3.12 Фильтрация массивов
[1,2,3].filter(item=>{return item>2}) //[3]
filter — это API ES5, который возвращает массив, удовлетворяющий добавленным элементам.
3.13 Преобразование объектов и массивов
Object.keys({name:'张三',age:14}) //['name','age']
Object.values({name:'张三',age:14}) //['张三',14]
Object.entries({name:'张三',age:14}) //[[name,'张三'],[age,14]]
Object.fromEntries([name,'张三'],[age,14]) //ES10的api,Chrome不支持 , firebox输出{name:'张三',age:14}
3.14 Массивы объектов
[{count:1},{count:2},{count:3}].reduce((p, e)=>p+(e.count), 0)
4. Структуры данных
Структура данных — это то, как компьютер хранит и организует данные, а алгоритм — это систематическое описание стратегии решения проблемы. Понимание основных структур данных и алгоритмов может улучшить производительность и качество вашего кода.
Это также важный навык для продвинутых программистов.
Ручной код для реализации стека, очереди, связанного списка, словаря, двоичного дерева, динамического программирования и жадного алгоритма.
4.1 Стек
Характеристики стека: первый пришел, последний вышел
class Stack {
constructor() {
this.items = [];
}
// 入栈
push(element) {
this.items.push(element);
}
// 出栈
pop() {
return this.items.pop();
}
// 末位
get peek() {
return this.items[this.items.length - 1];
}
// 是否为空栈
get isEmpty() {
return !this.items.length;
}
// 长度
get size() {
return this.items.length;
}
// 清空栈
clear() {
this.items = [];
}
}
// 实例化一个栈
const stack = new Stack();
console.log(stack.isEmpty); // true
// 添加元素
stack.push(5);
stack.push(8);
// 读取属性再添加
console.log(stack.peek); // 8
stack.push(11);
console.log(stack.size); // 3
console.log(stack.isEmpty); // false
4.2 Очередь
Очередь: первый пришел первый вышел очередь класса { конструктор (элементы) { this.items = предметы || []; }
enqueue(element) {
this.items.push(element);
}
dequeue() {
return this.items.shift();
}
front() {
return this.items[0];
}
clear() {
this.items = [];
}
get size() {
return this.items.length;
}
get isEmpty() {
return !this.items.length;
}
print() {
console.log(this.items.toString());
}
}
const queue = new Queue();
console.log(queue.isEmpty); // true
queue.enqueue("John");
queue.enqueue("Jack");
queue.enqueue("Camila");
console.log(queue.size); // 3
console.log(queue.isEmpty); // false
queue.dequeue();
queue.dequeue();
4.3 Связанный список
Связанный список:
Хранит коллекцию упорядоченных элементов;
Но в отличие от массивов каждый элемент состоит из узла, в котором хранится сам элемент и ссылка на следующий элемент.
Чтобы получить доступ к элементу в середине связанного списка, вам нужно пройти от начальной точки, чтобы найти нужный элемент
class Node {
constructor(element) {
this.element = element;
this.next = null;
}
}
// 链表
class LinkedList {
constructor() {
this.head = null;
this.length = 0;
}
// 追加元素
append(element) {
const node = new Node(element);
let current = null;
if (this.head === null) {
this.head = node;
} else {
current = this.head;
while (current.next) {
current = current.next;
}
current.next = node;
}
this.length++;
}
// 任意位置插入元素
insert(position, element) {
if (position >= 0 && position <= this.length) {
const node = new Node(element);
let current = this.head;
let previous = null;
let index = 0;
if (position === 0) {
this.head = node;
node.next = current;
} else {
while (index++ < position) {
previous = current;
current = current.next;
}
node.next = current;
previous.next = node;
}
this.length++;
return true;
}
return false;
}
// 移除指定位置元素
removeAt(position) {
// 检查越界值
if (position > -1 && position < this.length) {
let current = this.head;
let previous = null;
let index = 0;
if (position === 0) {
this.head = current.next;
} else {
while (index++ < position) {
previous = current;
current = current.next;
}
previous.next = current.next;
}
this.length--;
return current.element;
}
return null;
}
// 寻找元素下标
findIndex(element) {
let current = this.head;
let index = -1;
while (current) {
if (element === current.element) {
return index + 1;
}
index++;
current = current.next;
}
return -1;
}
// 删除指定文档
remove(element) {
const index = this.findIndex(element);
return this.removeAt(index);
}
isEmpty() {
return !this.length;
}
size() {
return this.length;
}
// 转为字符串
toString() {
let current = this.head;
let string = "";
while (current) {
string += ` ${current.element}`;
current = current.next;
}
return string;
}
}
const linkedList = new LinkedList();
console.log(linkedList);
linkedList.append(2);
linkedList.append(6);
linkedList.append(24);
linkedList.append(152);
linkedList.insert(3, 18);
console.log(linkedList);
console.log(linkedList.findIndex(24));
4.4 Словари
Словарь: Подобный объект, значение хранения по ключу и значением Словарь класса { Конструктор () { this.items = {}; }
set(key, value) {
this.items[key] = value;
}
get(key) {
return this.items[key];
}
remove(key) {
delete this.items[key];
}
get keys() {
return Object.keys(this.items);
}
get values() {
/*
也可以使用ES7中的values方法
return Object.values(this.items)
*/
// 在这里我们通过循环生成一个数组并输出
return Object.keys(this.items).reduce((r, c, i) => {
r.push(this.items[c]);
return r;
}, []);
}
}
const dictionary = new Dictionary();
dictionary.set("Gandalf", "gandalf@email.com");
dictionary.set("John", "johnsnow@email.com");
dictionary.set("Tyrion", "tyrion@email.com");
console.log(dictionary);
console.log(dictionary.keys);
console.log(dictionary.values);
console.log(dictionary.items);
4.5 Бинарное дерево
Особенности: древовидная структура с двумя поддеревьями на узел. класс NodeTree { конструктор (ключ) { этот.ключ = ключ; это.слева = ноль; это.право = ноль; } }
class BinarySearchTree {
constructor() {
this.root = null;
}
insert(key) {
const newNode = new NodeTree(key);
const insertNode = (node, newNode) => {
if (newNode.key < node.key) {
if (node.left === null) {
node.left = newNode;
} else {
insertNode(node.left, newNode);
}
} else {
if (node.right === null) {
node.right = newNode;
} else {
insertNode(node.right, newNode);
}
}
};
if (!this.root) {
this.root = newNode;
} else {
insertNode(this.root, newNode);
}
}
//访问树节点的三种方式:中序,先序,后序
inOrderTraverse(callback) {
const inOrderTraverseNode = (node, callback) => {
if (node !== null) {
inOrderTraverseNode(node.left, callback);
callback(node.key);
inOrderTraverseNode(node.right, callback);
}
};
inOrderTraverseNode(this.root, callback);
}
min(node) {
const minNode = node => {
return node ? (node.left ? minNode(node.left) : node) : null;
};
return minNode(node || this.root);
}
max(node) {
const maxNode = node => {
return node ? (node.right ? maxNode(node.right) : node) : null;
};
return maxNode(node || this.root);
}
}
const tree = new BinarySearchTree();
tree.insert(11);
tree.insert(7);
tree.insert(5);
tree.insert(3);
tree.insert(9);
tree.insert(8);
tree.insert(10);
tree.insert(13);
tree.insert(12);
tree.insert(14);
tree.inOrderTraverse(value => {
console.log(value);
});
console.log(tree.min());
console.log(tree.max());
5. Алгоритмы
5.1 Пузырьковый алгоритм
Пузырьковая сортировка, сортировка выбором, сортировка вставками — здесь я не буду вдаваться в подробности.
5.2 Фибоначчи
Особенности: Третий член равен сумме двух предыдущих
function fibonacci(num) {
if (num === 1 || num === 2) {
return 1
}
return fibonacci(num - 1) + fibonacci(num - 2)
}
5.3 Динамическое программирование
Особенности: благодаря глобальному планированию большая проблема разбивается на мелкие задачи для получения оптимального решения.
Случай: Минимальная сдача монет
Соединенные Штаты имеют следующие номиналы (монеты): d1=1, d2=5, d3=10, d4=25.
Если мы ищем 36 центов сдачи, мы можем использовать 1 25 центов, 1 10 центов и 1 пенни (1 цент).
class MinCoinChange {
constructor(coins) {
this.coins = coins
this.cache = {}
}
makeChange(amount) {
if (!amount) return []
if (this.cache[amount]) return this.cache[amount]
let min = [], newMin, newAmount
this.coins.forEach(coin => {
newAmount = amount - coin
if (newAmount >= 0) {
newMin = this.makeChange(newAmount)
}
if (newAmount >= 0 &&
(newMin.length < min.length - 1 || !min.length) &&
(newMin.length || !newAmount)) {
min = [coin].concat(newMin)
}
})
return (this.cache[amount] = min)
}
}
const rninCoinChange = new MinCoinChange([1, 5, 10, 25])
console.log(rninCoinChange.makeChange(36))
// [1, 10, 25]
const minCoinChange2 = new MinCoinChange([1, 3, 4])
console.log(minCoinChange2.makeChange(6))
// [3, 3]
5.4 Жадные алгоритмы
Особенности: Решайте проблемы с помощью оптимальных решений Используйте жадный алгоритм для решения случая в 2.3.
function MinCoinChange(coins) {
var coins = coins;
var cache = {};
this.makeChange = function(amount) {
var change = [],
total = 0;
for (var i = coins.length; i >= 0; i--) {
var coin = coins[i];
while (total + coin <= amount) {
change.push(coin);
total += coin;
}
}
return change;
};
}
var minCoinChange = new MinCoinChange([1, 5, 10, 25]); console.log(minCoinChange.makeChange(36)); console.log(minCoinChange.makeChange(34)); console.log(minCoinChange.makeChange(6));
6 шаблонов проектирования
Если шаблон проектирования применяется к проекту, он может реализовать повторное использование и разделение кода, а также улучшить качество кода. В этой статье в основном представлены 14 шаблонов проектирования. Для написания компонентов пользовательского интерфейса необходим пакетный фреймворк.
6.1 Простой заводской шаблон
1. Определение: также известный как статический фабричный метод, который предназначен для создания объекта и назначения свойств и методов.
2. Применение: извлеките те же свойства и методы класса и инкапсулируйте их в объект.
3. Код:
let UserFactory = function (role) {
function User(opt) {
this.name = opt.name;
this.viewPage = opt.viewPage;
}
switch (role) {
case 'superAdmin':
return new User(superAdmin);
break;
case 'admin':
return new User(admin);
break;
case 'user':
return new User(user);
break;
default:
throw new Error('参数错误, 可选参数:superAdmin、admin、user')
}
}
//调用
let superAdmin = UserFactory('superAdmin');
let admin = UserFactory('admin')
let normalUser = UserFactory('user')
//最后得到角色,可以调用
6.2 Шаблон фабричного метода
1. Определение: абстракция класса продукта возлагает основную ответственность за создание экземпляров нескольких типов продуктов на бизнес-производителей.
2. Приложение: создать экземпляр
3. Код:
var Factory=function(type,content){
if(this instanceof Factory){
var s=new this[type](content);
return s;
}else{
return new Factory(type,content);
}
}
//工厂原型中设置创建类型数据对象的属性
Factory.prototype={
Java:function(content){
console.log('Java值为',content);
},
PHP:function(content){
console.log('PHP值为',content);
},
Python:function(content){
console.log('Python值为',content);
},
}
//测试用例
Factory('Python','我是Python');
6.3 Режим прототипа
1. Определение: Установите свойство прототипа функции 2. Применение: реализация наследования 3. Код:
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);//cat
console.log(cat.eat('fish'));//cat正在吃:fish undefined
console.log(cat.sleep());//cat正在睡觉! undefined
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
6.4 Одноэлементный шаблон
1. Определения: создается экземпляр класса только последовательно 2. Приложение: укажите пространство имен 3. Код:
let singleCase = function(name){
this.name = name;
};
singleCase.prototype.getName = function(){
return this.name;
}
// 获取实例对象
let getInstance = (function() {
var instance = null;
return function(name) {
if(!instance) {//相当于一个一次性阀门,只能实例化一次
instance = new singleCase(name);
}
return instance;
}
})();
// 测试单体模式的实例,所以one===two
let one = getInstance("one");
let two = getInstance("two");
6.5 Видный режим
1. Определение: обеспечить согласованный интерфейс для набора интерфейсов в подсистеме. 2. Применение: упрощение сложных интерфейсов. 3. Код:Внешний вид Режим
6.6 Режим адаптера
1. Определение: преобразование интерфейса в интерфейс, требуемый клиентом, без изменения кода клиента, чтобы несовместимый код мог работать вместе. 2. Применение: параметры функции адаптации 3. Код:режим адаптера
6.7 Шаблон декоратора
1. Определение: добавление свойств или методов к объекту без изменения исходного объекта. 2. Код
let decorator=function(input,fn){
//获取事件源
let input=document.getElementById(input);
//若事件源已经绑定事件
if(typeof input.onclick=='function'){
//缓存事件源原有的回调函数
let oldClickFn=input.onclick;
//为事件源定义新事件
input.onclick=function(){
//事件源原有回调函数
oldClickFn();
//执行事件源新增回调函数
fn();
}
}else{
//未绑定绑定
input.onclick=fn;
}
}
//测试用例
decorator('textInp',function(){
console.log('文本框执行啦');
})
decorator('btn',function(){
console.log('按钮执行啦');
})
6.8 Режим моста
1. Определение: отделение абстрактной части от части реализации, чтобы обе они могли меняться независимо друг от друга. 2. Кодрежим моста
6.9 Шаблон модульного метода
1. Определение: определите шаблон для последующего вызова с другими параметрами. 2. Код:шаблон метода модуля
6.10 Шаблон наблюдателя
1. Функция: решить связь между классами и объектами, объектами и объектами. 2. Код:
let Observer=
(function(){
let _message={};
return {
//注册接口,
//1.作用:将订阅者注册的消息推入到消息队列
//2.参数:所以要传两个参数,消息类型和处理动作,
//3.消息不存在重新创建,存在将消息推入到执行方法
regist:function(type,fn){
//如果消息不存在,创建
if(typeof _message[type]==='undefined'){
_message[type]=[fn];
}else{
//将消息推入到消息的执行动作
_message[type].push(fn);
}
},
//发布信息接口
//1.作用:观察这发布消息将所有订阅的消息一次执行
//2.参数:消息类型和动作执行传递参数
//3.消息类型参数必须校验
fire:function(type,args){
//如果消息没有注册,则返回
if(!_message[type]) return;
//定义消息信息
var events={
type:type, //消息类型
args:args||{} //消息携带数据
},
i=0,
len=_message[type].length;
//遍历消息
for(;i<len;i++){
//依次执行注册消息
_message[type][i].call(this,events);
}
},
//移除信息接口
//1.作用:将订阅者注销消息从消息队列清除
//2.参数:消息类型和执行的动作
//3.消息参数校验
remove:function(type,fn){
//如果消息动作队列存在
if(_message[type] instanceof Array){
//从最后一个消息动作序遍历
var i=_message[type].length-1;
for(;i>=0;i--){
//如果存在该动作在消息队列中移除
_message[type][i]===fn&&_message[type].splice(i,1);
}
}
}
}
})()
//测试用例
//1.订阅消息
Observer.regist('test',function(e){
console.log(e.type,e.args.msg);
})
//2.发布消息
Observer.fire('test',{msg:'传递参数1'});
Observer.fire('test',{msg:'传递参数2'});
Observer.fire('test',{msg:'传递参数3'});
6.11 Режим состояния
1. Определение: изменение состояния объекта приводит к изменению поведения. 2. Функция: решить сложные, если суждения 3. Кодрежим состояния
6.12 Режим стратегии
1. Определение: определяет серию семейных алгоритмов и инкапсулирует каждый алгоритм отдельно, так что алгоритмы можно заменять друг другом, независимо от клиентов, которые используют алгоритм. 2. Кодрежим стратегии
6.13 Режим доступа
1. Определение: инкапсулировать некоторые атрибуты, которых тип данных не имеет посредством наследования, 2. Функция: Пусть объект имеет метод работы с массивом 3. Код:шаблон посетителя
6.14 Паттерн посредника
1. Определение: настройте промежуточный слой, который обрабатывает взаимодействие между объектами. 2. Код:модель посредника
7. HTTP
1.1 Что такое HTTP
HTTP — это протокол для подключения клиентов, шлюзов и серверов.
7.2 Особенности
Поддержка режима клиент/сервер: можно подключить клиент и сервер;
Просто и быстро: в запросе нужно только передать метод запроса, путь и тело запроса;
Гибкость: гибкие типы данных передачи;
Нет подключения: отключиться сразу после завершения запроса;
Без гражданства: невозможно вспомнить последний запрос.
7.3 Как решить проблемы без сохранения состояния и без установления соединения
Без сохранения состояния: сам протокол HTTP не может разрешить это состояние, только состояние сохраняется в файлах cookie и сеансах.Общий сценарий заключается в том, что состояние входа сохраняется;
Нет связи: вы можете поддерживать активность через собственное свойство.
7.4 Процесс запроса
Адрес запроса HTTP(S) → разрешение DNS → трехстороннее рукопожатие → запрос на отправку → волна четыре раза
Источник изображения процесса трехстороннего рукопожатия CSDN)вставьте сюда описание изображения
- Помахал четыре раза (источник изображения CSDN)
вставьте сюда описание изображения
7.5 Сравнение HTTP 0.9~3.0
7.5.1 HTTP 0.9
Разрешить клиенту отправлять только такие запросы GET;
И не поддерживает заголовки запросов, протокол поддерживает только обычный текст;
Без сохранения состояния каждый доступ обрабатывается независимо, и отключение завершается;
Нет кода состояния.
7.5.2 HTTP 1.0
С аутентификацией личности, трехстороннее рукопожатие; Поля заголовка поддержки запроса и ответа; содержимое заголовка запроса; |Имя атрибута|Значение| |--|--|--| |Принять |Допустимые типы MIME| |Accept-Encoding|Формат, в котором данные могут быть декодированы| |Accept-Language|Допустимые языки| |Соединение| значением keep-alive является длинное соединение| |Хост|Хост и порт| |Pragma| Следует ли кэшировать, укажите no-cache для возврата к обновлению| |Реферер|Маршрутизация страницы| |If-Modified-Since|значение времени|
Содержимое заголовка ответа;
|Имя атрибута|Значение| |-|-|-| |Соединение| значением keep-alive является длинное соединение| |Content-Type| Возвращает тип документа, распространенные значения: text/plain, text/html, text/json| |Дата|Время отправки сообщения| |Сервер|Имя сервера| |Last-Modified| — это время, s возвращает время последнего изменения| |Expires| Время истечения кэша, сравнение времени b и s| Уведомление
expires является содержимым заголовка ответа и возвращает фиксированное время, дефект заключается в том, что сервер необходимо перезагрузить, когда время истекло;
Если в заголовке запроса есть If-Modified-Since, сервер сравнит время с last-modified и вернет 304;
Объект ответа начинается со строки состояния ответа;
Гипертекст не ограничен объектом ответа;
Поддержка методов GET, HEAD, POST;
имеет код состояния;
Поддерживает длинные соединения (но короткие соединения используются по умолчанию), механизмы кэширования и аутентификацию.
7.5.3 HTTP 1.1
Добавьте Cache-Control в заголовок запроса
|Имя атрибута|Значение| |-|-|-| |Cache-Control|Метод, представленный в 1.1, определяет механизм кэширования, за которым следуют запросы и ответы.Значения: общедоступные (кэшируются как b, так и s), частные (кэш b), без кэширования (не кэшируются), no-store (без кеша), max-age (время кеша, с - единица измерения), min-fresh (минимальное время обновления), max-age=3600| |If-None-Match | Значение etag, возвращаемое заголовком ответа последнего запроса, добавляет Cache-Control к заголовку ответа, указывая, могут ли все механизмы кэширования кэшировать и какой тип etag возвращает хэш-значение, второй заголовок запроса содержит сумма Сравнение стоимости сервера |
Уведомление
Возврат максимального возраста Cache-Control - это относительное время кэша. Cache-Control имеет более высокий приоритет, чем expires Недостаток: невозможно получить последний измененный файл в первый раз.
7.5.4 HTTP 2.0
Передача в бинарном формате;
Мультиплексирование фактически разделяет данные запроса на кадры и отправляет их в TCP не по порядку. TCP может иметь только один пар, поэтому он все равно будет блокироваться;
сжатие заголовков;
Сервер push активно отправляет статические ресурсы на сторону B, чтобы избежать задержек в оба конца.
7.5.5 HTTP 3.0
1. Он основан на протоколе QUIC, основанном на UDP.
2. Особенности:
Пользовательский механизм подключения: TCP идентифицируется по IP/порту, изменение рукопожатия при повторном подключении, UDP — это 64-битный идентификатор, соединение отсутствует;
Пользовательский механизм повторной передачи: TCP использует передачу порядковых номеров и ответов, QUIC использует передачу добавочных порядковых номеров; неблокирующее мультиплексирование: один и тот же QUIC может создавать несколько потоков.
7.5.6 HTTPS
1. https — это SSL, добавленный к протоколу http;
2. В основном включают: рукопожатие (обмен и проверка учетных данных) и протокол записи (шифрование данных).
7.5.7 Кэш
1. По протоколу: кеш уровня протокола и кеш протокола не-http:
1.1 Кэш уровня протокола: используйте настройку значения атрибута заголовка протокола http;
1.2 Кэш непротокольного уровня: используйте значение атрибута http-equiv метатега для Expires, set-cookie.
2. По кешу: сильный кеш и кеш согласования:
2.1 Надежный кеш: используйте параметры управления кешем и истечения срока действия, чтобы напрямую возвращать время истечения срока действия, чтобы в течение периода кеша не выполнялся запрос, If-modify-since;
2.2 Кэш согласования: заголовок ответа возвращает хеш-значение etag или last-modified, второй заголовок запроса If-none-match или IF-modify-since содержит последнее хэш-значение, и 304 возвращается, если они непротиворечивы.
3. Согласовать сравнение кеша: etag имеет более высокий приоритет, чем last-modified;
4. Тег etag имеет высокую точность, точность последнего изменения равна s, и будет записано, сколько раз etag изменялся в течение 1 с; производительность последнего изменения хорошая, и etag должен получить значение хеш-функции.
5. Процесс чтения кэша браузера:
Сначала он определит надежный кэш, а затем определит, существует ли etag кэша согласования (последнее изменение);
Существует значение, переносимое атрибутом If-None-match (If-Modified-since);
Запросите сервер, сервер сравнивает etag (последнее изменение) и возвращает 304, когда он вступает в силу.
Обновление F5 будет игнорировать сильный кеш и не будет игнорировать кеш согласования, ctrl+f5 будет недействительным
7.5.8 Код состояния
|Последовательность|Подробности| |-|-|-| |1XX(Уведомление)|| |2XX(успех)| 200(успех), 201(создание сервера), 202(сервер получил необработанное), 203(несанкционированная информация), 204(контент не возвращен), 205(сброс контента), 206(частичный контент))| |3XX(перенаправление)|301(перемещено навсегда), 302(перемещено временно), 303(см. другие местоположения), 304(без изменений), 305(использовать прокси), 307(временно перенаправлено)| |4XX(Ошибка клиента)|400(Неверный запрос), 401(Неавторизованный), 403(Запрещено), 404(Не найдено), 405(Метод отключен), 406(Не принято), 407(Требуется авторизация через прокси)| | 5XX (ошибка сервера) | 500 (исключение сервера), 501 (еще не реализовано), 502 (неверный шлюз), 503 (служба недоступна), 504 (время ожидания шлюза), 505 (версия HTTP не поддерживается) |
7.5.9 Анализ запросов браузера
7.5.10 Резюме
протокол
|Версия |Содержание| |-|-|-| |http0.9| Позволяет клиенту отправлять только GET-запросы такого типа; не поддерживает заголовки запросов, протокол поддерживает только обычный текст; без сохранения состояния, каждый доступ обрабатывается независимо, полное отключение; без кода состояния http1.0 устраняет недостатки версии 0.9, добавляя атрибуты If-modify-since(last-modify) и expires cache| |http1.x|Добавлены атрибуты cache-control и If-none-match(etag) cache| |http2.0|передача в двоичном формате, мультиплексирование, сжатие заголовков, отправка сервером| |http3.0|Использование протокола QUIC, настраиваемый механизм соединения, настраиваемый механизм повторной передачи, неблокирующее мультиплексирование| тайник
|Тип|Особенность| |-|-|-| |Сильный кеш| Устанавливается параметрами If-modify-since(last-modify), expires и cache-control, значением атрибута является время, поэтому в течение этого времени не требуется никаких запросов| |Negotiate Cache| Устанавливается с помощью If-none-match(etag), атрибут etag представляет собой хеш-значение, поэтому необходимо сравнить запрос со значением сервера|
8. Резюме
Это просто прочесывание нативного JS от элементарного до продвинутого;
Оригинальные кодовые слова не так просты, добро пожаловать, звезда!