前端知识点总结js篇

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
图片[1]-前端知识点总结js篇-智码星河
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,执行宏任务中的异步代码
图片[2]-前端知识点总结js篇-智码星河
图片[3]-前端知识点总结js篇-智码星河
16. 事件委托和事件代理
* 原因:添加到页面的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断与DOM进行交互,
       容易引起重绘重排,事件委托可以减少操作dom的次数。
* 原理:利用冒泡思想。把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职责。
17. promise

(总结不够全面,建议参考https://es6.ruanyifeng.com/#docs/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的区别
图片[4]-前端知识点总结js篇-智码星河
* 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);

每种方法都有其适用场景和性能特点,选择最适合的方法取决于具体的项目需求和环境。通常,使用ES6的Setfilter()方法是最佳选择,因为它们既简洁又高效。

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( ); //获取日期与时间

本站代码模板仅供学习交流使用请勿商业运营,严禁从事违法,侵权等任何非法活动,否则后果自负!
文章版权声明 1 本网站名称: 智码星河
2 本站永久网址:https://wx234.cn
© 版权声明 文章版权归作者所有,未经允许请勿转载。

WX234.CN
喜欢就支持一下吧
点赞8赞赏 分享打赏
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

夸夸
夸夸
还有吗!没看够!
取消
昵称表情代码图片

    暂无评论内容