Двенадцать дополнительных знаний JS, сколько вы можете написать?

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

Преимущества и недостатки анализа нескольких наследств.

Наследование цепочки прототипов
            function Parent () {
                this.names = ["舔狗的泪"];
            }
            
            function Child () {
            
            }
            
            Child.prototype = new Parent();
            
            let child1 = new Child();

Недостаток 1: вы не можете передавать параметры Parent.

    child1.names.push(1)
    let child2=new Child()
    console.log(child2.names) // ["舔狗的泪",1]

Недостаток 2: операции над ссылочными типами несколькими экземплярами будут изменены.

вызов наследования
            function Parent () {
                this.names = "舔狗的泪";
            }
            
            Parent.prototype.getName=()=>{}
            
            function Child () {
                Parent.call(this,'可以传参')
            }
            
            let child1 = new Child();

Преимущества: может передавать параметры.
Недостаток: child1 не может получить метод выше родительского прототипа.

наследование композиции
            function Parent () {
                this.names = "舔狗的泪";
            }
            
            Parent.prototype.getName=()=>{}
            
            function Child () {
                Parent.call(this,'可以传参')
            }
            
            Child.prototype=new Parent()
            
            let child1 = new Child();

Преимущества: вы можете передавать параметры, чтобы получить методы родительского прототипа.
недостаток:new Child()Когда метод Parent в Child выполняется один раз,Child.prototype=new Parent()Родительский метод выполняется снова.

паразитарное наследование
     function createP(original) {
         //下面一行的代码意思 clone.prototype={ name: '舔狗的泪' }
        var clone = Object.create(original); 
        clone.getName  = function () {
          // 以某种方式来增强对象
          console.log(this.name)
        };
        return clone; 
      }
    
     var parent = { name: '舔狗的泪' };
     var child = createP(parent);

Недостаток 1: вы не можете передавать параметры Parent.
Недостаток 2: операции над ссылочными типами несколькими экземплярами будут изменены.

Наследование паразитарного состава
            function Parent () {
                this.names = ["舔狗的泪"];
            }
            
            Parent.prototype.getName=()=>{}
            
            function Child () {
                Parent.call(this,'可以传参')
            }
            
            Child.prototype=Object.create(Parent.prototype)
            Child.prototype.fn=()=>{}
            
            let child1 = new Child();

Вышеуказанные недостатки оптимизированы

позвонить, подать заявку, привязать реализацию

вызов может поддерживать несколько параметров

Использование: fn1.myCall1('указатель','параметр1','параметр2')

    Function.prototype.myCall1 = function (context,...arg) {
        // 如果没有传或传的值为空对象 context指向window
        context = context || window;
        let fn = mySymbol();
        context[fn] = this; //给context添加一个方法 指向this
        // 处理参数 去除第一个参数this 其它传入fn函数
        const result = context[fn](...arg); //执行fn
        delete context[fn]; //删除方法
        //返回函数调用的返回值
        return result;
      };

Анализ: контекст [Fn] Контекст объекта увеличивается путем добавления свойства Fn, что соответствует функции, которую вы указываете на это, а контекст [FN] () выполнен. Это внутри указывает на контекст, потому что это контекстный вызов.

apply

Использование: fn.myApply('указатель',['параметр 1','параметр 2']), что в основном совпадает с вызовом.

     Function.prototype.myApply = function (context, args) {
        context = context || window;
        args = args ? args : [];
        const fn = Symbol();
        context[fn] = this;
        const result = context[fn](...args);
        delete context[fn];
        return result;
      };
bind

Необходимо анализировать волну bind, большинство людей действительно не обязательно понимают. Использование: fn.myBind('указатель','параметр 1')('параметр 2').

    Function.prototype.myBind = function (context) {
        if (typeof this !== 'function') {
          throw new Error('请bind一个函数');
        }

        var self = this;
        var args = Array.prototype.slice.call(arguments, 1);

        var fBound = function () {
          var funArgs = Array.prototype.slice.call(arguments);
          return self.apply(
            this instanceof fNOP ? this : context,
            args.concat(funArgs)
          );
        };
        var fNOP = function () {};
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
      };

Почему эта линия сужденияthis instanceof fNOP ? this : context, когда в качестве конструктора используется bind, нет необходимости менять точку this. В сочетании со следующим рисунком это в fBound указывает на a в настоящее время.this instanceof fNOP ===true

    let A=Animal.bind(Cat,name)
    let a=new A()

Зачем писать следующие строки кода?
Когда в прототипе Animal есть другие методы, a недоступен.

        var fNOP = function () {};
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();

Тогда почему бы просто не использовать fBound.prototype=this.prototype?
Поскольку если fBound.prototype=this.prototype, указатели fBound.prototype и this.prototype указывают на одно и то же пространство памяти, изменения fBound.prototype повлияют на this.prototype.

Принцип реализации нового

  1. Создать пустой объект
  2. связь с прототипом этого нового объекта
  3. Выполнение методов конструктора, свойств и методов, указывающих на созданный объект
  4. Если в конструкторе не возвращается никакой другой объект, верните этот новый созданный объект, в противном случае верните объект, возвращенный в конструкторе.
        function _new(){
            let targetObj={}
            let [constructor,...args]=[...arguments]
            targetObj.__proto__=constructor.prototype
            let result =constructor.apply(targetObj,args)
            if(result&&(typeof (result)==='object'||typeof (result)==='function')){
                return result
            }

            return targetObj
        }

compose

Суть исходного кода redux applyMiddleware также заключается в методе compose, который выполняет мидлвар в строке. Вы можете взглянуть на исходный код Redux, когда у вас будет время, это действительно здорово. Я сильно имитирую исходный код, составленный с помощью функции передачи параметров.

        function middleware1(x){
            return x+1
        }
        function middleware2(x){
            return x+1
        }
        function middleware3(x){
            return x+1
        }
        function middleware4(x){
            return x+1
        }
        function compose(...funcs) {
            return arg => funcs.reduceRight((composed, f) => f(composed), arg);
        }
        compose(middleware1,middleware2,middleware3,middleware4)(0)

глубокая копия

Без версии WeakMap циклические ссылки вызовут бесконечный цикл, вызывающий утечку памяти.

       function deepClone1(obj){
            if(typeof obj==='object'&&obj!==null){
                let obj1=Array.isArray(obj) ? [] : {}
                for (let key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        obj1[key] = deepClone(obj[key]) // 递归拷贝
                    }
                }
                return obj1
            }
            return obj
        }
        let test={name:'aa',age:18}
        test.a=test
        let test1=deepClone1(test) //会报错 ,内存溢出

Ссылаясь на WeakMap, вышеупомянутая проблема переполнения может быть решена, как Map, так и WeakMap могут справиться

     function deepClone2(obj, hash = new WeakMap()){
            if(typeof obj==='object'&&obj!==null){
                if (hash.has(obj)) {
                    return hash.get(obj);
                }
                let obj1=Array.isArray(obj) ? [] : {}
                hash.set(obj, obj1);
                for (let key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        obj1[key] = deepClone2(obj[key],hash) 
                    }
                }
                return obj1
            }
            return obj
        }

выравнивание массива

   [1,2,3,[4,5,[6,7]]].flat(Infinity)  //[1, 2, 3, 4, 5, 6, 7]
    function flatter(arr) {
            if (!arr.length) return;
            return arr.reduce(
              (pre, next) =>
                Array.isArray(next) ? [...pre, ...flatter(next)] : [...pre, next],
              []
            );
        }

каррирование функций

fn.lengthОтносится к длине параметра addFn, потому что есть a, b, c, поэтому длина равна 3

  let curry = (fn, ...args) => args.length < fn.length ? (...arguments) => curry(fn, ...args, ...arguments) : fn(...args);

  function addFn(a, b, c) {
      return a + b + c;
  }
  var add = curry(addFn);
  
  add(1,2,3) //6
  add(1,2)(3) //6
  add(1)(2)(3) //6

Хук AsyncSeriesWaterfallHook в веб-пакете

Это асинхронный последовательный хук, следующая задача получает возвращаемое значение предыдущей задачи. На рисунке ниже показано использование.
webpackЯдром потока событий являетсяtapable,tapables9 крючков на пультеpluginsСерийное исполнение

	{ AsyncSeriesWaterfallHook } = require('tapable')
	let myAsyncSeriesWaterfallHook=new AsyncSeriesWaterfallHook(['name'])
	myAsyncSeriesWaterfallHook.tapAsync('1',(name,cb)=>{
		setTimeout(()=>{
			console.log('1',name)
			cb(null,'aa')
		},1000)
	})
	myAsyncSeriesWaterfallHook.tapAsync('2',(name,cb)=>{
		setTimeout(()=>{
			console.log('3',name)
			cb(null,'bb')
		},1000)
	})
	myAsyncSeriesWaterfallHook.tapAsync('3',(name,cb)=>{
		setTimeout(()=>{
			console.log('3',name)
			cb(null,'cc')
		},1000)
	})

	myAsyncSeriesWaterfallHook.callAsync('yang',()=>{
		console.log('end')
	})
    
        // 1 yang
        // 2 aa
        // 3 bb
        // end   

без помощиasync awaitЧтобы реализовать асинхронный последовательный хук,nextДействительно умное использование.

    
class AsyncSeriesWaterfallHook{
    constructor() {
        this.hooks = [];
    }
    tapAsync () {
        this.hooks.push(arguments[arguments.length-1]);
    }
    callAsync () {
        let args = Array.from(arguments); //将传进来的参数转化为数组
        let done = args.pop(); // 取出数组的最后一项 即成功后的回调函数
        let index = 0;
        let _this = this;
        function next(err, data) {
            if(index>=_this.hooks.length) return done();
            if (err) return done(err);
            let fn = _this.hooks[index++];
            if (index == 1) {
                fn(...args, next)
            } else {
                fn(data, next)
            }
        }
        next()
    }
}

ES6 class

nuggets.capable/post/702429…

Map Set

Наггетс.Талант/пост/702540…

Promise

Наггетс.Талант/пост/702689…

async await

nuggets.capable/post/702910…

Суммировать

Она была ошарашена на некоторое время, а потом пошла наверх.После того, как я вернулся в общежитие, я получил от нее сообщение и много написал... Общее содержание - отправить мне карточку хорошего человека, который есть в моей жизни. .Это был первый раз, когда я признался девушке, которая мне понравилась, и это был также первый раз, когда я почувствовал душевную боль.Я не знал, что ей ответить, поэтому всю ночь просматривал записи нашего чата...
В более поздний период я ​​жил в оцепенении каждый день, и ничем не мог интересоваться. Я больше не приносил ей завтрак. Мои отношения с ней также стали очень нежными. Я боялся, что она видеть меня каждый раз, на следующем уроке я найду место подальше от нее, и у нас с ней не было никакого общения, но я все еще скучаю по ней...
League of Legends доминировала в нашем университете в течение четырех лет. Интернет-кафе и общежития были в основном этой игрой. В то время кто-то в школе организовал соревнование по League of Legends. Каждый майор прислал команду для игры в игру. Как член команды , с постоянными победами в конкурсе, мы также привлекли внимание наших одноклассников. Многие ученики проявляют инициативу, чтобы поприветствовать меня, поболтать и пригласить меня поиграть вместе. Это первый раз, когда я чувствую, что я нахожусь в по крайней мере, не бесполезны. Когда мы вышли в топ-4, в ночь перед соревнованиями мои одноклассницы выразили нам свои наилучшие пожелания. Она также прислала мне ночью отдельное сообщение, сказав несколько слов ободрения. Я сдержал свое волнение и ответил: Хорошо."
В топ-4 я ​​пожертвовал своим Уэйном, сыгравшим 3000. В ранних командных боях и в более поздних командных боях я полагался на свои различные кокетливые позиции и волну «распыли это Q», чтобы положить конец противоположному, и в ту ночь я стал школьный пост бар дискуссия Горячие точки... (продолжение следует)