周亚博的个人博客

  • 首页
  • 盛夏光年
  • 陪风去荡
  • 布响丸啦
我频繁记录着 因为生活值得
  1. 首页
  2. 盛夏光年
  3. 正文

js面试笔记(一)

2022-09-09 74点热度 0人点赞 0条评论

延迟加载js的方式

1、 通常都会将js文件的引入放到body的最后,
2、 通过async | defer可以实现延迟加载
【一般情况下js的下载和执行会暂停html的解析, 执行完毕后再继续解析html】
两种延迟加载的区别:
- async: 解析html的同时下载js, 两者同步进行, 只有执行时才暂停html解析
- defer: 解析html的同时下载js, 但是js的执行则是放到了html解析完毕之后
- defer是顺次执行, 与代码顺序有关
- async执行的顺序不一定, 先下载完先执行, js文件存在依赖关系不建议使用

js的数据类型

- 基本类型: string number booan undefined null symbol bigint
- 引用类型: object
// 隐式转换
console.log(true+1) //2
console.log(true+'name') // truename
console.log(undefined+1) // NaN(数值类型),但不是一个具体的数字
console.log(typeof null) // object
console.log(typeof undefined) // undefined

null和undefined的区别

为什么会出现undefined:
- 作者认为null是一个object类型, 认为表示'无'最好不是对象
- null会被隐式转换为0, 数据类型不匹配时, 不容易发现错误
相同点:
- 都可表示'无'
不同点: 
- null是一个表示'无'的对象, 是一个空对象指针, 转换为数值为0, 需要null关键字声明
- undefined是一个表示'无'的原始值, 转换为数值为NaN, 变量定义未赋值就是undefined

js作用域

- 除了函数外, js是没有块级作用域的
- 作用域链实现内部可以访问外部的变量(内部优先), 但是外部仍然不能访问内部变量
- 声明变量是否使用了var, 如果直接使用b=1, 这是全局变量, 函数外部仍可以访问
【优先级: 声明变量 > 声明普通函数 > 传递参数 > 变量提升】

js数组去重

function noRepeat(arr) {
    if (arr.length < 2) {
        return arr;
    }
    let newArr = [arr[0]];
    // 遍历原数组的每个元素和新数组每个元素比较
    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < newArr.length; j++) {
            if (arr[i] === newArr[j]) {
                break;
            }
            // 循环完毕都没有重复的
            if (j === newArr.length - 1) {
                newArr.push(arr[i]);
            }
        }
    }
    return newArr;
}
let newArr = [...new Set(arr)]

new操作符做了什么

- 创建了一个空的对象
- 将空对象的原型指向构造函数的原型
- 改变this指向
- 对构造函数有返回值的处理判断
    如果返回值是基本数据类型, 就会创建一个新的实例对象
    如果返回值是一个引用数据类型, 就会返回构造函数的返回值

闭包

function fun() {
  let count = 1;
  return function () {
    count++;
    console.log(count);
  };
}
let fun2 = fun();       fun执行的结果才是一个闭包
fun2(); // 2
fun2(); // 3
闭包实际上是一个函数,声明在另一个函数内部,对外部函数的局部变量存在引用作用: 实现局部变量的共享和长久保存,同时不会造成全局污染
概括: 内层函数操作外层函数的局部变量,外层函数将内层函数返回
【闭包能持久储存变量的原因是: 外层函数作用域对象没有被释放】
- 闭包的优点是延长变量的生命周期 | 创建私有环境
- 闭包的缺点是容易造成内存泄露

原型链

原型:原型可以共享属性和方法
- 函数拥有prototype,对象拥有__prototype__
查找顺序:
- 对象本身查找 —— 构造函数中查找 —— 对象的原型 —— 构造函数的原型 —— Object的原型中 ——null
原型链:
- 原型链就是将原型串联起来的结构
- 原型链的顶端是null

js继承的方式

// ES6的class继承
class Parent {
    constructor() {
        this.age = 18
    }
}
class Child extends Parent {
    constructor() {
        super()
        this.name = '张三'
    }
}
let child = new Child()
console.log(child) // Child {age: 18, name: '张三'}
// 原型链继承
function Parent() {
    this.age = 20
}

function Child() {
    this.name = '张三'
}
Child.prototype = new Parent()
let child = new Child()
console.log(child.name, child.age)
// 构造函数继承
function Parent() {
    this.age = 20
}

function Child() {
    this.name = '张三'
    Parent.call(this)
}
let child = new Child()
console.log(child)

call/apply/bind

共同点: 可以改变this指向, 改变函数体内的this指向
方法: 函数.call()   函数.apply()      函数.bind()
区别: 
- call的参数是依次传递到括号中
- apply则是将所有参数放到数组中作为第二个参数
- bind不会立即执行, 返回值是一个函数, 需要手动调用

深拷贝和浅拷贝

- 浅拷贝: 只是复制引用, 而没有复制真正的值
    let obj2 = Object.assign(obj1)
    let arr1 = arr2
- 深拷贝: 拷贝真正的值, 两者的改变不会相互影响
    let obj2 = JSON.parse(JSON.stringify(obj1)), 不能拷贝方法
    解构赋值只能实现一维的深拷贝
function deepClone(source) {
  // 判断是数组还是对象,
  const targetObj = source.constructor === Array ? [] : {}
  // 判断属性是否存在
  for (let keys in source) {
    if (source.hasOwnProperty(keys)) {
      if (source[keys] && typeof source[keys] === 'object') {
        // 引用数据类型(数组|对象)
        targetObj[keys] = source.constructor === Array ? [] : {}
        // 递归调用
        targetObj[keys] = deepClone(source[keys])
      } else {
        // 基本数据类型,直接赋值
        targetObj[keys] = source[keys]
      }
    }
  }
  return targetObj
}

统计字出现的次数

let str = 'aaaabbbvvvaabbvvc'
// 最终的返回值是一个对象,包含字符和数量
function count(srt) {
    let obj = {}
    for (let i = 0; i < str.length; i++) {
        if (obj[str[i]]) {
            obj[str[i]] += 1
        } else {
            obj[str[i]] = 1
        }
    }
    return obj
}
console.log(count(str))

统计出现最多的次数

function getMax(obj) {
    let max = 0
    let name = ''
    for (let key in obj) {
        if (obj[key] > max) {
            max = obj[key]
            name = key
        }
        return { [name]: max }
    }
}
console.log(getMax(count(str)))

解析字符串

let url = 'https://zhouyaker.cn/index.php/?key1=1&key2=2&key3=3'
// 最终返回结果为一个对象,是参数的键和值
function parseQueryString(url) {
    let obj = {}
    let urlArr = url.split('?')
    let paramsArr = urlArr[1].split('&')
    for (var i = 0; i < paramsArr.length; i++) {
        let paramsItem = paramsArr[i].split('=')
        obj[paramsItem[0]] = paramsItem[1]
    }
    return obj
}
console.log(parseQueryString(url))
标签: js 面试
最后更新:2022-09-24

粥呀Bo

所谓惊喜,就是苦苦等候的兔子来了,后面却跟着狼

点赞
< 上一篇
下一篇 >

文章评论

取消回复

COPYRIGHT © 2022 zhouyaker.cn. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

陕ICP备2022009272号