wap网站软件,wordpress 免备案cdn,软件开发工程师前景,建设网站公司需要准备哪些材料一、 实现深拷贝和浅拷贝
1.深拷贝
function checkType(any) {return Object.prototype.toString.call(any).slice(8, -1)
}//判断拷贝的要进行深拷贝的是数组还是对象#xff0c;是数组的话进行数组拷贝#xff0c;对象的话进行对象拷贝
//如果获得的数据是可遍历的#…一、 实现深拷贝和浅拷贝
1.深拷贝
function checkType(any) {return Object.prototype.toString.call(any).slice(8, -1)
}//判断拷贝的要进行深拷贝的是数组还是对象是数组的话进行数组拷贝对象的话进行对象拷贝
//如果获得的数据是可遍历的就拿到对应的value实现深拷贝
function clone(any){if(checkType(any) Object) { // 拷贝对象let o {};//遍历for(let key in any) {o[key] clone(any[key])}return o;} else if(checkType(any) Array) { // 拷贝数组var arr []//遍历for(let i 0,leng any.length;ileng;i) {arr[i] clone(any[i])}return arr;} else if(checkType(any) Function) { // 拷贝函数return new Function(return any.toString()).call(this)} else if(checkType(any) Date) { // 拷贝日期return new Date(any.valueOf())} else if(checkType(any) RegExp) { // 拷贝正则return new RegExp(any)} else if(checkType(any) Map) { // 拷贝Map 集合let m new Map()any.forEach((v,k){m.set(k, clone(v))})return m} else if(checkType(any) Set) { // 拷贝Set 集合let s new Set()for(let val of any.values()) {s.add(clone(val))}return s}return any;
}
2.浅拷贝
function shallowCopy(src) {var dst {};for (var prop in src) {//只要还没读完就继续读读到的话就直接把属性名返回就行没有进入深层//hasOwnProperty是用来判断一个对象是否有你给出的名称的属性或对象。有则返回true没有返回false不过需要注意的是此方法无法检查该对象的原型链中是否具有该属性该属性必须是对象本身的一个成员。if (src.hasOwnProperty(prop)) {dst[prop] src[prop];}}return dst;
}
二、 讲一下event loop
事件循环是js引擎执行js的机制用来实现js的异步特性。事件循环的过程为当执行栈空的时候就会从任务队列中取任务来执行。共分3步 取一个宏任务来执行。执行完毕后下一步。 取一个微任务来执行执行完毕后再取一个微任务来执行。直到微任务队列为空执行下一步。 更新UI渲染。
1.EventLoop概念
Event Loop即事件循环是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制也就是我们经常使用异步的原理。
因为JavaScript就是单线程也就是说同一个时间只能做一件事。单线程就意味着所有任务需要排队前一个任务结束才会执行后一个任务。如果前一个任务耗时很长后一个任务就不得不一直等着。
所有任务可以分成两种一种是同步任务synchronous另一种是异步任务asynchronous
2.同步任务和异步任务
同步任务函数返回—拿到预期结果 异步任务函数返回—拿不到预期结果还要通过一定的手段获得结果 简单点说 同步任务:会立即执行的任务 异步任务:不会立即执行的任务(异步任务又分为宏任务与微任务)
在异步任务中任务被分为两种一种宏任务MacroTask)也叫Task一种叫微任务MicroTask)。
宏任务由宿主对象发起的任务setTimeout。宏任务(定时器)包括 script setTimeoutsetIntervalsetImmediate(Node.js)I/OpostMessage MessageChannelUI rendering(即I/O、定时器、事件绑定、ajax)
微任务由js引擎发起的任务promise。微任务包括 process.nextTick(Node.js)promise.then()promise.catch()MutationObserver。(即Promise的then、catch、finally和process的nextTick)
注意Promise的then等方法是微任务而Promise中的代码是同步任务并且process的nextTick的执行顺序优先于Promise的then等方法因为process.nextTick是直接告诉浏览器说要尽快执行而不是放入队列
3.同步任务
当有多个同步任务时这些同步任务会依次入栈出栈如下图 同步任务1先入栈执行完之后出栈接着同步任务2入栈依此类推
4.异步任务
异步任务会在同步任务执行之后再去执行那么如果异步任务代码在同步任务代码之前呢在js机制里存在一个队列叫做任务队列专门用来存放异步任务。也就是说当异步任务出现的时候会先将异步任务存放在任务队列中当执行完所有的同步任务之后再去调用任务队列中的异步任务
例如下图现在存在两个同步任务两个异步任务 js会先将同步任务1提至主线程然后发现异步任务1和2则将异步任务1和2依次放入任务队列 然后同步任务1执行完之后出栈又将同步任务2入栈执行 当同步任务2执行完之后再从任务队列中提取异步任务执行 5.总结
js中微任务总是先于宏任务执行也就是说这三种任务的执行顺序是同步任务微任务宏任务
6.案例
scriptconsole.log(1);setTimeout(function(){console.log(2)},0)new Promise((resolve,reject){console.log(3)resolve()console.log(4)}).then((){console.log(5)})console.log(6)
/script 三、 js如何判断一个变量是数组
判断变量的类型是最经常使用的方法但是判断的方式有很多
1.typeof
var ary [1,2,3,4];
console.log(typeof ary); // 输出‘object’
很明显typeof只能检测基本数据类型并不能检测出来是否为数组。
2.instanceof
var ary [1,2,3,4];
console.log(ary instanceof Array); //输出true
看起来挺好使的实际上也确实挺好使的但是要求变量必须在当前页面声明。
3.原型链
var ary [1,2,3,4];
console.log(ary.__proto__.constructorArray); //输出true
console.log(ary.constructorArray) //输出true
两种方法都一样但是在IE中“proto”没有定义。这种方法也存在和“instanceof”一样的问题必须先声明变量。
4.isArray
let a [2,543,32];
console.log(Array.isArray(a));//true
必须先声明变量
5.完美方法
var arr [1,2,3,4];
console.log(Object.prototype.toString.call(arr)) //输出[object Array]
为了使用简便我们可以封装成一个函数。
var ary [1,2,3,4];
function isArray(o){
return Object.prototype.toString.call(o)[object Array];
}
console.log(isArray(ary));
当然这种方法不仅仅可以用来判断是否为数组其他的也同样适用。
console.log(Object.prototype.toString.call(123)) //[object Number]
console.log(Object.prototype.toString.call(123)) //[object String]
console.log(Object.prototype.toString.call(undefined)) //[object Undefined]
console.log(Object.prototype.toString.call(true)) //[object Boolean]
console.log(Object.prototype.toString.call({})) //[object Object]
console.log(Object.prototype.toString.call([])) //[object Array]
console.log(Object.prototype.toString.call(function(){})) //[object Function]
四、 JavaScript数据类型
JavaScript共有八种数据类型分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt
其中 Symbol 和 BigInt 是ES6 中新增的数据类型
Symbol 代表创建后独一无二且不可变的数据类型它主要是为了解决可能出现的全局变量冲突的问题。 BigInt 是一种数字类型的数据它可以表示任意精度格式的整数使用 BigInt 可以安全地存储和操作大整数即使这个数已经超出了 Number 能够表示的安全整数范围。 这些数据可以分为原始数据类型和引用数据类型
栈原始数据类型Undefined、Null、Boolean、Number、String 堆引用数据类型对象、数组和函数
五、 柯里化
1. 什么是函数柯里化
函数柯里化就是我们给一个函数传入一部分参数此时就会返回一个函数来接收剩余的参数。 柯里化是一种函数的转换。是指将一个函数从可调用的 f(a, b, c) 转换为 f(a)(b)(c)
2. 简单的柯里化的实现
没有柯里化的实现 将其转化为柯里化的案例 上述代码可简写为 3.函数柯里化的好处
我们希望处理函数时希望函数功能尽可能单一。如下面代码所示我们希望第一个参数2,第二个参数*2,第三个参数** 2,最后再相加此时我们可以使用函数的柯里化 function makeAdder(count) {return function(num) {return count num}
}
// 在之后使用返回的函数时我们不需要再继续传入count 了
var adder5 makeAdder(5)
adder5(10)
adder5(14)
adder5(1100)
adder5(555) 4.柯里化的优点
柯里化是使函数变得更具体些即作用范围更小
5.传入函数的柯里化执行
function currying(fn, ...rest) {return function(...args) {//...rest3,4//...args1,2return fn(...rest, ...args);}
}
function sum(a, b, c, d) {console.log(a b c d)
}
//传入sum,即currying(fn,...rest)解析成sum,1,2
//add是接收currying返回的函数
const add currying(sum, 1, 2);
//add(3,4)即function(3,4),这个function是sum(3,4),所以add(3,4)就会执行最后那个sum四个数相加的函数
add(3, 4);
// 执行结果
10
function add(a, b, c, d) {console.log(a b c d);
}
const curriedAdd currying(add);
//接收curry()()()()
curriedAdd(1)(2)(3)(4); // 10
curriedAdd(1, 2, 3)(4); // 10
curriedAdd(1, 2, 3, 4); // 10
function currying(fn) {
//一开始curriedAdd传入一个参数1lenadd参数长度4const len fn.length;
//_args[]let _args [];const curry () {
//...args1return function (...args) {
//_args.length0,args.length1,小于len4// 如果参数攒够了就执行if (_args.length args.length len) {const result fn(..._args, ...args);// 执行完重置_args_args [];return result;}// 参数不够就继续攒else {//_args[..._args,...args][1]_args [..._args, ...args];//curriedAdd(1)返回值是一个curry函数以此类推return curry();}}}return curry();
}
六、 如何理解闭包为什么有这种特性为什么需要闭包闭包的缺点
1什么是闭包
闭包就是能够读取其他函数内部变量的函数。
由于在javascript中只有函数内部的子函数才能读取局部变量所以说闭包可以简单理解成“定义在一个函数内部的函数“。
所以在本质上闭包是将函数内部和函数外部连接起来的桥梁。
2如何生成闭包?
函数嵌套 内部函数被引用。
function outer() {var a 1;function inner() {console.log(a);}return inner;
}
//这里的闭包就是返回的inner函数
var b outer();
3闭包作用 可以让内部的函数访问到外部函数的变量避免变量在全局作用域中存在被修改的风险 可以读取函数内部的变量 让这些变量的值始终保持在内存中不会在f1调用后被自动清除
4使用闭包的注意事项
不用的时候解除引用避免不必要的内存占用。
为什么有闭包的这种特性如果形成闭包外部函数执行完后其中的局部变量可能被内部函数使用所以不能销毁因此内部函数能一致访问到这些局部变量直到引用解除。
5闭包的优点 隐藏变量避免放在全局有被篡改的风险。 方便调用上下文的局部变量
6闭包的缺点 使用时候不注意的话容易产生内存泄漏。 由于闭包会使得函数中的变量都被保存在内存中内存消耗很大所以不能滥用闭包否则会造成网页的性能问题在IE中可能导致内存泄露。解决方法是在退出函数之前将不使用的局部变量全部删除