主頁 > 前端設計 > 【面試】前端面試常考手寫題 - JavaScript - CSS

【面試】前端面試常考手寫題 - JavaScript - CSS

2021-08-14 08:04:05 前端設計

在這里插入圖片描述

持續更新中…

文章目錄

  • 1. CSS布局
    • 1.1 盒子居中對齊
    • 1.2 兩欄布局
    • 1.3 三欄布局
      • 雙飛翼
      • 圣杯
    • 1.4 品字布局
  • 2. JS手寫函式
    • 2.1 手寫原生
      • Promise
      • Promise.all
      • Promise.race
      • Promise.resolve()
      • Promise.reject()
      • call
      • apply
      • bind
      • new
      • instanceof
    • 2.2 自定義函式
      • 陣列去重
      • 陣列扁平化
      • 深拷貝
      • 深比較
      • 節流
      • 防抖
      • 寄生式組合繼承
      • ES6繼承
      • 柯里化
      • Ajax
      • 亂數
  • 3. 場景題

1. CSS布局

1.1 盒子居中對齊

1.2 兩欄布局

1.3 三欄布局

雙飛翼

圣杯

1.4 品字布局

2. JS手寫函式

2.1 手寫原生

Promise

/**
 * Promise建構式
 * @param {*} executor 執行器函式(同步執行)(resolve, reject) => {}
 */
function Promise(executor) {

  const self = this; // 保存當前實體物件的this的值
  // 添加屬性
  self.PromiseState = PENDING // 給promise物件指定status屬性,初始值為pending
  self.PromiseResult = null // 給promise物件指定一個用于存盤結果資料的屬性
  self.callbacks = [] // 存的是物件 每個元素的結構:{onResolved() {}, onRejected() {}}

  /**
   * executor內部定義成功時呼叫的函式
   * @param {*} value 成功的值
   * @returns 
   */
  function resolve(value) {
    // 如果當前狀態不是pending,直接結束
    if (self.PromiseState !== PENDING) return
    // 1. 修改物件的狀態(promiseState)為 fulfilled
    self.PromiseState = RESOLVED 
    // 2. 設定物件結果值(promiseResult)為 value
    self.PromiseResult = value
    // 如果有待執行的callback函式,立即【異步】執行回呼函式onResolved
    if (self.callbacks.length > 0) {
      setTimeout(() => { // 放入佇列中執行所有成功的回呼
        self.callbacks.forEach(callbacksObj => {
          callbacksObj.onResolved(value)
        })
      }, 0)
    }
  }
  
  /**
   * executor內部定義失敗時呼叫的函式
   * @param {*} reason 失敗的原因
   * @returns 
   */
  function reject(reason) {
    // 如果當前狀態不是pending,直接結束
    if (self.PromiseState !== PENDING) return
    // 1. 修改物件的狀態(promiseState)為 rejected
    self.PromiseState = REJECTED
    // 2. 設定物件結果值(promiseResult)為 reason
    self.PromiseResult = reason
    // 如果有待執行的callback函式,立即【異步】執行回呼函式onRejected
    if (self.callbacks.length > 0) {
      setTimeout(() => { // 放入佇列中執行所有失敗的回呼
        self.callbacks.forEach(callbacksObj => {
          callbacksObj.onRejected(reason)
        })
      }, 0)
    }
  }
  
  // 立即【同步】執行executor函式
  try {
    executor(resolve, reject)
  } catch(error) { // 如果執行器拋出例外,promise物件變成rejected狀態
    reject(error)
  }
}

Promise.all

接收的是一個promise陣列promises
當傳入的所有promise都成功,則回傳一個成功的promise,值為所有成功promise的值的陣列【注意順序】
當傳入的promises中有一個不成功,則回傳一個失敗的promise,其值為這個失敗的promise的值

思路
首先創建一個結果陣列,再創建要給計數變數

Promise.all = function(promises){
	return new Promise((resolve, reject)=>{
		let count = 0
		const values = []
		for(let i = 0; i < promises.length; i++){
			Promise.resolve(promise[i]).then(value => {
				count++
				values[i] = value
				if(count === promises.length){
					resolve(values)
				}
			}, reason => { 
				reject(reason) 
			})
		}
	})
}

Promise.race

接收的是一個promise陣列promises
回傳一個promise,狀態和值都取決于第一個改變狀態的promise

Promise.race = function(promises) {
	return new Promise((resolve, reject)=>{
		for(let i = 0; i < promises.length; i++) {
			Promise.resolve(promises[i]).then(value => {
				resolve(value)
			}, reason => {
				reject(reason)
			}
		}
	})
}

Promise.resolve()

Promise.resolve = function(value) {
	return new Promise((resolve, reject) => {
		if(value instanceof Promise) {
			value.then(resolve, reject)
		} else {
			resolve(value)
		}
	}
}

Promise.reject()

Promise.reject = function(reason) {
	return new Promise((resolve, reject)=> {
		reject(reason)
	})
}

call

function call(Fn, obj, ...args) {
  if (obj === undefined || obj === null) {
    // 表示全域物件(ES11新增特性)
    obj = globalThis;
  }
  // 為 obj 添加臨時的方法
  obj.temp = Fn;
  // 呼叫 temp 方法
  let result = obj.temp(...args);
  // 洗掉tempfangfa
  delete obj.temp;
  // 回傳執行結果
  return result;
}

apply

function apply(Fn, obj, arr) {
  if (obj === undefined || obj === null) {
    obj = globalThis;
  }
  // 為obj添加臨時方法
  obj.temp = Fn;
  // 執行方法
  let result = obj.temp(...arr);
  // 洗掉臨時屬性
  delete obj.temp;
  // 回傳結果
  return result;
}

bind

function bind(Fn, obj, ...args) {
  // 回傳一個新的函式
  return function (...args2) {
    // 執行 call 函式、
    return call(Fn, obj, ...args, ...args2);
  };
}

new

function newInstance(Fn, ...args) {
  // 1. 創建新物件
  // 創建空的object實體物件,作為Fn的實體物件
  const obj = {};
  // 修改新物件的原型物件
  // 將Fn的prototype(顯式原型)屬性賦值給obj的__proto__(隱式原型)屬性
  obj.__proto__ = Fn.prototype;
  // 2. 修改函式內部this指向新物件,并執行
  //
  const result = Fn.call(obj, ...args);
  // 3. 回傳新物件
  // return obj
  // 與new保持一直,如果建構式有回傳值,回傳值是物件a就回傳物件a,否則回傳實體物件
  return result instanceof Object ? result : obj;
}

instanceof

function myInstanceOf(obj, Fn) {
  // 得到obj的隱式原型物件
  let protoObj = obj.__proto__;
  // 原型物件存在,就遍歷原型鏈
  while (protoObj) {
    // 實體物件的隱式原型 等于 建構式的顯式原型 就回傳true
    if (protoObj === Fn.prototype) {
      return true;
    }
    // 不相等就根據原型鏈一直往上找 直到最后為null
    protoObj = protoObj.__proto__;
  }
  return false;
}

2.2 自定義函式

陣列去重

function unique1(arr) {
  const result = [];
  const obj = {};
  arr.forEach((item) => {
    if (!obj.hasOwnProperty(item)) {
      obj[item] = true;
      result.push(item);
    }
  });
  return result;
}
function unique(arr) {
  return [...new Set(arr)];
}
function objSort(obj){
    let newObj = {}
    //遍歷物件,并將key進行排序
    Object.keys(obj).sort().map(key => {
        newObj[key] = obj[key]
    })
    //將排序好的陣列轉成字串
    return JSON.stringify(newObj)
}

function unique(arr){
    let set = new Set();
    for(let i=0;i<arr.length;i++){
        let str = objSort(arr[i])
        set.add(str)
    }
    //將陣列中的字串轉回物件
    arr = [...set].map(item => {
        return JSON.parse(item)
    })
    return arr
}

陣列扁平化

function flatten(arr) {
  let result = [];
  arr.forEach((item) => {
    // 判斷是不是陣列
    if (Array.isArray(item)) {
      result = result.concat(flatten(item));
    } else {
      result = result.concat(item);
    }
  });
  return result;
}
function flatten1(arr) {
  let result = [...arr];
  // 判斷result里有沒有子陣列
  while (result.some((item) => Array.isArray(item))) {
    result = [].concat(...result);
  }
  return result;
}

深拷貝

function deepClone1(target) {
  // 通過資料創建JSON格式的字串
  let str = JSON.stringify(target);
  // 將 JSON 字串創建為JS資料
  let data = JSON.parse(str);
  return data;
}
function deepClone(target) {
  if (typeof target === "object" && target !== null) {
    // 創建一個容器
    const result = Array.isArray(target) ? [] : {};
    // 遍歷target
    for (let key in target) {
      // 檢測該屬性是否為物件本身的屬性(不能拷貝原型物件上的屬性)
      if (target.hasOwnProperty(key)) {
        result[key] = deepClone2(target[key]);
      }
    }
    return result;
  } else {
    return target;
  }
}
function deepClone3(target, map = new Map()) {
  if (typeof target === "object" && target !== null) {
    // 克隆資料之前進行判斷,查看資料之前是否被克隆過
    let cache = map.get(target);
    if (cache) {
      return cache;
    }
    // 創建一個容器
    const result = Array.isArray(target) ? [] : {};
    // 將新的結果保存到容器中
    map.set(target, result);
    // 遍歷target
    for (let key in target) {
      // 檢測該屬性是否為物件本身的屬性(不能拷貝原型物件上的屬性)
      if (target.hasOwnProperty(key)) {
        result[key] = deepClone3(target[key], map);
      }
    }
    return result;
  } else {
    return target;
  }
}

深比較

function isObject(obj) {
  return typeof obj === object && obj !== null;
}

// 深度比較
function isEqual(obj1, obj2) {
  if (!isObject(obj1) || !isObject(obj2)) {
    // 值型別,直接判斷【一般不會傳函式,不考慮函式】
    return obj1 === obj2;
  }
  if (obj1 === obj2) {
    return true;
  }
  // 兩個都是物件或陣列,而且不相等
  // 1. 先判斷鍵的個數是否相等,不相等一定回傳false
  const obj1Keys = Object.keys(obj1);
  const obj2Keys = Objext.keys(obj2);
  if (obj1Keys.length !== obj2Keys.length) {
    return false;
  }
  // 2. 以obj1為基準,和obj2依次遞回比較
  for (let key in obj1) {
    // 遞回比較
    const res = isEqual(obj1[key], obj2[key]);
    if (!res) {
      return false;
    }
  }
  // 3. 全相等
  return true;
}

節流

使用定時器版本

function throttle(callback, wait=100){
	let flag = true
	return function(){
		if(flag){
			flag = false
			setTimeout(()=>{
				flag = true
				callback(...arguments)
			}, wait)
		}
	}
}

不使用定時器版本

function throttle(callback, wait=100){
	let start = 0
	return function(){
		let now = Date.now()
		if(now - start >= wait) {
			callback(...arguments)
			start = now
		}
	}
}

防抖

連續觸發事件,只有最后一次成功

function debounce(callback, wait=100) {
  // 定時器變數
  let timeId = undefined;
  // 回傳一個函式
  return function () {
  	// 有定時器,就清空,取消定時器,阻止回呼執行
    if (timeId !== undefined) {
      // 清空定時器
      clearTimeout(timeId);
    }
    
    // 啟動定時器
    timeId = setTimeout(() => {
      // 執行回呼
      callback(...arguments);
      // 執行完了重置id
      timeId = undefined;
    }, wait);
  };
}

寄生式組合繼承

function Person(obj) {
    this.name = obj.name
    this.age = obj.age
}
Person.prototype.add = function(value){
    console.log(value)
}
var p1 = new Person({name:"番茄", age: 18})

function Person1(obj) {
    Person.call(this, obj)
    this.sex = obj.sex
}
// 這一步是繼承的關鍵
Person1.prototype = Object.create(Person.prototype);
Person1.prototype.constructor = Person1;

Person1.prototype.play = function(value){
    console.log(value)
}
var p2 = new Person1({name:"雞蛋", age: 118, sex: "男"})

ES6繼承

class People{
  constructor(name='wang',age='27'){
    this.name = name;
    this.age = age;
  }
  eat(){
    console.log(`${this.name} ${this.age} eat food`)
  }
}
//繼承父類
class Woman extends People{ 
   constructor(name = 'ren',age = '27'){ 
     //繼承父類屬性
     super(name, age); 
   } 
    eat(){ 
     //繼承父類方法
      super.eat() 
    } 
} 
let wonmanObj=new Woman('xiaoxiami'); 
wonmanObj.eat();

柯里化

function curry(fn,...args){
  let fnLen = fn.length,
      argsLen = args.length;
  //對比函式的引數和當前傳入引數
  //若引數不夠就繼續遞回回傳curry
  //若引數夠就呼叫函式回傳相應的值
  if(fnLen > argsLen){
    return function(...arg2s){
      return curry(fn,...args,...arg2s)
    }
  }else{
    return fn(...args)
  }
}

Ajax

function ajax(url) {
	const p = new Promise((resolve, reject) => {
		const xhr = new XMLHttpRequest()
		xhr.open('GET', url, true)
		xhr.onreadystatechange = function () {
			if(xhr.readyState === 4) {
				if(xhr.status === 200) {
					resolve(
						JSON.parse(xhr.responseText)
					)
				} else if (xhr.status === 404) {
					reject(new Error('404 not found'))
				}
			}
		}
		xhr.send(null)
	})
	return p
}

亂數

function getRandom(min, max) {
  return Math.floor(Math.random() * (max - min)) + min   
}

3. 場景題

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/293628.html

標籤:其他

上一篇:Vue前端框架筆記01:初識vue

下一篇:JavaScript入門第十九章(JS補充知識點)(完結)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more