文章目录
- [一、JavaScript 基础](#一、JavaScript 基础)
-
- [1. 手写 Object.create](#1. 手写 Object.create)
- [2. 手写 instanceof 方法](#2. 手写 instanceof 方法)
- [3. 手写 new 操作符](#3. 手写 new 操作符)
- [4. 手写 Promise](#4. 手写 Promise)
- [5. 手写 Promise.then](#5. 手写 Promise.then)
- [8. 手写防抖函数](#8. 手写防抖函数)
- [9. 手写节流函数](#9. 手写节流函数)
- [10. 手写类型判断函数](#10. 手写类型判断函数)
- [11. 手写 call 函数](#11. 手写 call 函数)
- [12. 手写 apply 函数](#12. 手写 apply 函数)
- [13. 手写 bind 函数](#13. 手写 bind 函数)
- [14. 函数柯里化的实现](#14. 函数柯里化的实现)
- [15. 实现AJAX请求](#15. 实现AJAX请求)
- [16. 使用Promise封装AJAX请求](#16. 使用Promise封装AJAX请求)
- [17. 实现浅拷贝](#17. 实现浅拷贝)
- [18. 实现深拷贝](#18. 实现深拷贝)
- 二、数据处理
-
- [1. 实现数组的扁平化](#1. 实现数组的扁平化)
-
- (1)递归实现
- [(2)reduce 函数迭代](#(2)reduce 函数迭代)
- [2. 实现数组去重](#2. 实现数组去重)
- [3. 实现数组的flat方法](#3. 实现数组的flat方法)
- [4. 实现数组的push方法](#4. 实现数组的push方法)
- [5. 实现数组的filter方法](#5. 实现数组的filter方法)
- [6. 实现数组的map方法](#6. 实现数组的map方法)
- [7. 实现字符串的repeat方法](#7. 实现字符串的repeat方法)
- [8. 实现非负大整数相加](#8. 实现非负大整数相加)
- [9. 实现类数组转化为数组](#9. 实现类数组转化为数组)
- 三、场景应用
-
- [1. 用Promise实现图片的异步加载](#1. 用Promise实现图片的异步加载)
- [2. 实现发布-订阅模式](#2. 实现发布-订阅模式)
- [3. 查找文章中出现频率最高的单词](#3. 查找文章中出现频率最高的单词)
- [4. 封装异步的fetch,使用async await方式来使用](#4. 封装异步的fetch,使用async await方式来使用)
- [5. 实现prototype继承](#5. 实现prototype继承)
- [6. 实现双向数据绑定](#6. 实现双向数据绑定)
- [7. 实现简单路由](#7. 实现简单路由)
- [8. 实现斐波那契数列](#8. 实现斐波那契数列)
- [9. 实现 jsonp](#9. 实现 jsonp)
一、JavaScript 基础
1. 手写 Object.create
Object.create() 用于创建一个新对象,使用现有的对象来提供新创建的对象的 proto。本质上,是对传入的对象执行了一次浅复制
javascript
// 原Objet.create
let person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
let anotherPerson = Object.create(person, {
name: { // 对数据属性name描述特性
value: "Greg"
}
});
console.log(anotherPerson.name); // "Greg"
// 手写
function create(obj) {
function Fun(){}
Fun.prototype = obj
return new Fun()
}
console.log(create(person).name) // Nicholas
2. 手写 instanceof 方法
测试一个对象是否是由某个特定的构造函数创建的实例。
步骤:
1、获取特定构造函数的 prototype 对象
2、通过Object.getPrototypeOf()获取测试对象的原型,一直往原型链上找直到顶层Object的对象原型Null
javascript
function myInstanceof(obj,fun) {
let prototype = fun.prototype // 获取特定构造函数的 prototype 对象
let proto = Object.getPrototypeOf(obj) // 获取测试对象的原型,[[Prototype]]通过Object.getPrototypeOf访问
while(true) {
if(proto === null) {return false}
if (prototype === proto ) {return true}
proto = Object.getPrototypeOf(proto)
}
}
3. 手写 new 操作符
在调用 new 的过程中会发生以上四件事情:
1、创建一个新的空对象。
2、将新对象的[[Prototype]](内部原型)设置为构造函数的prototype对象。
3、将构造函数的this指向新创建的对象。
4、如果构造函数返回一个对象,则new表达式的结果就是这个对象;否则,结果就是this所指向的对象
javascript
// 实现目标myNew
function Fun(name,age) {
this.name = name
this.age = age
}
let newData = myNew(Fun,'lida',16)
console.log(newData.name) // lida
// 实现myNew
function myNew(fun,...args) {
let newObj = Object.create(fun.prototype)
let result = fun.apply(newObj,args)
return result instanceof Object ? result : obj;
}
4. 手写 Promise
javascript
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function MyPromise(fn) {
// 保存初始化状态
let self = this;
// 初始化状态
this.state = PENDING;
// 用于保存 resolve 或者 rejected 传入的值
this.value = null;
// 用于保存 resolve 的回调函数
this.resolvedCallbacks = [];
// 用于保存 reject 的回调函数
this.rejectedCallbacks = [];
// 状态转变为 fulfilled 方法
function resolve(value) {
// 判断传入元素是否为 Promise 值,如果是,则状态改变必须等待前一个状态改变后再进行改变
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}
// 保证代码的执行顺序为本轮事件循环的末尾
setTimeout(() => {
// 只有状态为 pending 时才能转变,
if (self.state === PENDING) {
// 修改状态
self.state = FULFILLED;
// 设置传入的值
self.value = value;
// 执行回调函数
self.resolvedCallbacks.forEach(callback => {
callback(value);
});
}
}, 0);
}
// 状态转变为 rejected 方法
function reject(value) {
// 保证代码的执行顺序为本轮事件循环的末尾
setTimeout(() => {
// 只有状态为 pending 时才能转变
if (self.state === PENDING) {
// 修改状态
self.state = REJECTED;
// 设置传入的值
self.value = value;
// 执行回调函数
self.rejectedCallbacks.forEach(callback => {
callback(value);
});
}
}, 0);
}
// 将两个方法传入函数执行
try {
fn(resolve, reject);
} catch (e) {
// 遇到错误时,捕获错误,执行 reject 函数
reject(e);
}
}
MyPromise.prototype.then = function(onResolved, onRejected) {
const self = this;
return new MyPromise((resolve, reject) => {
// 处理 onResolved
let resolved = () => {
try {
if (typeof onResolved === 'function') {
const result = onResolved(self.value);
// 如果结果仍然是 Promise,则等待它解决后再 resolve
result instanceof MyPromise ? result.then(resolve, reject) : resolve(result);
} else {
resolve(self.value);
}
} catch (error) {
reject(error);
}
};
// 处理 onRejected
let rejected = () => {
try {
if (typeof onRejected === 'function') {
const result = onRejected(self.value);
result instanceof MyPromise ? result.then(resolve, reject) : resolve(result);
} else {
reject(self.value);
}
} catch (error) {
reject(error);
}
};
// 根据当前 Promise 的状态,决定调用哪个回调
switch (self.state) {
case FULFILLED:
resolved();
break;
case REJECTED:
rejected();
break;
case PENDING:
self.resolvedCallbacks.push(resolved);
self.rejectedCallbacks.push(rejected);
break;
}
});
};
// 示例使用
let promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
promise.then(
(value) => {
console.log(value)
return 2
},
)
.then((erro) => {
console.log(erro)
})
5. 手写 Promise.then
javascript
MyPromise.prototype.then = function(onResolved, onRejected) {
const self = this;
return new MyPromise((resolve, reject) => {
// 处理 onResolved
let resolved = () => {
try {
if (typeof onResolved === 'function') {
const result = onResolved(self.value);
// 如果结果仍然是 Promise,则等待它解决后再 resolve
result instanceof MyPromise ? result.then(resolve, reject) : resolve(result);
} else {
resolve(self.value);
}
} catch (error) {
reject(error);
}
};
// 处理 onRejected
let rejected = () => {
try {
if (typeof onRejected === 'function') {
const result = onRejected(self.value);
result instanceof MyPromise ? result.then(resolve, reject) : resolve(result);
} else {
reject(self.value);
}
} catch (error) {
reject(error);
}
};
// 根据当前 Promise 的状态,决定调用哪个回调
switch (self.state) {
case FULFILLED:
resolved();
break;
case REJECTED:
rejected();
break;
case PENDING:
self.resolvedCallbacks.push(resolved);
self.rejectedCallbacks.push(rejected);
break;
}
});
};
8. 手写防抖函数
javascript
// 函数防抖的实现
function debounce(fn, wait) {
let timer = null;
return function() {
let context = this,
args = arguments;
// 如果此时存在定时器的话,则取消之前的定时器重新记时
if (timer) {
clearTimeout(timer);
timer = null;
}
// 设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
}
// 使用示例
const myEfficientFn = debounce(function() {
// 一些高开销的操作,例如 DOM 操作、网络请求等
console.log('Function called!');
}, 250); // 设置防抖间隔为 250 毫秒
// 假设我们有一个频繁触发的事件处理器,例如滚动事件
window.addEventListener('scroll', myEfficientFn);
9. 手写节流函数
javascript
function throttle(func, limit) {
let inThrottle;
return function() {
const context = this;
const args = arguments;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
// 使用示例
const handleScroll = throttle(function() {
console.log('Scrolling...');
// 更新页面内容
}, 200);
// 绑定到窗口的 scroll 事件
window.addEventListener('scroll', handleScroll);
10. 手写类型判断函数
javascript
function getType(value) {
// 判断数据是 null 的情况
if (value === null) {
return value + "";
}
// 判断数据是引用类型的情况
if (typeof value === "object") {
let valueClass = Object.prototype.toString.call(value),
type = valueClass.split(" ")[1].split("");
type.pop();
return type.join("").toLowerCase();
} else {
// 判断数据是基本数据类型的情况和函数的情况
return typeof value;
}
}
Object.prototype.toString.call(value): 通过间接的方式调用 toString 方法,这样可以确保我们得到的是对象的内部类字符串,而不是对象自己定义的 toString 方法返回的结果。
11. 手写 call 函数
1、判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
2、判断传入上下文对象是否存在,如果不存在,则设置为 window 。
3、处理传入的参数,截取第一个参数后的所有参数。
4、将函数作为上下文对象的一个属性。
5、使用上下文对象来调用这个方法,并保存返回结果。
6、删除刚才新增的属性。
返回结果。
javascript
Function.prototype.myCall = function(context, ...args) {
// 确保context不是null或undefined,否则设置为全局对象(window或global)
context = context ? Object(context) : window;
// 临时给context添加一个唯一的属性,并将函数本身赋值给它
const fnSymbol = Symbol('fn');
context[fnSymbol] = this;
// 使用context来调用这个函数,并传入参数args
const result = context[fnSymbol](...args); // 调用函数,this绑定到 context
// 调用完成后,删除临时添加的属性
delete context[fnSymbol];
// 返回函数调用的结果
return result;
};
function greet(name, age) {
console.log(`Hello, my name is ${name} and I'm ${age} years old.`);
return this.value;
}
const obj = { value: 'Test' };
// 使用手写的 myCall 方法
greet.myCall(obj, 'Alice', 30); // 输出: Hello, my name is Alice and I'm 30 years old.
// 并且会返回 'Test',因为 this 在 greet 函数内部指向了 obj 对象
12. 手写 apply 函数
javascript
Function.prototype.myApply = function(context, args) {
// 确保context不是null或undefined,否则设置为全局对象(window或global)
context = context ? Object(context) : window;
// 如果args不是数组或类似数组对象,则抛出错误
if (!Array.isArray(args)) {
throw new Error('Second argument to myApply must be an array or array-like object');
}
// 将args转换为真正的数组(如果它是类似数组的对象)
args = Array.prototype.slice.call(args);
// 临时给context添加一个唯一的属性,并将函数本身赋值给它
const fnSymbol = Symbol('fn');
context[fnSymbol] = this;
// 使用context来调用这个函数,并传入args中的参数
const result = context[fnSymbol](...args);
// 调用完成后,删除临时添加的属性
delete context[fnSymbol];
// 返回函数调用的结果
return result;
};
13. 手写 bind 函数
javascript
Function.prototype.myBind = function(context, ...initialArgs) {
// 保存对原函数的引用
const self = this;
// 返回一个新的函数
return function F(...args) {
// 如果F作为构造函数被new调用,则绑定context到新的实例对象上
if (this instanceof F) {
return new self(...initialArgs, ...args);
}
// 调用原函数,并传入之前保存的initialArgs和当前函数的args
return self.apply(context, [...initialArgs, ...args]);
};
};
//调用
function greet(name, age) {
console.log(`Hello, my name is ${name} and I'm ${age} years old.`);
console.log(this.value);
}
const obj = { value: 'Test' };
// 使用手写的 myBind 方法
const boundGreet = greet.myBind(obj, 'Alice');
boundGreet(30); // 输出: Hello, my name is Alice and I'm 30 years old.
// 并且会输出: Test,因为 this 在 greet 函数内部指向了 obj 对象
14. 函数柯里化的实现
javascript
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
// 使用示例
function sum(a, b, c) {
return a + b + c;
}
const curriedSum = curry(sum);
const sumTwo = curriedSum(1, 2); // 返回一个函数,等待第三个参数
const result = sumTwo(3); // 调用这个函数,返回 6
console.log(result)
15. 实现AJAX请求
通过 JavaScript 的 异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。
创建AJAX请求的步骤:
1、创建一个 XMLHttpRequest 对象。
2、在这个对象上使用 open 方法创建一个 HTTP 请求,open 方法所需要的参数是(请求的方法、请求的地址、是否异步和用户的认证信息)。
3、在发起请求前,可以为这个对象添加一些信息和监听函数。比如说可以通过 setRequestHeader 方法来为请求添加头信息。还可以为这个对象添加一个状态监听函数。一个 XMLHttpRequest 对象一共有 5 个状态,当它的状态变化时会触发onreadystatechange 事件,可以通过设置监听函数,来处理请求成功后的结果。当对象的 readyState 变为 4 的时候,代表服务器返回的数据接收完成,这个时候可以通过判断请求的状态,如果状态是 2xx 或者 304 的话则代表返回正常。这个时候就可以通过 response 中的数据来对页面进行更新了。
4、当对象的属性和监听函数设置完成后,最后调用 send 方法来向服务器发起请求,可以传入参数作为发送的数据体。
javascript
const SERVER_URL = "/server";
let xhr = new XMLHttpRequest();
// 创建 Http 请求
xhr.open("GET", SERVER_URL, true);
// 设置状态监听函数
xhr.onreadystatechange = function() {
if (this.readyState !== 4) return;
// 当请求成功时
if (this.status === 200) {
handle(this.response);
} else {
console.error(this.statusText);
}
};
// 设置请求失败时的监听函数
xhr.onerror = function() {
console.error(this.statusText);
};
// 设置请求头信息
xhr.responseType = "json";
xhr.setRequestHeader("Accept", "application/json");
// 发送 Http 请求
xhr.send(null);
16. 使用Promise封装AJAX请求
javascript
// promise 封装实现:
function getJSON(url) {
// 创建一个 promise 对象
let promise = new Promise(function(resolve, reject) {
let xhr = new XMLHttpRequest();
// 新建一个 http 请求
xhr.open("GET", url, true);
// 设置状态的监听函数
xhr.onreadystatechange = function() {
if (this.readyState !== 4) return;
// 当请求成功或失败时,改变 promise 的状态
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
// 设置错误监听函数
xhr.onerror = function() {
reject(new Error(this.statusText));
};
// 设置响应的数据类型
xhr.responseType = "json";
// 设置请求头信息
xhr.setRequestHeader("Accept", "application/json");
// 发送 http 请求
xhr.send(null);
});
return promise;
}
17. 实现浅拷贝
浅拷贝意味着只有对象的顶层属性和值被复制。如果对象的属性值是一个对象或数组(即引用类型),那么实际上复制的是这个对象或数组在内存中的地址引用,而不是对象或数组本身的内容。
(1)Object.assign()
javascript
let target = {a: 1};
let object2 = {b: 2,obj: {c: 4}};
Object.assign(target,object2);
object2.obj.c = 6
object2.b = 9
console.log(target); // { a: 1, b: 2, obj: { c: 6 } }
注意:
如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性。
如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回。
因为null 和 undefined 不能转化为对象,所以第一个参数不能为null或 undefined,会报错。
(2)扩展运算符
javascript
let obj1 = {a:1,b:{c:1}}
let obj2 = {...obj1};
obj1.a = 2;
console.log(obj1); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj1.b.c = 2;
console.log(obj1); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}
(3)数组方法实现数组浅拷贝
1、Array.prototype.slice
slice() 方法返回一个新的数组对象,这一对象是一个由 start 和 end 决定的原数组的浅拷贝(包括 start,不包括 end)
javascript
let arr = [{a: 1},{b: 2}];
let a = arr.slice(); // [{a: 1},{b: 2}];
arr[0].a = 5
console.log(arr,a) // [ { a: 5 }, { b: 2 } ] [ { a: 5 }, { b: 2 } ]
2、Array.prototype.concat
javascript
let arr = [{a: 1},{b: 2}];
let a = arr.concat(); // [{a: 1},{b: 2}];
arr[0].a = 5
console.log(arr,a) // [ { a: 5 }, { b: 2 } ] [ { a: 5 }, { b: 2 } ]
(4)手写实现浅拷贝
javascript
function shallowCopy(object) {
// 只拷贝对象
if (!object || typeof object !== "object") return;
// 根据 object 的类型判断是新建一个数组还是对象
let newObject = Array.isArray(object) ? [] : {};
// 遍历 object,并且判断是 object 的属性才拷贝
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = object[key];
}
}
return newObject;
}// 浅拷贝的实现;
18. 实现深拷贝
(1)JSON.stringify()
使用JSON.parse(JSON.stringify(obj)),但存在问题,拷贝的对象中如果有函数,undefined,symbol,当使用过JSON.stringify()进行处理之后,都会消失。
(2)手写实现深拷贝函数
javascript
// 深拷贝的实现
function deepCopy(object) {
if (!object || typeof object !== "object") return;
let newObject = Array.isArray(object) ? [] : {};
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] =
typeof object[key] === "object" ? deepCopy(object[key]) : object[key];
}
}
return newObject;
}
二、数据处理
1. 实现数组的扁平化
(1)递归实现
javascript
function fun (arr) {
if (!Array.isArray(arr)) {
return
}
let result = []
for (let item of arr) {
if (Array.isArray(item)) {
result = result.concat(fun(item))
} else {
result.push(item)
}
}
return result
}
let arr = [1, [2, [3, 4, 5]]];
console.log(fun(obj))
(2)reduce 函数迭代
javascript
let arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.reduce(function(prev, next){
return prev.concat(Array.isArray(next) ? flatten(next) : next)
}, [])
}
console.log(flatten(arr));// [1, 2, 3, 4,5]
2. 实现数组去重
javascript
const array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];
Array.from(new Set(array)); // [1, 2, 3, 5, 9, 8]
3. 实现数组的flat方法
javascript
function _flat(arr, depth) {
if(!Array.isArray(arr) || depth <= 0) {
return arr;
}
return arr.reduce((prev, cur) => {
if (Array.isArray(cur)) {
return prev.concat(_flat(cur, depth - 1))
} else {
return prev.concat(cur);
}
}, []);
}
4. 实现数组的push方法
javascript
let arr = [];
Array.prototype._push = function() {
for( let i = 0 ; i < arguments.length ; i++){
this[this.length] = arguments[i] ;
}
return this.length;
}
5. 实现数组的filter方法
javascript
Array.prototype._filter = function(fn) {
if (typeof fn !== "function") {
throw Error('参数必须是一个函数');
}
const res = [];
for (let i = 0, len = this.length; i < len; i++) {
fn(this[i]) && res.push(this[i]);
}
return res;
}
6. 实现数组的map方法
javascript
Array.prototype._map = function(fn) {
if (typeof fn !== "function") {
throw Error('参数必须是一个函数');
}
const res = [];
for (let i = 0, len = this.length; i < len; i++) {
res.push(fn(this[i]));
}
return res;
}
7. 实现字符串的repeat方法
javascript
function repeat(s, n) {
return (new Array(n + 1)).join(s);
}
8. 实现非负大整数相加
javascript
function sumBigNumber(a, b) {
let res = '';
let temp = 0;
a = a.split('');
b = b.split('');
while (a.length || b.length || temp) {
temp += ~~a.pop() + ~~b.pop();
res = (temp % 10) + res;
temp = temp > 9
}
return res.replace(/^0+/, '');
}
9. 实现类数组转化为数组
通过 call 调用数组的 slice 方法来实现转换
javascript
Array.prototype.slice.call(arrayLike);
通过 call 调用数组的 splice 方法来实现转换
javascript
Array.prototype.splice.call(arrayLike, 0);
通过 apply 调用数组的 concat 方法来实现转换
javascript
Array.prototype.concat.apply([], arrayLike);
通过 Array.from 方法来实现转换
javascript
Array.from(arrayLike);
三、场景应用
1. 用Promise实现图片的异步加载
javascript
let imageAsync=(url)=>{
return new Promise((resolve,reject)=>{
let img = new Image();
img.src = url;
img.οnlοad=()=>{
console.log(`图片请求成功,此处进行通用操作`);
resolve(image);
}
img.οnerrοr=(err)=>{
console.log(`失败,此处进行失败的通用操作`);
reject(err);
}
})
}
imageAsync("url").then(()=>{
console.log("加载成功");
}).catch((error)=>{
console.log("加载失败");
})
2. 实现发布-订阅模式
javascript
class EventBus {
constructor() {
this.subscribers = {};
}
subscribe(event, callback) {
if (!this.subscribers[event]) {
this.subscribers[event] = [];
}
this.subscribers[event].push(callback);
}
publish(event, data) {
if (this.subscribers[event]) {
this.subscribers[event].forEach(callback => {
callback(data);
});
}
}
unsubscribe(event, callback) {
if (this.subscribers[event]) {
this.subscribers[event] = this.subscribers[event].filter(subCallback => subCallback !== callback);
}
}
}
// 使用示例:
const bus = new EventBus();
function handleMessage(data) {
console.log('Received message:', data);
}
bus.subscribe('message', handleMessage);
bus.publish('message', 'Hello, world!'); // 输出: Received message: Hello, world!
bus.unsubscribe('message', handleMessage);
3. 查找文章中出现频率最高的单词
javascript
function findMostWord(article) {
// 合法性判断
if (!article) return;
// 参数处理
article = article.trim().toLowerCase();
let wordList = article.match(/[a-z]+/g),
visited = [],
maxNum = 0,
maxWord = "";
article = " " + wordList.join(" ") + " ";
// 遍历判断单词出现次数
wordList.forEach(function(item) {
if (visited.indexOf(item) < 0) {
// 加入 visited
visited.push(item);
let word = new RegExp(" " + item + " ", "g"),
num = article.match(word).length;
if (num > maxNum) {
maxNum = num;
maxWord = item;
}
}
});
return maxWord + " " + maxNum;
}
4. 封装异步的fetch,使用async await方式来使用
javascript
(async () => {
class HttpRequestUtil {
async get(url) {
const res = await fetch(url);
const data = await res.json();
return data;
}
async post(url, data) {
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await res.json();
return result;
}
async put(url, data) {
const res = await fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
data: JSON.stringify(data)
});
const result = await res.json();
return result;
}
async delete(url, data) {
const res = await fetch(url, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
data: JSON.stringify(data)
});
const result = await res.json();
return result;
}
}
const httpRequestUtil = new HttpRequestUtil();
const res = await httpRequestUtil.get('http://golderbrother.cn/');
console.log(res);
})();
5. 实现prototype继承
所谓的原型链继承就是让新实例的原型等于父类的实例:
javascript
//父方法
function SupperFunction(flag1){
this.flag1 = flag1;
}
//子方法
function SubFunction(flag2){
this.flag2 = flag2;
}
//父实例
var superInstance = new SupperFunction(true);
//子继承父
SubFunction.prototype = superInstance;
//子实例
var subInstance = new SubFunction(false);
//子调用自己和父的属性
subInstance.flag1; // true
subInstance.flag2; // false
6. 实现双向数据绑定
javascript
let obj = {}
let input = document.getElementById('input')
let span = document.getElementById('span')
// 数据劫持
Object.defineProperty(obj, 'text', {
configurable: true,
enumerable: true,
get() {
console.log('获取数据了')
},
set(newVal) {
console.log('数据更新了')
input.value = newVal
span.innerHTML = newVal
}
})
// 输入监听
input.addEventListener('keyup', function(e) {
obj.text = e.target.value
})
7. 实现简单路由
javascript
// hash路由
class Route{
constructor(){
// 路由存储对象
this.routes = {}
// 当前hash
this.currentHash = ''
// 绑定this,避免监听时this指向改变
this.freshRoute = this.freshRoute.bind(this)
// 监听
window.addEventListener('load', this.freshRoute, false)
window.addEventListener('hashchange', this.freshRoute, false)
}
// 存储
storeRoute (path, cb) {
this.routes[path] = cb || function () {}
}
// 更新
freshRoute () {
this.currentHash = location.hash.slice(1) || '/'
this.routes[this.currentHash]()
}
}
// 创建 Route 类的实例
const router = new Route();
// 为 '/' 路径注册一个回调函数
router.storeRoute('/', function() {
console.log('Home page!');
// 这里可以执行当访问 '/' 路径时需要的操作
});
// 为 '/about' 路径注册一个回调函数
router.storeRoute('about', function() {
console.log('About page!');
// 这里可以执行当访问 '/about' 路径时需要的操作
});
// 手动触发 freshRoute 方法,模拟 hash 变化或页面加载完成
// router.freshRoute();
// 或者,你可以通过改变 location.hash 来触发 hashchange 事件
location.hash = '#about'; // 这将触发路由到 '/about' 的回调函数
8. 实现斐波那契数列
1、递归方式:
递归方法比较直观,但是在大规模的计算中,可能会因为重复计算导致性能问题。
javascript
function fibonacci(n) {
if (n <= 0) {
return 0;
} else if (n === 1) {
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
// 使用方法
console.log(fibonacci(10)); // 输出: 55
2、迭代方式:
javascript
function fibonacci(n) {
if (n <= 0) {
return 0;
} else if (n === 1) {
return 1;
} else {
let a = 0;
let b = 1;
let temp;
for (let i = 2; i <= n; i++) {
temp = a + b;
a = b;
b = temp;
}
return b;
}
}
// 使用方法
console.log(fibonacci(10)); // 输出: 55
9. 实现 jsonp
javascript
// 动态的加载js文件
function addScript(src) {
const script = document.createElement('script');
script.src = src;
script.type = "text/javascript";
document.body.appendChild(script);
}
addScript("http://xxx.xxx.com/xxx.js?callback=handleRes");
// 设置一个全局的callback函数来接收回调结果
function handleRes(res) {
console.log(res);
}
// 接口返回的数据格式
handleRes({a: 1, b: 2});