亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JS的基礎面試題及解決方法案例

發布時間:2020-10-09 16:41:23 來源:億速云 閱讀:227 作者:小新 欄目:web開發

這篇文章主要介紹JS的基礎面試題及解決方法案例,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

作為前端開發,JS是重中之重,最近結束了面試的高峰期,基本上offer也定下來了就等開獎,趁著這個時間總結下32個手寫JS問題,這些都是高頻面試題,希望對你能有所幫助。

關于源碼都緊遵規范,都可跑通MDN示例,其余的大多會涉及一些關于JS的應用題和本人面試過程

01.數組扁平化

數組扁平化是指將一個多維數組變為一個一維數組

const arr = [1, [2, [3, [4, 5]]], 6];// => [1, 2, 3, 4, 5, 6]

方法一:使用flat()

const res1 = arr.flat(Infinity);

方法二:利用正則

const res2 = JSON.stringify(arr).replace(/\[|\]/g, '').split(',');

但數據類型都會變為字符串

方法三:正則改良版本

const res3 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']');

方法四:使用reduce

const flatten = arr => {  return arr.reduce((pre, cur) => {    return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
  }, [])
}const res4 = flatten(arr);

方法五:函數遞歸

const res5 = [];const fn = arr => {  for (let i = 0; i < arr.length; i++) {    if (Array.isArray(arr[i])) {
      fn(arr[i]);
    } else {
      res5.push(arr[i]);
    }
  }
}
fn(arr);

02.數組去重

const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];// => [1, '1', 17, true, false, 'true', 'a', {}, {}]

方法一:利用Set

const res1 = Array.from(new Set(arr));

方法二:兩層for循環+splice

const unique1 = arr => {  let len = arr.length;  for (let i = 0; i < len; i++) {    for (let j = i + 1; j < len; j++) {      if (arr[i] === arr[j]) {
        arr.splice(j, 1);        // 每刪除一個樹,j--保證j的值經過自加后不變。同時,len--,減少循環次數提升性能
        len--;
        j--;
      }
    }
  }  return arr;
}

方法三:利用indexOf

const unique2 = arr => {  const res = [];  for (let i = 0; i < arr.length; i++) {    if (res.indexOf(arr[i]) === -1) res.push(arr[i]);
  }  return res;
}

當然也可以用include、filter,思路大同小異。

方法四:利用include

const unique3 = arr => {  const res = [];  for (let i = 0; i < arr.length; i++) {    if (!res.includes(arr[i])) res.push(arr[i]);
  }  return res;
}

方法五:利用filter

const unique4 = arr => {  return arr.filter((item, index) => {    return arr.indexOf(item) === index;
  });
}

方法六:利用Map

const unique5 = arr => {  const map = new Map();  const res = [];  for (let i = 0; i < arr.length; i++) {    if (!map.has(arr[i])) {
      map.set(arr[i], true)
      res.push(arr[i]);
    }
  }  return res;
}

03.類數組轉化為數組

類數組是具有length屬性,但不具有數組原型上的方法。常見的類數組有arguments、DOM操作方法返回的結果。

方法一:Array.from

Array.from(document.querySelectorAll('p'))

方法二:Array.prototype.slice.call()

Array.prototype.slice.call(document.querySelectorAll('p'))

方法三:擴展運算符

[...document.querySelectorAll('p')]

方法四:利用concat

Array.prototype.concat.apply([], document.querySelectorAll('p'));

04.Array.prototype.filter()

Array.prototype.filter = function(callback, thisArg) {  if (this == undefined) {    throw new TypeError('this is null or not undefined');
  }  if (typeof callback !== 'function') {    throw new TypeError(callback + 'is not a function');
  }  const res = [];  // 讓O成為回調函數的對象傳遞(強制轉換對象)
  const O = Object(this);  // >>>0 保證len為number,且為正整數
  const len = O.length >>> 0;  for (let i = 0; i < len; i++) {    // 檢查i是否在O的屬性(會檢查原型鏈)
    if (i in O) {      // 回調函數調用傳參
      if (callback.call(thisArg, O[i], i, O)) {
        res.push(O[i]);
      }
    }
  }  return res;
}復制代碼

對于>>>0有疑問的:解釋>>>0的作用

05.Array.prototype.map()

Array.prototype.map = function(callback, thisArg) {  if (this == undefined) {    throw new TypeError('this is null or not defined');
  }  if (typeof callback !== 'function') {    throw new TypeError(callback + ' is not a function');
  }  const res = [];  // 同理
  const O = Object(this);  const len = O.length >>> 0;  for (let i = 0; i < len; i++) {    if (i in O) {      // 調用回調函數并傳入新數組
      res[i] = callback.call(thisArg, O[i], i, this);
    }
  }  return res;
}

06.Array.prototype.forEach()

forEach跟map類似,唯一不同的是forEach是沒有返回值的。

Array.prototype.forEach = function(callback, thisArg) {  if (this == null) {    throw new TypeError('this is null or not defined');
  }  if (typeof callback !== "function") {    throw new TypeError(callback + ' is not a function');
  }  const O = Object(this);  const len = O.length >>> 0;  let k = 0;  while (k < len) {    if (k in O) {
      callback.call(thisArg, O[k], k, O);
    }
    k++;
  }
}

07.Array.prototype.reduce()

Array.prototype.reduce = function(callback, initialValue) {  if (this == undefined) {    throw new TypeError('this is null or not defined');
  }  if (typeof callback !== 'function') {    throw new TypeError(callbackfn + ' is not a function');
  }  const O = Object(this);  const len = this.length >>> 0;  let accumulator = initialValue;  let k = 0;  // 如果第二個參數為undefined的情況下
  // 則數組的第一個有效值作為累加器的初始值
  if (accumulator === undefined) {    while (k < len && !(k in O)) {
      k++;
    }    // 如果超出數組界限還沒有找到累加器的初始值,則TypeError
    if (k >= len) {      throw new TypeError('Reduce of empty array with no initial value');
    }
    accumulator = O[k++];
  }  while (k < len) {    if (k in O) {
      accumulator = callback.call(undefined, accumulator, O[k], k, O);
    }
    k++;
  }  return accumulator;
}

08.Function.prototype.apply()

第一個參數是綁定的this,默認為window,第二個參數是數組或類數組

Function.prototype.apply = function(context = window, args) {  if (typeof this !== 'function') {    throw new TypeError('Type Error');
  }  const fn = Symbol('fn');
  context[fn] = this;  const res = context[fn](...args);  delete context[fn];  return res;
}

09.Function.prototype.call

call唯一不同的是,call()方法接受的是一個參數列表

Function.prototype.call = function(context = window, ...args) {  if (typeof this !== 'function') {    throw new TypeError('Type Error');
  }  const fn = Symbol('fn');
  context[fn] = this;  const res = context[fn](...args);  delete context[fn];  return res;
}

10.Function.prototype.bind

Function.prototype.bind = function(context, ...args) {  if (typeof this !== 'function') {    throw new Error("Type Error");
  }  // 保存this的值
  var self = this;  return function F() {    // 考慮new的情況
    if(this instanceof F) {      return new self(...args, ...arguments)
    }    return self.apply(context, [...args, ...arguments])
  }
}

11.debounce(防抖)

觸發高頻時間后n秒內函數只會執行一次,如果n秒內高頻時間再次觸發,則重新計算時間。

const debounce = (fn, time) => {  let timeout = null;  return function() {
    clearTimeout(timeout)
    timeout = setTimeout(() => {
      fn.apply(this, arguments);
    }, time);
  }
};

防抖常應用于用戶進行搜索輸入節約請求資源,window觸發resize事件時進行防抖只觸發一次。

12.throttle(節流)

高頻時間觸發,但n秒內只會執行一次,所以節流會稀釋函數的執行頻率。

const throttle = (fn, time) => {  let flag = true;  return function() {    if (!flag) return;
    flag = false;
    setTimeout(() => {
      fn.apply(this, arguments);
      flag = true;
    }, time);
  }
}

節流常應用于鼠標不斷點擊觸發、監聽滾動事件。

13.函數珂里化

指的是將一個接受多個參數的函數 變為 接受一個參數返回一個函數的固定形式,這樣便于再次調用,例如f(1)(2)

經典面試題:實現add(1)(2)(3)(4)=10;add(1)(1,2,3)(2)=9;

function add() {  const _args = [...arguments];  function fn() {
    _args.push(...arguments);    return fn;
  }
  fn.toString = function() {    return _args.reduce((sum, cur) => sum + cur);
  }  return fn;
}

14.模擬new操作

3個步驟:

  1. ctor.prototype為原型創建一個對象。
  2. 執行構造函數并將this綁定到新創建的對象上。
  3. 判斷構造函數執行返回的結果是否是引用數據類型,若是則返回構造函數執行的結果,否則返回創建的對象。
function newOperator(ctor, ...args) {  if (typeof ctor !== 'function') {    throw new TypeError('Type Error');
  }  const obj = Object.create(ctor.prototype);  const res = ctor.apply(obj, args);  const isObject = typeof res === 'object' && res !== null;  const isFunction = typeof res === 'function';  return isObject || isFunction ? res : obj;
}

15.instanceof

instanceof運算符用于檢測構造函數的prototype屬性是否出現在某個實例對象的原型鏈上。

const myInstanceof = (left, right) => {  // 基本數據類型都返回false
  if (typeof left !== 'object' || left === null) return false;  let proto = Object.getPrototypeOf(left);  while (true) {    if (proto === null) return false;    if (proto === right.prototype) return true;
    proto = Object.getPrototypeOf(proto);
  }
}

16.原型繼承

這里只寫寄生組合繼承了,中間還有幾個演變過來的繼承但都有一些缺陷

function Parent() {  this.name = 'parent';
}function Child() {
  Parent.call(this);  this.type = 'children';
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

17.Object.is

Object.is解決的主要是這兩個問題:

+0 === -0  // true
NaN === NaN // false復制代碼
const is= (x, y) => {  if (x === y) {    // +0和-0應該不相等
    return x !== 0 || y !== 0 || 1/x === 1/y;
  } else {    return x !== x && y !== y;
  }
}

18.Object.assign

Object.assign()方法用于將所有可枚舉屬性的值從一個或多個源對象復制到目標對象。它將返回目標對象(請注意這個操作是淺拷貝)

Object.defineProperty(Object, 'assign', {  value: function(target, ...args) {    if (target == null) {      return new TypeError('Cannot convert undefined or null to object');
    }    
    // 目標對象需要統一是引用數據類型,若不是會自動轉換
    const to = Object(target);    for (let i = 0; i < args.length; i++) {      // 每一個源對象
      const nextSource = args[i];      if (nextSource !== null) {        // 使用for...in和hasOwnProperty雙重判斷,確保只拿到本身的屬性、方法(不包含繼承的)
        for (const nextKey in nextSource) {          if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
    }    return to;
  },  // 不可枚舉
  enumerable: false,  writable: true,  configurable: true,
})

19.深拷貝

遞歸的完整版本(考慮到了Symbol屬性):

const cloneDeep1 = (target, hash = new WeakMap()) => {  // 對于傳入參數處理
  if (typeof target !== 'object' || target === null) {    return target;
  }  // 哈希表中存在直接返回
  if (hash.has(target)) return hash.get(target);  const cloneTarget = Array.isArray(target) ? [] : {};
  hash.set(target, cloneTarget);  // 針對Symbol屬性
  const symKeys = Object.getOwnPropertySymbols(target);  if (symKeys.length) {
    symKeys.forEach(symKey => {      if (typeof target[symKey] === 'object' && target[symKey] !== null) {
        cloneTarget[symKey] = cloneDeep1(target[symKey]);
      } else {
        cloneTarget[symKey] = target[symKey];
      }
    })
  }  for (const i in target) {    if (Object.prototype.hasOwnProperty.call(target, i)) {
      cloneTarget[i] =        typeof target[i] === 'object' && target[i] !== null
        ? cloneDeep1(target[i], hash)
        : target[i];
    }
  }  return cloneTarget;
}

20.Promise

實現思路:Promise源碼實現

const PENDING = 'PENDING';      // 進行中const FULFILLED = 'FULFILLED';  // 已成功const REJECTED = 'REJECTED';    // 已失敗class Promise {  constructor(exector) {    // 初始化狀態
    this.status = PENDING;    // 將成功、失敗結果放在this上,便于then、catch訪問
    this.value = undefined;    this.reason = undefined;    // 成功態回調函數隊列
    this.onFulfilledCallbacks = [];    // 失敗態回調函數隊列
    this.onRejectedCallbacks = [];    const resolve = value => {      // 只有進行中狀態才能更改狀態
      if (this.status === PENDING) {        this.status = FULFILLED;        this.value = value;        // 成功態函數依次執行
        this.onFulfilledCallbacks.forEach(fn => fn(this.value));
      }
    }    const reject = reason => {      // 只有進行中狀態才能更改狀態
      if (this.status === PENDING) {        this.status = REJECTED;        this.reason = reason;        // 失敗態函數依次執行
        this.onRejectedCallbacks.forEach(fn => fn(this.reason))
      }
    }    try {      // 立即執行executor
      // 把內部的resolve和reject傳入executor,用戶可調用resolve和reject
      exector(resolve, reject);
    } catch(e) {      // executor執行出錯,將錯誤內容reject拋出去
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function'? onRejected:      reason => { throw new Error(reason instanceof Error ? reason.message:reason) }    // 保存this
    const self = this;    return new Promise((resolve, reject) => {      if (self.status === PENDING) {
        self.onFulfilledCallbacks.push(() => {          // try捕獲錯誤
          try {            // 模擬微任務
            setTimeout(() => {              const result = onFulfilled(self.value);              // 分兩種情況:
              // 1. 回調函數返回值是Promise,執行then操作
              // 2. 如果不是Promise,調用新Promise的resolve函數
              result instanceof Promise ? result.then(resolve, reject) : resolve(result);
            })
          } catch(e) {
            reject(e);
          }
        });
        self.onRejectedCallbacks.push(() => {          // 以下同理
          try {
            setTimeout(() => {              const result = onRejected(self.reason);              // 不同點:此時是reject
              result instanceof Promise ? result.then(resolve, reject) : reject(result);
            })
          } catch(e) {
            reject(e);
          }
        })
      } else if (self.status === FULFILLED) {        try {
          setTimeout(() => {            const result = onFulfilled(self.value);
            result instanceof Promise ? result.then(resolve, reject) : resolve(result);
          });
        } catch(e) {
          reject(e);
        }
      } else if (self.status === REJECTED){        try {
          setTimeout(() => {            const result = onRejected(self.reason);
            result instanceof Promise ? result.then(resolve, reject) : reject(result);
          })
        } catch(e) {
          reject(e);
        }
      }
    });
  }  catch(onRejected) {    return this.then(null, onRejected);
  }  static resolve(value) {    if (value instanceof Promise) {      // 如果是Promise實例,直接返回
      return value;
    } else {      // 如果不是Promise實例,返回一個新的Promise對象,狀態為FULFILLED
      return new Promise((resolve, reject) => resolve(value));
    }
  }  static reject(reason) {    return new Promise((resolve, reject) => {
      reject(reason);
    })
  }
}

21.Promise.all

Promise.all是支持鏈式調用的,本質上就是返回了一個Promise實例,通過resolvereject來改變實例狀態。

Promise.myAll = function(promiseArr) {  return new Promise((resolve, reject) => {    const ans = [];    let index = 0;    for (let i = 0; i < promiseArr.length; i++) {
      promiseArr[i]
      .then(res => {
        ans[i] = res;
        index++;        if (index === promiseArr.length) {
          resolve(ans);
        }
      })
      .catch(err => reject(err));
    }
  })
}

22.Promise.race

Promise.race = function(promiseArr) {  return new Promise((resolve, reject) => {
    promiseArr.forEach(p => {      // 如果不是Promise實例需要轉化為Promise實例
      Promise.resolve(p).then(        val => resolve(val),
        err => reject(err),
      )
    })
  })
}復制代碼

23.Promise并行限制

就是實現有并行限制的Promise調度器問題。

詳細實現思路:某條高頻面試原題:實現有并行限制的Promise調度器

class Scheduler {  constructor() {    this.queue = [];    this.maxCount = 2;    this.runCounts = 0;
  }
  add(promiseCreator) {    this.queue.push(promiseCreator);
  }
  taskStart() {    for (let i = 0; i < this.maxCount; i++) {      this.request();
    }
  }
  request() {    if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) {      return;
    }    this.runCounts++;    this.queue.shift()().then(() => {      this.runCounts--;      this.request();
    });
  }
}   
const timeout = time => new Promise(resolve => {
  setTimeout(resolve, time);
})  
const scheduler = new Scheduler();  
const addTask = (time,order) => {
  scheduler.add(() => timeout(time).then(()=>console.log(order)))
}
  
  
addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
scheduler.taskStart()// 2// 3// 1// 4

24.JSONP

script標簽不遵循同源協議,可以用來進行跨域請求,優點就是兼容性好但僅限于GET請求

const jsonp = ({ url, params, callbackName }) => {  const generateUrl = () => {    let dataSrc = '';    for (let key in params) {      if (Object.prototype.hasOwnProperty.call(params, key)) {
        dataSrc += `${key}=${params[key]}&`;
      }
    }
    dataSrc += `callback=${callbackName}`;    return `${url}?${dataSrc}`;
  }  return new Promise((resolve, reject) => {    const scriptEle = document.createElement('script');
    scriptEle.src = generateUrl();    document.body.appendChild(scriptEle);    window[callbackName] = data => {
      resolve(data);      document.removeChild(scriptEle);
    }
  })
}

25.AJAX

const getJSON = function(url) {  return new Promise((resolve, reject) => {    const xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Mscrosoft.XMLHttp');
    xhr.open('GET', url, false);
    xhr.setRequestHeader('Accept', 'application/json');
    xhr.onreadystatechange = function() {      if (xhr.readyState !== 4) return;      if (xhr.status === 200 || xhr.status === 304) {
        resolve(xhr.responseText);
      } else {
        reject(new Error(xhr.responseText));
      }
    }
    xhr.send();
  })
}

26.event模塊

實現node中回調函數的機制,node中回調函數其實是內部使用了觀察者模式

觀察者模式:定義了對象間一種一對多的依賴關系,當目標對象Subject發生改變時,所有依賴它的對象Observer都會得到通知。

function EventEmitter() {  this.events = new Map();
}// 需要實現的一些方法:// addListener、removeListener、once、removeAllListeners、emit// 模擬實現addlistener方法const wrapCallback = (fn, once = false) => ({ callback: fn, once });
EventEmitter.prototype.addListener = function(type, fn, once = false) {  const hanlder = this.events.get(type);  if (!hanlder) {    // 沒有type綁定事件
    this.events.set(type, wrapCallback(fn, once));
  } else if (hanlder && typeof hanlder.callback === 'function') {    // 目前type事件只有一個回調
    this.events.set(type, [hanlder, wrapCallback(fn, once)]);
  } else {    // 目前type事件數>=2
    hanlder.push(wrapCallback(fn, once));
  }
}// 模擬實現removeListenerEventEmitter.prototype.removeListener = function(type, listener) {  const hanlder = this.events.get(type);  if (!hanlder) return;  if (!Array.isArray(this.events)) {    if (hanlder.callback === listener.callback) this.events.delete(type);    else return;
  }  for (let i = 0; i < hanlder.length; i++) {    const item = hanlder[i];    if (item.callback === listener.callback) {
      hanlder.splice(i, 1);
      i--;      if (hanlder.length === 1) {        this.events.set(type, hanlder[0]);
      }
    }
  }
}// 模擬實現once方法EventEmitter.prototype.once = function(type, listener) {  this.addListener(type, listener, true);
}// 模擬實現emit方法EventEmitter.prototype.emit = function(type, ...args) {  const hanlder = this.events.get(type);  if (!hanlder) return;  if (Array.isArray(hanlder)) {
    hanlder.forEach(item => {
      item.callback.apply(this, args);      if (item.once) {        this.removeListener(type, item);
      }
    })
  } else {
    hanlder.callback.apply(this, args);    if (hanlder.once) {      this.events.delete(type);
    }
  }  return true;
}
EventEmitter.prototype.removeAllListeners = function(type) {  const hanlder = this.events.get(type);  if (!hanlder) return;  this.events.delete(type);
}

27.圖片懶加載

可以給img標簽統一自定義屬性src='default.png',當檢測到圖片出現在窗口之后再補充src屬性,此時才會進行圖片資源加載。

function lazyload() {  const imgs = document.getElementsByTagName('img');  const len = imgs.length;  // 視口的高度
  const viewHeight = document.documentElement.clientHeight;  // 滾動條高度
  const scrollHeight = document.documentElement.scrollTop || document.body.scrollTop;  for (let i = 0; i < len; i++) {    const offsetHeight = imgs[i].offsetTop;    if (offsetHeight < viewHeight + scrollHeight) {      const src = imgs[i].dataset.src;
      imgs[i].src = src;
    }
  }
}// 可以使用節流優化一下window.addEventListener('scroll', lazyload);

28.滾動加載

原理就是監聽頁面滾動事件,分析clientHeightscrollTopscrollHeight三者的屬性關系。

window.addEventListener('scroll', function() {  const clientHeight = document.documentElement.clientHeight;  const scrollTop = document.documentElement.scrollTop;  const scrollHeight = document.documentElement.scrollHeight;  if (clientHeight + scrollTop >= scrollHeight) {    // 檢測到滾動至頁面底部,進行后續操作
    // ...
  }
}, false);

一個Demo:頁面滾動加載的Demo

29.渲染幾萬條數據不卡住頁面

渲染大數據時,合理使用createDocumentFragmentrequestAnimationFrame,將操作切分為一小段一小段執行。

setTimeout(() => {  // 插入十萬條數據
  const total = 100000;  // 一次插入的數據
  const once = 20;  // 插入數據需要的次數
  const loopCount = Math.ceil(total / once);  let countOfRender = 0;  const ul = document.querySelector('ul');  // 添加數據的方法
  function add() {    const fragment = document.createDocumentFragment();    for(let i = 0; i < once; i++) {      const li = document.createElement('li');
      li.innerText = Math.floor(Math.random() * total);
      fragment.appendChild(li);
    }
    ul.appendChild(fragment);
    countOfRender += 1;
    loop();
  }  function loop() {    if(countOfRender < loopCount) {      window.requestAnimationFrame(add);
    }
  }
  loop();
}, 0)

30.打印出當前網頁使用了多少種HTML元素

一行代碼可以解決:

const fn = () => {  return [...new Set([...document.querySelectorAll('*')].map(el => el.tagName))].length;
}

值得注意的是:DOM操作返回的是類數組,需要轉換為數組之后才可以調用數組的方法。

31.將VirtualDom轉化為真實DOM結構

這是當前SPA應用的核心概念之一

// vnode結構:// {//   tag,//   attrs,//   children,// }//Virtual DOM => DOMfunction render(vnode, container) {
  container.appendChild(_render(vnode));
}function _render(vnode) {  // 如果是數字類型轉化為字符串
  if (typeof vnode === 'number') {
    vnode = String(vnode);
  }  // 字符串類型直接就是文本節點
  if (typeof vnode === 'string') {    return document.createTextNode(vnode);
  }  // 普通DOM
  const dom = document.createElement(vnode.tag);  if (vnode.attrs) {    // 遍歷屬性
    Object.keys(vnode.attrs).forEach(key => {      const value = vnode.attrs[key];
      dom.setAttribute(key, value);
    })
  }  // 子數組進行遞歸操作
  vnode.children.forEach(child => render(child, dom));  return dom;
}

32.字符串解析問題

var a = {    b: 123,    c: '456',    e: '789',
}var str=`a{a.b}aa{a.c}aa {a.d}aaaa`;// => 'a123aa456aa {a.d}aaaa'復制代碼

實現函數使得將str字符串中的{}內的變量替換,如果屬性不存在保持原樣(比如{a.d}

類似于模版字符串,但有一點出入,實際上原理大差不差

const fn1 = (str, obj) => {    let res = '';    // 標志位,標志前面是否有{
    let flag = false;    let start;    for (let i = 0; i < str.length; i++) {        if (str[i] === '{') {
            flag = true;
            start = i + 1;            continue;
        }        if (!flag) res += str[i];        else {            if (str[i] === '}') {
                flag = false;
                res += match(str.slice(start, i), obj);
            }
        }
    }    return res;
}// 對象匹配操作const match = (str, obj) => {    const keys = str.split('.').slice(1);    let index = 0;    let o = obj;    while (index < keys.length) {        const key = keys[index];        if (!o[key]) {            return `{${str}}`;
        } else {
            o = o[key];
        }
        index++;
    }    return o;
}

以上是JS的基礎面試題及解決方法案例的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

唐河县| 和政县| 虞城县| 清新县| 磴口县| 家居| 阿鲁科尔沁旗| 衡山县| 阜城县| 稻城县| 芜湖县| 乳源| 周口市| 肥乡县| 普宁市| 泾源县| 嵊州市| 佛冈县| 嘉义县| 彩票| 景宁| 保定市| 特克斯县| 靖西县| 武功县| 承德市| 高碑店市| 通州市| 肇州县| 航空| 陇南市| 木里| 墨竹工卡县| 绥德县| 会昌县| 德安县| 沈阳市| 理塘县| 常山县| 六枝特区| 昭觉县|