1: 手写create
function create(obj) {
// 构造函数
function Func () {
}
// 构造函数的原型指向传入的对象
Func.prototype = obj;
// 返回该对象
return new Func();
}
let newObj = create(obj);
2:js常见的金额处理
2.1 金额转千分位
function moneyToThousands(money) {
// 处理异常
let isMoneny = (money+ '').match(/\d+.?\d{0,2}/);
console.log(isMoneny);
if(!isMoneny) {
console.log('金额不合法');
return
}
// 整数部分
let integersPart = (money+ '').split('.')[0];
// 小数部分
let decimalPart = (money + '').split('.')[1] || '';
let arr = integersPart.split('').reverse(); // 千分位是从小到大分割的
let r = ''
arr.forEach((item, i) => {
if(i !== 0 && i % 3 === 0) {
r = item + ',' + r;
} else {
r = item + r;
}
})
return r + (decimalPart ? '.' + decimalPart : '');
}
2.2 千分位转金额
function ThousandsToMoney(thousands) {
while(thousands.indexOf(',') !== -1) {
thousands = thousands.replace(',', '');
}
console.log(thousands);
return thousands
}
2.3 金额转大写
3 手写instanceOf
function myInstanceof(obj, fun) {
let pro = Object.getPrototypeOf(obj); // 对象的原型
let prototype = fun.prototype;
while(true) {
if(!pro) {
return false;
}
if(pro === prototype) {
return true;
}
pro = Object.getPrototypeOf(pro)
}
}
手写New
// 实现new
function myNew(construct, ...args) {
let obj = {};
construct.prototype = Object.create(obj);
construct.apply(obj, args);
return obj
}
function Person (name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log(this.name)
}
let test = myNew(Person, 'LIUHUAN', 21);
console.log(test);
防抖
function debounceFun(fn, delay=500) {
let timer = null;
return function () {
if(timer) {
clearTimeout(timer);
}
setTimeout(() => {
fn.apply(this, args);
}, delay)
}
}
节流
throttle(fun, delay) {
let timer = null;
return function () {
if(!timer) {
timer = setTimeout(() => {
fun();
timer = null;
}, delay)
}
}
},
判断类型
function getType(value) {
if(value === null) {
return value + ''
}
if(typeof value === "object") {
return Object.prototype.toString.call(value).slice(8,1).toLowerCase()
} else {
return typeof value;
}
}
手写call,apply,bind
Function.prototype.myCall = function (ctx, ...args) {
if(ctx === null || ctx === undefined) ? globalThis : Object(ctx);
var key = Symbol('temp'); // 防止和对象cxt有重复的属性
Object.defineProperty(ctx, key, {
enumrable: false,
value: this
})
let result = ctx[key](...args); // 调用this()
delete ctx[key];
return result;
}
手写promise
class Mypromse {
static PENDING = '等待';
static FULFILLED='成功';
static REJECTTED = '失败';
constructor(func) {
this.status = Mypromse.PENDING;
this.result = null;
this.resolveCallbacks = [];
this.rejectCallbacks = [];
try{
func(this.resolve.bind(this), this.reject.bind(this))
}catch(error) {
this.reject(error);
} ;
}
resolve(result) {
setTimeout(() => {
this.status = Mypromse.FULFILLED;
this.result = result;
this.resolveCallbacks.forEach(callback => {
callback(result)
})
})
}
reject(result) {
setTimeout(() => {
this.status = Mypromse.REJECTTED;
this.result = result;
this.rejectCallbacks.forEach(callback => {
callback(result)
})
})
}
then(onFullfield, onRejected) {
onFullfield = typeof onFullfield === 'function' ? onFullfield : () => {};
onRejected = typeof onRejected === 'function' ? onRejected : () => {};
if(this.status === Mypromse.PENDING) {
this.resolveCallbacks.push(onFullfield)
this.rejectCallbacks.push(onRejected)
}
if(this.status === Mypromse.FULFILLED) {
setTimeout(() => {onFullfield(this.result)})
}
if(this.status === Mypromse.REJECTTED) {
setTimeout(() => {onRejected(this.result)})
}
}
}
console.log('第一步')
let p1 = new Mypromse((resolve, reject) => {
console.log('第二走')
setTimeout(() => {
resolve('这次一定');
console.log('第三步')
})
})
p1.then(res => {console.log(res)}, res => {console.log(res.message)});
console.log('第四步');
发布订阅者模式
class Observer{
constructor() {
this.message = {} // 调度者对象
}
// 订阅事件
$on(type, callback) {
if(!this.message[type]) {
this.message[type] = []
}
this.message[type].push(callback);
}
// 促发事件
$emit(type) {
if(!this.message[type]) {return}
this.message[type].forEach(item => {
item();
})
}
// 解绑事件
$off(type, callback) {
if(!this.message[type]) {
return
}
if(!callback) {return}
this.message[type] = this.message[type].filters(item => {
item !== callback
})
}
树形数据拍扁
1.直接拍扁,但是不用找parentId的 测试数据:
let treeData = [
{
id: 1,
name: '一级部门1',
children: [
{
id: 11,
name: '二级部门1',
children: [
{ id: 111, name: '三级部门1' },
{ id: 112, name: '三级部门2' },
],
},
{
id: 12,
name: '二级部门2',
children: [
{
id: 121,
name: '三级部门3',
children: [
{ id: 1211, name: '四级部门1' },
{ id: 1212, name: '四级部门2' },
],
},
],
},
],
},
{
id: 2,
name: '一级部门2',
children: [
{ id: 21, name: '二级部门3' },
{ id: 22, name: '二级部门4' },
],
},
];
代码实现:
function flatData(data) {
let arr = [];
data.forEach(item => {
arr.push({id: item.id, name: item.name});
item.children && arr.push(...flatData(item.children))
})
return arr
}
console.log(flatData(treeData));
2.直接拍扁,但是需要找parentId的,这种只需要再每次循环的时候记住parentId就行;
function flatDataWithParent(data, parentId=null) {
let arr = [];
console.log(parentId);
data.forEach(item => {
arr.push({id: item.id, name: item.name, parentId: parentId})
item.children && arr.push(...flatDataWithParent(item.children, item.id))
})
return arr
}
console.log(flatDataWithParent(treeData));
3.拍扁成路径的多维数组的形式,例如返回成这样的[[1,11,111],[2,22,222]]形式 这种在elemnt-ui级联选择器组件里面,选中某个节点,组件返回的就是这种多维数组的形式,于是自己写了一个简单的小实现。 `function transformTreeData(treeData) { const result = [];
function traverse(node, path) { // 将当前节点的 id 添加到路径中 const newPath = [...path, node.id];
// 如果当前节点没有子节点,将路径推入结果数组
if (!node.children || node.children.length === 0) {
result.push(newPath);
return;
}
// 递归遍历子节点
for (const child of node.children) {
traverse(child, newPath);
}
}
// 遍历根节点 for (const node of treeData) { traverse(node, []); }
return result; }`
扁平数据转树形
上一节讲了如何将树形数据拍扁,这节讲一下如何将拍扁的数据还原成树形数据;这种场景还是很常见的,也是通过递归的方式实现的 测试数据: