Нативная поверхность JS от элементарного до продвинутого [почти 1,5 Вт слов]

внешний интерфейс JavaScript
Нативная поверхность JS от элементарного до продвинутого [почти 1,5 Вт слов]

предисловие

Пришло время начать волну основ 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)3 次握手.jpgвставьте сюда описание изображения

  1. Помахал четыре раза (источник изображения CSDN)

imageвставьте сюда описание изображения

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 от элементарного до продвинутого;
Оригинальные кодовые слова не так просты, добро пожаловать, звезда!