水平有限,如有错误,敬请指正。
Javascript篇
1. 数据类型
* 基本数据类型(Number,Boolean,String,null,undefined,symbol(ES6新增),BigInt)
* 引用类型 (Object,Array,Function)
2. 基本数据类型和引用数据类型的区别
* let声明的变量只在let命令的块级作用域内有效。
* let命令不存在变量提升,var会发生变量提升
* let声明变量会存在暂时性死区,即变量会绑定某个区域不受外部影响。
* let命令不允许重复定义,但是var可以,重复定义之后后面的值回覆盖前面的值。
* const声明常量,赋值后不可改变,一旦声明必须初始化。
* const也只在声明的块级作用域内有效。变量声明不会提升。
* const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动
3. let,var和const的区别
* let声明的变量只在let命令的块级作用域内有效。
* let命令不存在变量提升,var会发生变量提升
* let声明变量会存在暂时性死区,即变量会绑定某个区域不受外部影响。
* let命令不允许重复定义,但是var可以,重复定义之后后面的值回覆盖前面的值。
* const声明常量,赋值后不可改变,一旦声明必须初始化。
* const也只在声明的块级作用域内有效。变量声明不会提升。
* const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动
4. Null和undefined区别
* Null代表空值,代表一个空对象指针;undefined表明变量声明了却未被初始化
* 用typeof判断时,typeof(undefined)能够得到undefined类型,但typeof(null)为object
* 转换时数值不一样,Number(undefined)为NaN,Number(null)为0
* Null一般用于释放内存空间/原型链顶端,当函数没有返回值时,返回undefined
5. 如何判断一个变量是不是数组。
* typeof() //判断基本数据类型。但是null判断为object
* Array.isArray() //返回true说明是数组。
* xxx instanceof Array //返回true说明是数组,可判断复杂数据类型
* Object.prototype.toString.call() //返回[object Array]字符串,说明是数组
6. 数组方法
* join() 数组转字符串,默认为逗号分隔符,原数组不变。
* push() 向数组末尾添加一个或多个元素,并返回新的长度。
* pop() 用于删除并返回数组的最后一个元素。
* shift() 用于把数组的第一个元素删除,并返回第一个元素的值。
* unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
* sort() 排序,但是是按照字符编码顺序进行排序的,所以需要实现一个排序函数。
。 升序return a-b;
。 逆序return b-a.
* concat() 用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。没有传
参的情况下,复制当前数组并返回。
* slice(start,end) 数组截取 ,返回一个新数组,(包含)start到end(不包括)的元素。
* splice(index,howmany,index1….indexX) 数组更新,用于向数组中添加/删除项目,
然后返回被删除的项目(会改变原始数组)
* indexOf(item,start),从前向后查找,没有返回-1。
* lastIndexOf(item,start)从数组末尾向前查找。
7. Object构造函数的方法
* object.assign() 复制一个或多个对象来创建新对象。
* Object.create() 使用指定的原型对象和属性创建一个新对象。
* Object.defineProperty(object , propName , descriptor) 给对象添加一个属性并指定该属性的配置。
- object 对象 => 给谁加
- propName 属性名 => 要加的属性的名字 [类型:String]
- descriptor 属性描述 => 加的这个属性有什么样的特性[类型:Object]
* Object.defineProperties() 给对象添加多个属性并分别指定他们的配置。
* Object.entries() 返回给定对象自身的可枚举属性的[key,value]数组。
* Object.freeze() 冻结对象:其它代码不能删除或更改任何属性。
* Object.is() 比较两个值是否相同NaN相等。
* Object.isExtensible() 判断对象是否可扩展。
* Object.isFrozen() 判断对象是否已经被冻结。
* Object.isSealed() 判断对象是否已经密封。
* Object.keys() 返回一个包含所有给定对象自身可枚举属性名称的数组。
* Object.values() 返回给定对象自身可枚举值的数组。
8. js字符串方法
* Slice(start,end),字符串的截取。
* Substr(start,length),字符串的截取。
* Substring(start,end) ---以两个参数中较小的一个作为起始位置,较大的一个作为结束位置。
* Split(字符串/正则,length) 字符串转数组。
* CharAt(position)返回指定位置上的字符,如果position<0或大于length,返回空字符串。
* Concat(string) 连接两个或多个字符串,可以直接用+。
* IndexOf(searchString,position)。返回某个指定的字符串值在字符串中首次出现的位置。
* lastIndexOf(searchString,position)。可返回一个指定的字符串值最后出现的位置
* localeCompare(target) 比较字符串,返回比较结果数字。大于target返回正数,小于返回负数,相等返回0。
* match(regexp) 让字符串和一个正则进行匹配。
* replace(searchValue,replaceValue) 对字符串进行查找和替换,并返回一个新字符串。
9. for...of,for...in,forEach和map的区别
// for ... of ... 接收数组,具有(iterable)迭代器
// for(item of str) {
// console.log(item)
// }
// for ... in 循环数组时 循环的索引, 循环对象时, 循环的是key
// 速度最慢
// for(item in str) {
// console.log(item)
// }
// forEach 循环遍历数组
// arr.forEach(function(item, index, ar) {
// console.log("item" + item);
// console.log("index" + index)
// console.log(ar)
// })
// map 只循环数组,不会对空数组进行检测,不会改变原数组
// var m = arr.map(function(item, index, ar) {
// return item === "a" ? "dddd" : item;
// })
// console.log(m);
10. JS中的原型链的理解
* 原型:js中每个对象都有一个与它关联的对象,叫做原型对象。
* 构造函数:用new来调用,就是为了创建一个自定义类
* 原型链:js查找属性得过程中,在自有的属性中找不到就去原型对象中查找,原型对象中找不到,就去原型对象得原型中查找,
一层一层向上查找的机制,叫做原型链。
function Person() {
}
var person = new Person();
console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
11. 闭包
* 内部变量访问外部变量的函数。
function foo(){
var a = 2;
function bar(){
console.log(a)
}
return bar()
}
var baz = foo()
baz() //2 这就是闭包的效果
* 优点:可以隔离作用域,不造成全局污染。
* 缺点:由于闭包长期驻留内存,则长期这样会导致内存泄露。
* 如何解决内存泄漏: 将暴露全外部的闭包变量置为null。
* 作用:
。解决循环变量泄漏为全局变量的问题
。ES6模块化之前防止变量冲突,通过闭包定义变量方法
。只能暴露一个接口去访问,私有化属性
。可以做累加器,函数内部return到外部 // 闭包实现一个count函数,每次调用+1
。实现柯里化。
. 将函数内部和函数外部连接起来
. 防止函数内部变量执行完成后被垃圾机制回收,使其一直保存在内存中
12. this的指向
* 在全局作用域内,this指向window
* 在函数中
。 箭头函数,this指向包裹箭头函数的第一个普通函数
。 普通函数,如果是直接调用则指向window,如果被obj调用则指向obj,如果通过new的方式创建实例,
则指向创建出来的实例化对象
。 使用call、apply、bind,this指向参数中创建的类实例
。 立即执行函数的话,this指向window
13. new的过程
* 创建一个新的空对象
* 新对象的__proto__指向构造函数的prototype
* 新对象赋值给构造函数内部的this上下文,并执行构造函数
* 如果构造函数没有显示返回对象,默认返回this
14. call、bind、apply、的区别
* call apply会立即执行,bind不会立即执行,因为她返回的是一个函数。
* 参数不同,apply的参数是数组,call和bind有多个参数。
//手写call
Function.prototype.myCall = function(context,...args){
if(!context && context === null){
context = window
}
let fn = Symbol()
context[fn] = this //此时this指向foo
console.log(' context[fn]: ', context[fn]);
return context[fn](...args)
}
let obj = {
a:1
}
function foo(){
console.log(this)
}
foo.myCall(obj,[1,2,3,4])
//手写apply
Function.prototype.myCall = function(context,args){
if(!context && context === null){
context = window
}
let fn = Symbol()
context[fn] = this //此时this指向foo
console.log(' context[fn]: ', context[fn]);
return context[fn](...args)
}
let obj = {
a:1
}
function foo(){
console.log(this)
}
foo.myCall(obj,[1,2,3,4])
15. 事件循环机制
a.JS是单线程,防止代码阻塞,我们把代码 (任务) :同步和异步
b.同步代码给is引擎执行,异步代码交给宿主环境(浏览器或者node)
c.同步代码放入执行栈中,异步代码等待时机成熟送入任务队列排队
d.执行栈执行完毕,会去任务队列看是否有异步任务,有就送到执行栈执行,
反复循环查看执行,这个过程是事件循环(eventloop)
* 同步代码执行完,才会执行事件循环,事件循环包括宏任务和微任务。执行宏任务的前提是清空所有微任务
* 三部分:主线程、宏队列(macrotask)、微队列(microtask)
* 主线程:scripts标签里包含的内容
* 宏队列:setTimeout、setInterval、setImmediate、I/O、UI rendering
* 微队列:promise.then(promise本身是同步,promise.then和promise。catch是
异步)、process.nextTick,async/await(await后面的的代码)
* Event loop 顺序
。执行同步代码,这属于宏任务
。执行栈为空,查询是否有微任务需要执行
。执行所有微任务
。必要的话渲染 UI
。然后开始下一轮 Event loop,执行宏任务中的异步代码
16. 事件委托和事件代理
* 原因:添加到页面的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断与DOM进行交互,
容易引起重绘重排,事件委托可以减少操作dom的次数。
* 原理:利用冒泡思想。把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职责。
17. promise
(总结不够全面,建议参考
* 异步编程的一种解决方案。
* promise的api
promise.then()成功时的回调
promise.catch()失败时的回调
promise.finally()无论promise处于什么状态都会执行
* 优点
。一旦状态(pending,resolved,rejected)改变,就不会再变。
。可以将异步的操作以同步的流程表达出来,避免回调地域。
* 缺点
。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。
。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
。最后,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
* promise.all 和 promise.race的区别
。promise.all //并发处理多个异步任务,所有任务都执行完成才能得到结果。
。promise.race // 并发处理多个异步任务,只有有一个完成就能得到相应结果。
。promise.allSettled //所有promise的参数数组发生变更(成功或失败),返回的promise对象才会变更。
。promise.any //只要参数实例有一个变成fulfilled 状态,包装实例就会fulfilled 状态,如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态。
18. 深拷贝和浅拷贝
* 浅拷贝:假设B复制了A,当A修改时,B也变了。
* 深拷贝:(基本数据类型基本都是深拷贝),深拷贝的对象与原来的对象是完全隔离的,一个对象的修改不会影响另外一个对象。
* 实现浅拷贝的方式
。 ...结构
。 object.assgin()
* 实现深拷贝的几种方式:
。json.parse(json.stringfy())
。Object.create() //实现的是深拷贝通过原型链的方式
* 函数库 lodash,提供 cloneDeep 实现
* 1.下载相关库**
* npm i --save lodash**
* 2.在相关文件中引入**
* import _ from "lodash"**
* 3.调用 _.cloneDeep() 方法实现深拷贝**
<script>
import _ from "lodash"
var objects = [{ 'a': 3 }, { 'b': 4 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]); 输出false
</script>
function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}
console.log('source.constructor: ', source.constructor);
for(let keys in source){
//判断是否有当前属性 keys = 基本数据类型,{},[]
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof(source[keys] === 'Object') ){
//递归
targetObj[keys] = deepClone(source[keys])
}else {
targetObj[keys] = source[keys]
}
}
}
return targetObj
}
let obj = {a:1}
let newObj = deepClone(obj)
console.log(obj.a === newObj.a) //false
19. cookie、sessionStorage和localStorage的区别
* cookie的弊端
。数量和长度的限制
。安全性问题,如果cookie被拦截,就可以获取所有session信息
。有些状态不能一直保存在客户端,(为了防止表单重复提交,需在服务端加计数器)
20.js显示类型和隐式类型的转换
显示:
Number():Number(null):0;Number(undefined):NaN
parseInt(value, radix):
parseFloat(value):
隐式:
算术运算符:加(+)、减(-)、乘(*)、除(/)、取模(%);
逻辑运算符:逻辑与(&&)、逻辑或(||)、逻辑非(!);
字符串运算符:+、+=。
'=='隐式转换
21.防抖和节流
函数防抖:
单位时间内,频繁触发一个事件,以最后一次触发为准。 防抖的实现: 1.声明一个全局变量存储定时器ID。 2.每一次触发交互的时候,先清除上一次的定时器,然后开启本次定时器。
//输入框事件
let timeID = null
document.querySelector('input').oninput = function () {
//1先清除之前的定时器
clearTimeout(timeID)
//2.开启本次定时器
timeID = setTimeout(() => {
console.log(`发送ajax,搜索的内容是${this.value}`)
}, 500)
}
函数节流
单位时间内,频繁触发一个事件,只会触发一次。 使用场景: ajax请求数据;图片懒加载 节流的实现
//声明一个全局变量存储触发时间
let lastTime = null
//页面滚动事件
window.onscroll = function () {
//1.每一次触发 先获取本次时间戳
let currentTime = Date.now()
//2.判断当前时间 与 上次触发时间 是否超过间隔
if (currentTime - lastTime >= 500) {
console.log(document.documentElement.scrollTop)//获取滚动距离
//3.存储本次的触发时间
lastTime = currentTime
}
}
22.async和await
* Async/await作用是用同步方式,执行异步操作。
* Await只能在async函数中使用,不然会报错
* Async函数返回的是一个状态为fulfilled的promise对象,有无值取决于有无return值。(没有则undefined),如果函数内部抛出异常或是返回reject,都会使函数的promise状态变为失败reject(只要不是异常,都不会走catch,哪怕是return false NaN undefined。内部含有未声明变量/函数,函数方法执行出错另当别论)。
* Await后面只有接promise才能实现排队操作。
23.数组去重的方法
.new Set()实现数组去重
.利用数组的indexof方法。新建一个空数组,遍历需要去重的数组,将数组元素存入新数组中,存放前判断数组中是否已经含有当前元素,没有则存入。此方法也无法对NaN
去重。
function removeDuplicate(arr) {
const newArr = []
arr.forEach(item => {
if (newArr.indexOf(item) === -1) {
newArr.push(item)
}
})
return newArr // 返回一个新数组
}
const result = removeDuplicate(arr)
console.log(result) // [ 1, 2, 'abc', true, false, undefined, NaN, NaN ]
利用双层循环加数组的splice方法。通过两层循环对数组元素进行逐一比较,然后通过splice方法来删除重复的元素。此方法对NaN是无法进行去重的
function removeDuplicate(arr) {
let len = arr.length
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1)
len-- // 减少循环次数提高性能
j-- // 保证j的值自加后不变
}
}
}
return arr
}
const result = removeDuplicate(arr)
console.log(result) // [ 1, 2, 'abc', true, false, undefined, NaN, NaN ]
使用ES6的Set结构
// 原始数组
const arr = [1, 9, 8, 8, 7, 2, 5, 3, 3, 3, 2, 3, 1, 4, 5, 444, 55, 22];
// 定义去重函数
function removeDuplicatesWithSet(arr) {
// 创建一个Set,自动去除重复元素
const uniqueSet = new Set(arr);
// 使用扩展运算符将Set转换为数组
const uniqueArray = [...uniqueSet];
return uniqueArray;
}
// 调用函数并打印结果
const result = removeDuplicatesWithSet(arr);
console.log(result);
使用filter()
方法
filter()
方法会创建一个新数组,其结果是通过提供的函数实现数组中的每个元素的筛选。
const arr = ['apple', 'apps', 'pear', 'apple', 'orange', 'apps'];
function removeDuplicatesWithFilter(arr) {
// 使用filter方法,只有当元素的索引和元素首次出现的位置相同时,才保留该元素
return arr.filter((item, index) => arr.indexOf(item) === index);
}
const result = removeDuplicatesWithFilter(arr);
console.log(result);
使用for
循环和indexOf()
这种方法遍历数组,使用indexOf()
检查元素是否已经存在于结果数组中。
const arr = [1, 9, 8, 8, 7, 2, 5, 3, 3, 3, 2, 3, 1, 4, 5, 444, 55, 22];
function removeDuplicatesWithFor(arr) {
const uniqueArray = []; // 初始化一个空数组用于存放唯一元素
for (let i = 0; i < arr.length; i++) {
// 如果元素尚未在uniqueArray中出现,则添加之
if (uniqueArray.indexOf(arr[i]) === -1) {
uniqueArray.push(arr[i]);
}
}
return uniqueArray;
}
const result = removeDuplicatesWithFor(arr);
console.log(result);
双重for
循环去重
尽管这种方法可以工作,但它效率低下,不推荐使用,尤其是对于大型数组。
const arr = [1, 9, 8, 8, 7, 2, 5, 3, 3, 3, 2, 3, 1, 4, 5, 444, 55, 22];
function removeDuplicatesWithDoubleFor(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
// 当找到重复元素时,从数组中移除它
if (arr[i] === arr[j]) {
arr.splice(j, 1);
j--; // 由于splice改变了数组长度,所以需要减一以保持正确的索引
}
}
}
return arr;
}
const result = removeDuplicatesWithDoubleFor(arr);
console.log(result);
使用indexOf()
与新数组
这种方法检查元素在原始数组中的首次出现位置,如果该位置与当前索引匹配,则添加到新数组中。
const arr = [1, 9, 8, 8, 7, 2, 5, 3, 3, 3, 2, 3, 1, 4, 5, 444, 55, 22];
function removeDuplicatesWithIndexOf(arr) {
const uniqueArray = [];
for (let i = 0; i < arr.length; i++) {
// 只有当元素首次出现时才添加到uniqueArray中
if (arr.indexOf(arr[i]) === i) {
uniqueArray.push(arr[i]);
}
}
return uniqueArray;
}
const result = removeDuplicatesWithIndexOf(arr);
console.log(result);
使用includes()
方法
includes()
方法检查数组中是否存在指定的值,如果存在则返回true
,否则返回false
。
const arr = [1, 9, 8, 8, 7, 2, 5, 3, 3, 3, 2, 3, 1, 4, 5, 444, 55, 22];
function removeDuplicatesWithIncludes(arr) {
const uniqueArray = [];
for (let i = 0; i < arr.length; i++) {
// 如果uniqueArray中不包含当前元素,则添加之
if (!uniqueArray.includes(arr[i])) {
uniqueArray.push(arr[i]);
}
}
return uniqueArray;
}
const result = removeDuplicatesWithIncludes(arr);
console.log(result);
使用reduce()
方法
reduce()
方法对数组中的每个元素执行一个由您提供的reducer
函数,将其结果汇总为单个返回值。
const arr = [1, 9, 8, 8, 7, 2, 5, 3, 3, 3, 2, 3, 1, 4, 5, 444, 55, 22];
function removeDuplicatesWithReduce(arr) {
// reducer函数,检查acc(累加器)中是否已经包含当前元素,如果没有,则添加
return arr.reduce((acc, curr) => {
if (!acc.includes(curr)) {
acc.push(curr);
}
return acc;
}, []);
}
const result = removeDuplicatesWithReduce(arr);
console.log(result);
Set
或filter()
方法是最佳选择,因为它们既简洁又高效。
24.获取当前时间_js 获取年份
//前端js获取当前时间的方法:
var time = new Date();
time.getYear(); //获取当前年份
time.getFullYear(); //获取完整的年份(4位,1970-???)
time.getMonth(); //获取当前月份(0-11,0代表1月)
time.getDate(); //获取当前日(1-31)
time.getDay(); //获取当前星期X(0-6,0代表星期天)
time.getTime(); //获取当前时间(从1970.1.1开始的毫秒数)
time.getHours(); //获取当前小时数(0-23)
time.getMinutes(); //获取当前分钟数(0-59)
time.getSeconds(); //获取当前秒数(0-59)
time.getMilliseconds(); //获取当前毫秒数(0-999)
time.toLocaleDateString(); //获取当前日期
var mytime=time.toLocaleTimeString(); //获取当前时间
time.toLocaleString( ); //获取日期与时间
不定期更新
本站代码模板仅供学习交流使用请勿商业运营,严禁从事违法,侵权等任何非法活动,否则后果自负!
WX234.CN
暂无评论内容