
持續更新中…
文章目錄
- 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
標籤:其他
