Was soll ich tun, wenn ich in einem JavaScript-Interview auf handgeschriebene Testfragen stoße? Zusammenfassung der Testfragen für handgeschriebenen Hochfrequenz-Front-End-Code

Implementierung von Anti-Shake und Throttling

function debounce(fn, delay) {
    
    
  var timer;
  return function () {
    
    
    var _this = this;
    var args = arguments;
    if (timer) {
    
    
      clearTimeout(timer);
    }
    timer = setTimeout(function () {
    
    
      fn.apply(_this, args);
    }, delay);
  };
}

function throttle(fn, delay) {
    
    
  var timer;
  return function () {
    
    
    var _this = this;
    var args = arguments;
    if (timer) {
    
    
      return;
    }
    timer = setTimeout(function() {
    
    
      fn.apply(_this, args); // 用apply指向调用debounce的对象,相当于_this.fn(args);
      timer = null;
    }, delay);
  }; 
}

Implementierung von JSONP

// jsonp原理:因为jsonp发送的并不是ajax请求,其实是动态创建script标签
// script标签是没有同源限制的,把script标签的src指向请求的服务端地址。
function jsonp(url, data = {
    
    }, callback = 'callback') {
    
    
  // 处理json对象,拼接url
  data.callback = callbak
  let params = []
  for (let key in data) {
    
    
    params.push(key + '=' + data[key])
  }
  let script = document.creatElement('script')
  script.src = url + '?' + params.join('&')
  document.body.appendChild(script)
  // 返回Promise
  return new Promise((resolve, reject) => {
    
    
    window[callback] = (data) => {
    
    
      try {
    
    
        resolve(data)
      } catch (e) {
    
    
        reject(e)
      } finally {
    
    
        // 移除script元素
        script.parentNode.removeChild(script)
        console.log(script)
      }
    }
  })
}
// 请求数据
jsonp('http://photo.sina.cn/aj/index', {
    
    
  page: 1,
  cate: 'recommend',
}, 'jsonCallback').then(data => {
    
    
  console.log(data)
})

Currying: Implementieren Sie sum, um sum(1)-, sum(1)(2,3)-Aufrufe zu unterstützen

Das Currying von Funktionen ist ein wichtiges Konzept in der funktionalen Programmierung in Javascript. Was es zurückgibt, ist eine Funktion von Funktionen. Seine Implementierung basiert auf Parametern und Rekursion und ruft durch Aufteilen von Parametern eine Funktionsmethode mit mehreren Parametern auf, um die Coderedundanz zu reduzieren und die Lesbarkeit zu verbessern.

function curry(fn, currArgs) {
    
    
  return function () {
    
    
    let args = [].slice.call(arguments);
    // 首次调用时,若未提供最后一个参数currArgs,则不用进行args的拼接
    if (currArgs !== undefined) {
    
    
      args = args.concat(currArgs);
    }
    // 递归调用
    if (args.length < fn.length) {
    
    
      return curry(fn, args);
    }
    // 递归出口
    return fn.apply(null, args);
  }
}

Analysieren Sie, wie die Curry-Funktion geschrieben ist:
Erstens hat sie zwei Parameter, fn bezieht sich auf die Quellverarbeitungsfunktionssumme am Anfang dieses Artikels. currArgs ist die Parameterliste, die beim Aufruf von Curry übergeben wird, z. B. (1, 2)(3).
Schauen Sie sich die Curry-Funktion noch einmal an. Sie wird eine anonyme Funktion als Ganzes zurückgeben.
Dann sei args = [].slice.call(arguments);, was bedeutet, die Argumente anzuordnen. arguments ist eine Array-ähnliche Struktur. Da es sich nicht um ein echtes Array handelt, können Array-Methoden nicht verwendet werden. Wir verwenden die Call-Methode und können problemlos die nativen Methoden des Arrays für Argumente verwenden.
Das Urteil von currArgs !== undefiniert besteht darin, das Problem des Parameterspleißens bei rekursiven Aufrufen zu lösen.
Bestimmen Sie abschließend, ob die Anzahl der Argumente gleich der Anzahl der Parameter von fn (also der Summe) ist. Wenn sie gleich sind, können Sie alle Parameter zur Ausgabe an fn übergeben, andernfalls Setzen Sie den rekursiven Aufruf fort, bis beide gleich sind.

Fügen Sie zwei Zeichenfolgennummern hinzu

function add(a, b) {
    
    
  // 小数前面补0
  const absLen = Math.abs(a.length - b.length)
  if (a.length > b.length) {
    
    
    b = Array(absLen).fill(0).join('') + b
  } else if (a.length < b.length) {
    
    
    a = Array(absLen).fill(0).join('') + a
  }
  const arrA = a.split('').reverse()
  const arrB = b.split('').reverse()
  let result = []
  let carry = 0 // 进位

  for (let i = 0; i < a.length; ++i) {
    
    
    let sum = parseInt(arrA[i]) + parseInt(arrB[i]) + carry
    result[i] = sum % 10
    carry = sum > 9 ? 1 : 0
  }
  if (carry === 1) {
    
    
    result[a.length] = 1
  }

  return result.reverse().join('')
 }

JS-Array reduzieren

var array = [[1, 2, 3], 4, 5, 6, [[7]], []]
var result = flatten(array)

console.log(result)

// 递归
function flatten(arr, result = []) {
    
    
  for (let item of arr) {
    
    
    if (Array.isArray(item))
      flatten(item, result)
    else
      result.push(item)
  }
  return result
}

// 迭代器实现
// 这里我们给数组的迭代器函数重新定义了 next 方法,
// 实现了一个 getFirst 用来递归取真正的第一个数组元素(无论嵌套多少层),
// 在对数组进行迭代操作的时候,会自动调用迭代器的 next 方法,获得我们一个个基本元素。
Array.prototype[Symbol.iterator] = function () {
    
    
  let arr = [].concat(this)
  const getFirst = function (array) {
    
    
    let first = array[0]
    // 去掉为 [] 的元素
    while (Array.isArray(array[0]) && array.length === 0) {
    
    
      array.shift()
    }
    if (Array.isArray(first)) {
    
    
      // 即将是 []
      if (first.length === 1) array.shift()
      return getFirst(first)
    } else {
    
    
      array.shift()
      return first
    }
  }
  return {
    
    
    next: function () {
    
    
      let item = getFirst(arr)
      if (item) {
    
    
        return {
    
    
          value: item,
          done: false,
        }
      } else {
    
    
        return {
    
    
          done: true,
        }
      }
    },
  }
}
// 生成器实现
function* flat(arr) {
    
    
  for (let item of arr) {
    
    
    if (Array.isArray(item))
      yield* flat(item)
    else
      yield item
  }
}

function flatten(arr) {
    
    
  let result = []
  for (let val of flat(arr)) {
    
    
    result.push(val)
  }
  return result
}


// reduce
function flatten(arr) {
    
    
  return arr.reduce((flat, toFlatten) => {
    
    
    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
  }, []);
}

Die längste sich nicht wiederholende Teilsequenz einer Zeichenfolge

// 12343210 => 43210
var lengthOfLongestSubstring = function (s) {
    
    
  let arr = [], max = 0
  for (let i = 0; i < s.length; i++) {
    
    
    let index = arr.indexOf(s[i])
    if (index !== -1) {
    
    
      arr.splice(0, index + 1);
    }
    arr.push(s.charAt(i))
    max = Math.max(arr.length, max)
  }
  return max
};
// chain = new Chain, chain.eat().sleep(5).eat().sleep(6).work()
Class Chain{
    
    
  Task = Promise.resolve();
  Eat() {
    
    
    this.Task = this.Task.then(_ => {
    
     console.log(eat) })
    Return this;
  }

  Sleep(t) {
    
    
    this.task = this.Task.then(_ => new Promise(r => {
    
    
      Console.log()
      setTimeout(r, t)
    }))
    Return this
  }
}

Minimale Implementierung des Generators

function generator(cb) {
    
    
  return (function () {
    
    
    var object = {
    
    
      next: 0,
      stop: function () {
    
     }
    };

    return {
    
    
      next: function () {
    
    
        var ret = cb(object);
        if (ret === undefined) return {
    
     value: undefined, done: true };
        return {
    
    
          value: ret,
          done: false
        };
      }
    };
  })();
}

Die minimalen Implementierungskernfunktionen von Promise:

  • new Promise(fn) wobei fn nur eine Funktion sein kann und sofort ausgeführt werden muss
  • success in Promise.then(success, fail) ist eine Funktion und wird ausgeführt, wenn „resolve“ aufgerufen wird. Das Gleiche gilt für fail

Umsetzungsideen:

  1. then(succeed, fail) fügt zunächst die Erfolgs- und Fehler-Callbacks in ein Callback-Array ein. callbacks[]
  2. „resolve()“ und „reject()“ durchlaufen Rückrufe
  3. resolve() liest den Erfolgsrückruf/reject() liest den Fehlerrückruf und führt die Erfolgs- und Fehlerrückrufe asynchron in Rückrufen aus
    (in die Mikrotask-Warteschlange dieser Runde einfügen). ) )
class Promise2 {
    
    
  state = "pending";
  callbacks = [];
  constructor(fn) {
    
    
    if (typeof fn !== "function") {
    
    
      throw new Error("must pass function");
    }
    fn(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(result) {
    
    
    if (this.state !== "pending") return;
    this.state = "fulfilled";
    nextTick(() => {
    
    
      this.callbacks.forEach((handle) => {
    
    
        if (typeof handle[0] === "function") {
    
    
          handle[0].call(undefined, result);
        }
      });
    });
  }
  reject(reason) {
    
    
    if (this.state !== "pending") return;
    this.state = "rejected";
    nextTick(() => {
    
    
      this.callbacks.forEach((handle) => {
    
    
        if (typeof handle[1] === "function") {
    
    
          handle[1].call(undefined, reason);
        }
      });
    });
  }
  then(succeed, fail) {
    
    
    const handle = [];
    if (typeof succeed === "function") {
    
    
      handle[0] = succeed;
    }
    if (typeof fail === "function") {
    
    
      handle[1] = fail;
    }
    this.callbacks.push(handle);
  }
}

function nextTick(fn) {
    
    
  if (process !== undefined && typeof process.nextTick === "function") {
    
    
    return process.nextTick(fn);
  } else {
    
    
    // 用MutationObserver实现浏览器上的nextTick
    var counter = 1;
    var observer = new MutationObserver(fn);
    var textNode = document.createTextNode(String(counter));

    observer.observe(textNode, {
    
    
      characterData: true,
    });
    counter += 1;
    textNode.data = String(counter);
  }
}

Dies ist ein Beobachtermuster. Diese Methode zum Sammeln von Abhängigkeiten -> Auslösen von Benachrichtigungen -> Entfernen von Abhängigkeiten zur Ausführung wird häufig bei der Implementierung des Beobachtermusters verwendet. In Promise besteht die Ausführungssequenz dann darin, Abhängigkeiten zu sammeln -> die Auflösung asynchron auszulösen. -> Ausführungsabhängigkeiten auflösen.

Versprechen Sie die A+-Spezifikation

Promise ist im Wesentlichen eine Zustandsmaschine und die Zustände können nur die folgenden drei sein: Ausstehend (Wartezustand), Erfüllt (Ausführungszustand) und Abgelehnt (abgelehnter Zustand). Die Zustandsänderung erfolgt in eine Richtung und kann nur von Ausstehend -> Erfüllt oder Ausstehend -> Abgelehnt geändert werden, Statusänderung ist irreversibel
Die then-Methode erhält zwei optionale Parameter, die den Rückrufen entsprechen, die bei Statusänderungen ausgelöst werden. Die then-Methode gibt ein Versprechen zurück. Die then-Methode kann für dasselbe Versprechen mehrmals aufgerufen werden.
Lassen Sie uns darüber nachdenken, wie Sie diesen Kettenaufruf implementieren:

  1. Offensichtlich muss .then() ein Promise zurückgeben, damit die then-Methode gefunden werden kann, daher werden wir den Rückgabewert der then-Methode in ein Promise einschließen.
  2. Der Rückruf von .then() muss den Rückgabewert des vorherigen .then() erhalten
  3. Die Rückrufe von .then() müssen nacheinander ausgeführt werden. Nehmen wir den obigen Code als Beispiel: Obwohl in der Mitte ein Promise zurückgegeben wird, muss die Ausführungsreihenfolge immer noch 1->2->3 sein. Wir müssen warten, bis sich der aktuelle Promise-Status ändert, bevor wir den nächsten bis dahin gesammelten Rückruf ausführen. Dies erfordert, dass wir den Rückgabewert von dann klassifizieren.
  4. Wertdurchdringung: Wenn then()
    laut Spezifikation ein Argument empfängt, das keine Funktion ist, sollten wir es ignorieren. Wenn dies nicht ignoriert wird, wird eine Ausnahme ausgelöst, wenn der then()-Rückruf keine Funktion ist, wodurch der Kettenaufruf unterbrochen wird
  5. behandelt die Situation, in der der Status aufgelöst/abgelehnt ist: Tatsächlich entspricht die Art und Weise, wie wir then()
    oben schreiben, der Situation, in der der Status aufgefüllt, manchmal aber auch aufgelöst ist /reject ist in then()
    wurde schon einmal ausgeführt (z. B. Promise.resolve().then()). Wenn der then()-Rückruf in die Ausführungswarteschlange von „resolve/reject“ verschoben wird Zu diesem Zeitpunkt wird der Rückruf nicht ausgeführt, also für Situationen, in denen sich der Status in „Erfüllt“ oder „Abgelehnt“ geändert hat.
// Promise/A+规范的三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    
    
  // 构造方法接收一个回调
  constructor(executor) {
    
    
    this._status = PENDING // Promise状态
    this._value = undefined // 储存then回调return的值
    this._resolveQueue = [] // 成功队列, resolve时触发
    this._rejectQueue = [] // 失败队列, reject时触发

    // 由于resolve/reject是在executor内部被调用, 因此需要使用箭头函数固定this指向, 否则找不到this._resolveQueue
    let _resolve = (val) => {
    
    
      // 把resolve执行回调的操作封装成一个函数,放进setTimeout里,以兼容executor是同步代码的情况
      const run = () => {
    
    
        if (this._status !== PENDING) return // 对应规范中的"状态只能由pending到fulfilled或rejected"
        this._status = FULFILLED // 变更状态
        this._value = val // 储存当前value

        // 这里之所以使用一个队列来储存回调,是为了实现规范要求的 "then 方法可以被同一个 promise 调用多次"
        // 如果使用一个变量而非队列来储存回调,那么即使多次p1.then()也只会执行一次回调
        while (this._resolveQueue.length) {
    
    
          const callback = this._resolveQueue.shift()
          callback(val)
        }
      }
      setTimeout(run)
    }
    // 实现同resolve
    let _reject = (val) => {
    
    
      const run = () => {
    
    
        if (this._status !== PENDING) return // 对应规范中的"状态只能由pending到fulfilled或rejected"
        this._status = REJECTED // 变更状态
        this._value = val // 储存当前value
        while (this._rejectQueue.length) {
    
    
          const callback = this._rejectQueue.shift()
          callback(val)
        }
      }
      setTimeout(run)
    }
    // new Promise()时立即执行executor,并传入resolve和reject
    executor(_resolve, _reject)
  }

  // then方法,接收一个成功的回调和一个失败的回调
  then(resolveFn, rejectFn) {
    
    
    // 根据规范,如果then的参数不是function,则我们需要忽略它, 让链式调用继续往下执行
    typeof resolveFn !== 'function' ? resolveFn = value => value : null
    typeof rejectFn !== 'function' ? rejectFn = reason => {
    
    
      throw new Error(reason instanceof Error ? reason.message : reason);
    } : null
    // return一个新的promise
    return new MyPromise((resolve, reject) => {
    
    
      // 把resolveFn重新包装一下,再push进resolve执行队列,这是为了能够获取回调的返回值进行分类讨论
      const fulfilledFn = value => {
    
    
        try {
    
    
          // 执行第一个(当前的)Promise的成功回调,并获取返回值
          let x = resolveFn(value)
          // 分类讨论返回值,如果是Promise,那么等待Promise状态变更,否则直接resolve
          // 这里resolve之后,就能被下一个.then()的回调获取到返回值,从而实现链式调用
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (error) {
    
    
          reject(error)
        }
      }
      // reject同理
      const rejectedFn = error => {
    
    
        try {
    
    
          let x = rejectFn(error)
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (error) {
    
    
          reject(error)
        }
      }
      switch (this._status) {
    
    
        // 当状态为pending时,把then回调push进resolve/reject执行队列,等待执行
        case PENDING:
          this._resolveQueue.push(fulfilledFn)
          this._rejectQueue.push(rejectedFn)
          break;
        // 当状态已经变为resolve/reject时,直接执行then回调
        case FULFILLED:
          fulfilledFn(this._value) // this._value是上一个then回调return的值(见完整版代码)
          break;
        case REJECTED:
          rejectedFn(this._value)
          break;
      }
    });
  }; 
}

Promise.Finally()

//finally()方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。在finally之后,还可以继续then。并且会将值原封不动的传递给后面的then
//finally方法
finally(callback) {
    
    
	return this.then(
		value => MyPromise.resolve(callback()).then(() => value), // MyPromise.resolve执行回调,并在then中return结果传递给后面的Promise
		reason => MyPromise.resolve(callback()).then(() => {
    
     throw reason }
	) // reject同理
)}
// MyPromise.resolve(callback())的意义,这里补充解释一下:这个写法其实涉及到一个finally()的使用细节,finally()如果return了一个reject状态的Promise,将会改变当前Promise的状态,这个MyPromise.resolve就用于改变Promise状态,在finally()没有返回reject态Promise或throw错误的情况下,去掉MyPromise.resolve也是一样的

Promise.all()

// Promise.all(iterable)方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve)
// 如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。

//静态的all方法
static all(promiseArr) {
    
    
  let index = 0
  let result = []
  return new MyPromise((resolve, reject) => {
    
    
    promiseArr.forEach((p, i) => {
    
    
      //Promise.resolve(p)用于处理传入值不为Promise的情况
      MyPromise.resolve(p).then(
        val => {
    
    
          index++
          result[i] = val
          //所有then执行后, resolve结果
          if (index === promiseArr.length) {
    
    
            resolve(result)
          }
        },
        err => {
    
    
          //有一个Promise被reject时,MyPromise的状态变为reject
          reject(err)
        }
      )
    })
  })
}

Promise.race()

// Promise.race(iterable)方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

static race(promiseArr) {
    
    
  return new MyPromise((resolve, reject) => {
    
    
    //同时执行Promise,如果有一个Promise的状态发生改变,就变更新MyPromise的状态
    for (let p of promiseArr) {
    
    
      MyPromise.resolve(p).then( //Promise.resolve(p)用于处理传入值不为Promise的情况
        value => {
    
    
          resolve(value) //注意这个resolve是上边new MyPromise的
        },
        err => {
    
    
          reject(err)
        }
      )
    }
  })
}

Versprechen und Asynchronität warten auf die Implementierung

function asyncToGenerator(generatorFn) {
    
    
  return function () {
    
    
    var gen = generatorFn.apply(this, arguments);
    return new Promise(function (resolve, reject) {
    
    
      function step(key, arg) {
    
    
        try {
    
    
          var info = gen[key](arg);
          var value = info.value;
        } catch (error) {
    
    
          reject(error);
          return;
        }

        if (info.done) {
    
    
          resolve(value);
        } else {
    
    
          return Promise.resolve(value).then(function (value) {
    
    
            step('next', value);
          }, function (err) {
    
    
            step('throw', err);
          });
        }
      }
      return step('next');
    });
  }
}

Implementierung der handschriftlichen Bindung

// 高级:支持 new,例如 new (funcA.bind(thisArg, args))
function bind_3(asThis) {
    
    
  var slice = Array.prototype.slice;
  var args1 = slice.call(arguments, 1);
  var fn = this;
  if (typeof fn !== "function") {
    
    
    throw new Error("Must accept function");
  }
  function resultFn() {
    
    
    var args2 = slice.call(arguments, 0);
    return fn.apply(
      resultFn.prototype.isPrototypeOf(this) ? this : asThis, // 用来绑定 this
      args1.concat(args2)
    );
  }
  resultFn.prototype = fn.prototype;
  return resultFn;
}

Handschriftliche tiefe Kopie

class DeepClone {
    
    
  constructor() {
    
    
    this.cacheList = [];
  }
  clone(source) {
    
    
    if (source instanceof Object) {
    
    
      const cache = this.findCache(source);
      if (cache) return cache; // 如果找到缓存,直接返回
      else {
    
    
        let target;
        if (source instanceof Array) {
    
    
          target = new Array();
        } else if (source instanceof Function) {
    
    
          target = function () {
    
    
            return source.apply(this, arguments);
          };
        } else if (source instanceof Date) {
    
    
          target = new Date(source);
        } else if (source instanceof RegExp) {
    
    
          target = new RegExp(source.source, source.flags);
        }
        this.cacheList.push([source, target]); // 把源对象和新对象放进缓存列表
        for (let key in source) {
    
    
          if (source.hasOwnProperty(key)) {
    
     // 不拷贝原型上的属性,太浪费内存
            target[key] = this.clone(source[key]); // 递归克隆
          }
        }
        return target;
      }
    }
    return source;
  }
  findCache(source) {
    
    
    for (let i = 0; i < this.cacheList.length; ++i) {
    
    
      if (this.cacheList[i][0] === source) {
    
    
        return this.cacheList[i][1]; // 如果有环,返回对应的新对象
      }
    }
    return undefined;
  }
}

Handschriftlich neu

function _new(obj, ...rest) {
    
    
  // 基于Obj的原型创建一个新的对象
  const newObj = Object.create(obj.prototype)
  // 添加属性到新创建的newObj上, 并获取obj函数执行的结果.
  const result = obj.apply(newObj, rest);
  // 如果执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象
  return typeof result === 'object' ? result : newObj;
}

Handschriftlicher EventHub (veröffentlichen-abonnieren)

Der Kerngedanke ist:

  1. Verwenden Sie ein Objekt als Cache
  2. on ist für die Veröffentlichung der Methode im Array verantwortlich, das dem zwischengespeicherten EventName entspricht
  3. emit ist für das Durchlaufen des Methodenarrays unter dem Trigger (Abonnement) EventName verantwortlich
  4. off Suchen Sie den Index der Methode und löschen Sie ihn
class EventHub {
    
    
  cache = {
    
    };
  on(eventName, fn) {
    
    
    this.cache[eventName] = this.cache[eventName] || [];
    this.cache[eventName].push(fn);
  }
  emit(eventName) {
    
    
    this.cache[eventName].forEach((fn) => fn());
  }
  off(eventName, fn) {
    
    
    const index = indexOf(this.cache[eventName], fn); // 这里用this.cache[eventName].indexOf(fn) 完全可以,封装成函数是为了向下兼容
    if (index === -1) return;
    this.cache[eventName].splice(index, 1);
  }
}
// 兼容 IE 8 的 indexOf
function indexOf(arr, item) {
    
    
  if (arr === undefined) return -1;
  let index = -1;
  for (let i = 0; i < arr.length; ++i) {
    
    
    if (arr[i] === item) {
    
    
      index = i;
      break;
    }
  }
  return index;
}

Handschriftliches Versprechen.irgendein

Promise.any = promises => {
    
    
  return new Promise((resolve, reject) => {
    
    
    let hasOneResolve = false;
    let remaining = promise.length;
    const errors = [];
    for (let index in Promises) {
    
    
      Promises[index].then(data => {
    
    
        if (hasOneResolved) return
        hasOneResolved = true
        resolve(data)
      }, err => {
    
    
        if (hasOneResolved) return;
        remaining--;
        errors[index] = err;
        remaining || reject(errors)
      })
    }
  })
}

Wie man ein Versprechen bricht

promise.then(fn).then()
// 补充fn
//fn
return new Promise((_, _) => {
    
     })

BFS und DFS

function deepTraversal(node) {
    
    
  let nodes = [];
  if (node != null) {
    
    
    nodes.push[node];
    let childrens = node.children
    for (let i = 0; i < childrens.length; i++) {
    
    
      deepTraversal(childrens[i]);
    }
  }
  return nodes;
}
function deepTraversal(node) {
    
    
  let nodes = []
  if (node != null) {
    
    
    //存放将来要访问的节点
    const stack = [];
    stack.push(node);
    while (stack.length != 0) {
    
    
      let item = stack.pop()
      nodes.push(item);
      let childrens = item.children;
      for (let i = children.length - 1; i >= 0; i--) {
    
    
        stack.push(childrens[i])
      }
    }
  }
  return nodes;
}

function wideTraversal(node) {
    
    
  let nodes = [];
  let i = 0;
  if (node != null) {
    
    
    nodes.push(node.nextElementSibling)
    node = nodes[i++]
    wideTraversal(node.firstElementChild)
  }
  return nodes;
}

function wideTraversal(node) {
    
    
  let nodes = [];
  let i = 0;
  while (node != null) {
    
    
    nodes.push(node)
    node = nodes[i++]
    let childrens = node.children;
    for (let i = 0; i < childrens.length; i++) {
    
    
      nodes.push(childrens[i])
    }
  }
  return nodes;
}

Je suppose que tu aimes

Origine blog.csdn.net/zw7518/article/details/120013536
conseillé
Classement