收集整理2022企业管理系统定制开发年最新题及答案,企业管理系统定制开发方便平时翻看记忆,企业管理系统定制开发欢迎各位大佬们补充。
一般来说,企业管理系统定制开发把下面基础中的高频题企业管理系统定制开发写熟练就差不多了。企业管理系统定制开发当然去面大厂这些远远不够,企业管理系统定制开发还要再刷一些。
基础
高频
1.手写 instanceof
- // 原理:企业管理系统定制开发验证当前类的原型prototype企业管理系统定制开发是否会出现在实例的原型链proto上,只要在它的原型链上,则结果都为true
- function myinstanceOf_(obj, class_name) {
- // let proto = obj.__proto__;
- let proto = Object.getPrototypeOf(obj)
- let prototype = class_name.prototype
- while (true) {
- if (proto == null) return false
- if (proto == prototype) return true
- // proto = proto.__proto__;
- proto = Object.getPrototypeOf(proto)
- }
- }
2.手写 new 操作符
- function myNew(){
- //1.创建一个新的对象
- let obj=new Object();
- //获得构造函数
- let con = [].shift.call(arguments); //[]为Array构造函数的实例 将类数组转化为真正的数组
- //2.新对象的隐式原型__proto__链接到构造函数的显式原型prototype
- obj.__proto__ = con.prototype;
- //3.构造函数内部的 this 绑定到这个新创建的对象 执行构造函数
- let result = con.apply(obj, arguments)
- //4.如果构造函数没有返回非空对象,则返回创建的新对象
- return typeof result == 'object' ? result:obj;
- }
- var test_create = myNew(Car, 'a', 'b', 'c');
- console.log(test_create)
3.手写 call、apply、bind 函数
- call(thisArg, ...args)
- // 给函数的原型添加 _call 方法,使得所有函数都能调用 _call
- // thisArg 就是要绑定的那个this;...args 扩展操作符传参,适合不定长参数,args是一个数组
- Function.prototype._call = function(thisArg,...args){
- // 1.获取需要执行的函数
- fn = this
-
- // 2.将 thisArg 转成对象类型(防止它传入的是非对象类型,例如123数字)
- thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
-
- // 3.使用 thisArg 调用函数,绑定 this
- thisArg.fn = fn
- let result = thisArg.fn(...args)
- delete thisArg.fn
-
- // 4.返回结果
- return result
- }
- apply(thisArg, argsArray)
- Function.prototype._apply = function(thisArg,argArray){
- // 1.获取需要执行的函数
- fn = this
-
- // 2.将 thisArg 转成对象类型(防止它传入的是非对象类型,例如123数字)
- thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
- // 判断一些边界情况
- argArray = argArray || []
-
- // 3.使用 thisArg 调用函数,绑定 this
- thisArg.fn = fn
- // 将传递过来的数组(可迭代对象)拆分,传给函数
- let result = thisArg.fn(...argArray)
- delete thisArg.fn
-
- // 4.返回结果
- return result
- }
- bind(thisArg, ...args)
- Function.prototype._call = function(thisArg,...args){
- fn = this
- thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
-
- thisArg.fn = fn
- let result = thisArg.fn(...args)
- delete thisArg.fn
-
- return result
- }
-
- // 利用 call 模拟 bind
- Function.prototype._bind = function(thisArg,...args){
- let fn = this // 需要调用的那个函数的引用
- // bind 需要返回一个函数
- return function(){
- return fn._call(thisArg, ...args)
- }
- }
4.手写深拷贝
PS:也可以用一样的模板,当然深拷贝考得多
- function deepCopy(object) {
- if (!object || typeof object !== "object") return object;
-
- let newObject = Array.isArray(object) ? [] : {};
-
- for (let key in object) {
- if (object.hasOwnProperty(key)) {
- newObject[key] = deepCopy(object[key]);
- }
- }
-
- return newObject;
- }
进阶:解决循环引用的深拷贝
- function deepClone(obj, hash = new WeakMap()) {
- if (!object || typeof object !== "object") return object;
-
- // 是对象的话就要进行深拷贝,遇到循环引用,将引用存储起来,如果存在就不再拷贝
- if (hash.get(obj)) return hash.get(obj);
- let cloneObj = Array.isArray(object) ? [] : {};
- hash.set(obj, cloneObj);
-
- for (let key in obj) {
- if (obj.hasOwnProperty(key)) {
- // 实现一个递归拷贝
- cloneObj[key] = deepClone(obj[key], hash);
- }
- }
- return cloneObj;
- }
5.手写防抖节流
- function debounce(func, delay) {
-
- // 这里使用了闭包,所以 timer 不会轻易被销毁
- let timer = null
-
- // 生成一个新的函数并返回
- return function (...args) {
- // 清空定时器
- if (timer) {
- clearTimeout(timer)
- }
- // 重新启动定时器
- timer = setTimeout(() => {
- func.call(this, ...args)
- }, delay)
- }
- }
-
- function throttle(func, delay) {
- let timer = null
- // 在 delay 时间内,最多执行一次 func
- return function (...args) {
- if (!timer) {
- timer = setTimeout(() => {
- func.call(this, ...args)
- // 完成一次计时,清空,待下一次触发
- timer = null
- }, delay)
- }
- }
- }
6.手写Ajax请求
- function ajax(url) {
- // 创建一个 XHR 对象
- return new Promise((resolve,reject) => {
- const xhr = new XMLHttpRequest()
- // 指定请求类型,请求URL,和是否异步
- xhr.open('GET', url, true)
- xhr.onreadystatechange = funtion() {
- // 表明数据已就绪
- if(xhr.readyState === 4) {
- if(xhr.status === 200){
- // 回调
- resolve(JSON.stringify(xhr.responseText))
- }
- else{
- reject('error')
- }
- }
- }
- // 发送定义好的请求
- xhr.send(null)
- })
- }
7.手写数组去重
- // 1.Set + 数组复制
- fuction unique1(array){
- // Array.from(),对一个可迭代对象进行浅拷贝
- return Array.from(new Set(array))
- }
-
- // 2.Set + 扩展运算符浅拷贝
- function unique2(array){
- // ... 扩展运算符
- return [...new Set(array)]
- }
-
- // 3.filter,判断是不是首次出现,如果不是就过滤掉
- function unique3(array){
- return array.filter((item,index) => {
- return array.indexOf(item) === index
- })
- }
-
- // 4.创建一个新数组,如果之前没加入就加入
- function unique4(array){
- let res = []
- array.forEach(item => {
- if(res.indexOf(item) === -1){
- res.push(item)
- }
- })
- return res
- }
进阶:如果数组内有数组和对象,应该怎么去重(此时对象的地址不同,用Set去不了重)
需要开通正版 WebStorm 的可以联系我,56元一年,正版授权激活,官网可查有效期,有需要的加我微信:poxiaozhiai6,备注:915。
8.手写数组扁平
- // 方法1-3:递归
- function flat1(array){
- // reduce(): 对数组的每一项执行归并函数,这个归并函数的返回值会作为下一次调用时的参数,即 preValue
- // concat(): 合并两个数组,并返回一个新数组
- return array.reduce((preValue,curItem) => {
- return preValue.concat(Array.isArray(curItem) ? flat1(curItem) : curItem)
- },[])
- }
-
- function flat2(array){
- let res = []
- array.forEach(item => {
- if(Array.isArray(item)){
- // res.push(...flat2(item))
- // 如果遇到一个数组,递归
- res = res.concat(flat2(item))
- }
- else{
- res.push(item)
- }
- })
- return res
- }
-
- function flat3(array){
- // some(): 对数组的每一项都运行传入的函数,如果有一项返回 TRUE,则这个方法返回 TRUE
- while(array.some(item => Array.isArray(item))){
- // ES6 增加了扩展运算符,用于取出参数对象的所有可遍历属性,拷贝到当前对象之中:
- array = [].concat(...array)
- console.log(...array)
- }
- return array
- }
-
- // 方法4、5:先转成字符串,再变回数组
- function flat4(array){
- //[1,[2,3]].toString() => 1,2,3
- return array.toString().split(',').map(item => parseInt(item))
- }
-
- function flat5(array){
- return array.join(',').split(',').map(item => Number(item))
- }
9.手写数组乱序
- // 方法1: sort + Math.random()
- function shuffle1(arr){
- return arr.sort(() => Math.random() - 0.5);//
- }
-
- // 方法2:时间复杂度 O(n^2)
- // 随机拿出一个数(并在原数组中删除),放到新数组中
- function randomSortArray(arr) {
- let backArr = [];
- while (arr.length) {
- let index = parseInt(Math.random() * arr.length);
- backArr.push(arr[index]);
- arr.splice(index, 1);
- }
- return backArr;
- }
-
- // 方法3:时间复杂度 O(n)
- // 随机选一个放在最后,交换
- function randomSortArray2(arr) {
- let lenNum = arr.length - 1;
- for (let i = 0; i < lenNum; i++) {
- let index = parseInt(Math.random() * (lenNum + 1 - i));
- [a[index],a[lenNum - i]] = [a[lenNum - i],a[index]]
- }
- return arr;
- }
10.手写 Promise.all()、Promise.race()
PS: 有能力的可以去写下 Promise 和其他的 Promise 方法
- function myAll(promises){
- // 问题关键:什么时候要执行resolve,什么时候要执行 reject
- return new Promise((resolve,reject) => {
- values = []
- // 迭代数组中的 Promise,将每个 promise 的结果保存到一个数组里
- promises.forEach(promise => {
- // 如果不是 Promise 类型要先包装一下
- // 调用 then 得到结果
- Promise.resolve(promise).then(res => {
- values.push(res)
- // 如果全部成功,状态变为 fulfilled
- if(values.length === promises.length){
- resolve(values)
- }
- },err => { // 如果出现了 rejected 状态,则调用 reject() 返回结果
- reject(err)
- })
- })
- }
- )
- }
11.手撕快排
PS: 常见的排序算法,像冒泡,选择,插入排序这些最好也背一下,堆排序归并排序能写则写。万一考到了呢,要是写不出就直接回去等通知了。
- const _quickSort = array => {
- // 补全代码
- quickSort(array, 0, array.length - 1)
- // 别忘了返回数组
- return array
- }
-
- const quickSort = (array, start, end) => {
- // 注意递归边界条件
- if(end - start < 1) return
- // 取第一个数作为基准
- const base = array[start]
- let left = start
- let right = end
- while(left < right){
- // 从右往左找小于基准元素的数,并赋值给右指针 array[right]
- while(left < right && array[right] >= base) right--
- array[left] = array[right]
- // 从左往右找大于基准元素的数,并赋值给左指针 array[left]
- while(left < right && array[left] <= base) left++
- array[right] = array[left]
- }
- // 双指针重合处,将基准元素填到这个位置。基准元素已经事先保存下来了,因此不用担心上面的赋值操作会覆盖掉基准元素的值
- // array[left] 位置已经确定,左边的都比它小,右边的都比它大
- array[left] = base
- quickSort(array, start, left - 1)
- quickSort(array, left + 1, end)
- return array
- }
12.手写 JSONP
- // 动态的加载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);
- }
-
- // 接口返回的数据格式,加载完js脚本后会自动执行回调函数
- handleRes({a: 1, b: 2});
13.手写寄生组合继承
PS: 组合继承也要能写出来
- function Parent(name) {
- this.name = name;
- this.say = () => {
- console.log(111);
- };
- }
- Parent.prototype.play = () => {
- console.log(222);
- };
- function Children(name,age) {
- Parent.call(this,name);
- this.age = age
- }
- Children.prototype = Object.create(Parent.prototype);
- Children.prototype.constructor = Children;
- // let child = new Children("111");
- // // console.log(child.name);
- // // child.say();
- // // child.play();
14.数组/字符串操作题
可以自己找些基础的练一下,就不一一列举了
15.手写二分查找
- // 迭代版
- function search(nums, target) {
- // write code here
- if(nums.length === 0) return -1
- let left = 0,right = nums.length - 1
- // 注意这里的边界,有等号
- while(left <= right){
- let mid = Math.floor((left + right) / 2)
- if(nums[mid] < target) left = mid + 1
- else if(nums[mid] > target) right = mid - 1
- else return mid
- }
- return -1
- }
- // 递归版
- function binary_search(arr, low, high, key) {
- if (low > high) {
- return -1;
- }
- var mid = parseInt((high + low) / 2);
- if (arr[mid] == key) {
- return mid;
- } else if (arr[mid] > key) {
- high = mid - 1;
- return binary_search(arr, low, high, key);
- } else if (arr[mid] < key) {
- low = mid + 1;
- return binary_search(arr, low, high, key);
- }
- };
16.手写函数柯里化
- function sum(x,y,z) {
- return x + y + z
- }
-
- function hyCurrying(fn) {
- // 判断当前已经接收的参数的个数,和函数本身需要接收的参数是否一致
- function curried(...args) {
- // 1.当已经传入的参数 大于等于 需要的参数时,就执行函数
- if(args.length >= fn.length){
- // 如果调用函数时指定了this,要将其绑定上去
- return fn.apply(this, args)
- }
- else{
- // 没有达到个数时,需要返回一个新的函数,继续来接收参数
- return function(...args2) {
- //return curried.apply(this, [...args, ...args2])
- // 接收到参数后,需要递归调用 curried 来检查函数的个数是否达到
- return curried.apply(this, args.concat(args2))
- }
- }
- }
- return curried
- }
-
- var curryAdd = hyCurry(add1)
-
- curryAdd(10,20,30)
- curryAdd(10,20)(30)
- curryAdd(10)(20)(30)
其他
1.手写事件委托
2.手写组合函数
3.常见DOM操作
4.手写数组常见方法 Array.filter/map/fill/reduce
5.手写Object.create()
6.手写Object.is()
7.手写Object.freeze()
8.手写列表转树
9.数字千分位分割
10.下划线转驼峰
11.大数相加
场景模拟题
高频
1.实现 sleep 函数
- async function test() {
- console.log('开始')
- await sleep(4000)
- console.log('结束')
- }
-
- function sleep(ms) {
- return new Promise(resolve => {
- setTimeout(() => {
- resolve()
- }, ms)
- })
- }
- test()
2.setTimeout 实现 setInterval
- function setInterval(fn, time){
- var interval = function(){
- // time时间过去,这个异步被执行,而内部执行的函数正是interval,就相当于进了一个循环
- setTimeout(interval, time);
- // 同步代码
- fn();
- }
- //interval被延迟time时间执行
- setTimeout(interval,time);
- }
3.异步循环打印 1,2,3
- var sleep = function (time, i) {
- return new Promise(function (resolve, reject) {
- setTimeout(function () {
- resolve(i);
- }, time);
- })
- };
-
-
- var start = async function () {
- for (let i = 1; i <= 3; i++) {
- let result = await sleep(1000, i);
- console.log(result);
- }
- };
-
- start();
4.循环打印红、黄、绿
- function red() {
- console.log('red');
- }
- function green() {
- console.log('green');
- }
- function yellow() {
- console.log('yellow');
- }
-
- const task = (timer, light) => {
- new Promise((resolve, reject) => {
- setTimeout(() => {
- if (light === 'red') {
- red()
- }
- else if (light === 'green') {
- green()
- }
- else if (light === 'yellow') {
- yellow()
- }
- resolve()
- }, timer)
- })
- }
- const taskRunner = async () => {
- await task(3000, 'red')
- await task(2000, 'green')
- await task(2100, 'yellow')
- taskRunner()
- }
- taskRunner()
其他
Promise 并发控制相关的题目,例如
更多 Promise 的面试题在这里:,面大厂的兄弟可以看看