前端1-JavaScript

88 阅读13分钟
  • 一、JavaScript\

    • ✔1.1 数据类型 (9种)\

      • 基本数据类型(栈):Number,String,Boolean,null,undefined,symbol(创建唯一值),bigint(比Number数据类型支持的范围更大的整数值)(后两个为ES6新增)\
      • 引用数据类型(堆):object,function\
    • ✔var、let、const\

      • let 和 const 的优点?\

        • let 和 const 有了块级作用域,变量声明不会提升相比于 var\
      • var、let、const的区别\

        • var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。\
        • let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。(有变量提升,但不赋值)\
        • const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。(除非是数组或对象才能修改)\
    • ✔1.2 普通函数、匿名函数、箭头函数\

      • 普通函数:function main(){}\
      • 匿名函数:function(){}\
      • 箭头函数:()=>{}(一种特殊的匿名函数)\
      • 箭头函数与普通函数的区别\

        • 箭头函数不能用new来创建构造函数的实例,箭头函数没有构造能力\

          • 箭头函数创建的时候不会为这个箭头函数创建[[Construct]]方法\
          • 箭头函数是匿名的,用完就扔了\
          • 箭头函数内部不会自动生成prototype属性\
          • 箭头函数内部没有生成arguments对象\
          • 箭头函数不能通过call,apple和bind来改变this的值(可以调用这些方法但this的值不受控制)\
        • this的指向\

          • this在普通函数里是动态的,谁调用就指向谁\
          • 箭头函数的this值取决于外部普通函数里的this值\
      • 函数内部有一个特殊的对象:arguments(是一个对象object,是类数组)\

        • 获取函数的参数使用\
        • 给函数传参时,可以像数组一样调用数组的元素或者属性\
      • 总结:\

        • 普通函数:\

          • 有new和原型\
          • 有arguments,super,new.target\
          • this指向是动态的\
          • call,apply和bind能修改this的值\
        • 箭头函数:\

          • 没有new和原型\
          • 没有arguments,super,new.target,只能调用外围的\
          • this指向是被普通函数包含的上一层this\
          • call,apply和bind不可修改this的值\
    • ✔函数柯里化\

      • 柯里化技术主要体现在函数里面返回函数\
      • 使用柯里化技术的函数可以很好的进行复用,大大减少代码量\
      • 柯里化可以进行兼容性的检测\

        • 常见的是判断事件监听addEventListener(主流浏览器的方法)和attachEvent(IE的方法)\
      • 柯里化还有一个很重要的作用是延迟执行,对参数复用功能进行改进\

        • ***参数复用案例:\

          • const curring = name => element => element[name]\
          • const name_profession = curring('profession')\
          • console.log(nameList1.map(name_profession));\
          • console.log(nameList2.map(name_profession));\
          • 注释:\

            • nameList1.map( name => element => element[name ] )\

              • 转化nameList1.map( 'profession'=> element => element['profession'] )\

                • 转化nameList1.map( 'profession'=> { nameList1=> nameList1['profession'] } )\
    • ✔new操作符具体干了什么呢\

      • (1) 创建一个空对象 son {}\
      • (2) 为 son 准备原型链连接son.proto = Father.prototype\
      • (3) 重新绑定this,使构造函数的this指向新对象Father.call(this)\
      • (4) 为新对象属性赋值son.name\
      • (5) 返回this return this,此时的新对象就拥有了构造函数的方法和属性了\
    • ✔1.3 call, apply(数组), bind\

      • call,apply和bind的作用都是改变this的指向\
      • call方法(this指向,...)\

        • steven.charge.call(becky, 95)\
        • call可以传递多个形参\
      • apply方法(this指向,数组[])\

        • steven.charge2.apply(becky, [30, 40])\
        • apply只能传递一个数组形参(接收的参数类型是数组)\
      • bind方法(this指向)\

        • const beckyCharge = steven.charge.bind(becky)\
        • bind不会被立即调用,而是返回一个函数对象,用变量保存,稍后再用(开发中常用)\
      • 为了进行this的硬绑定\
      • 手写call,apply,bind\
    • ✔1.4 eventloop, 宏任务和微任务\

      • eventloop概念:\

        • 检查当前调用栈为空的时候,从消息队列头部弹出一个回调放入调用栈执行\
      • 在执行过程中遇到微任务和宏任务,分别添加到微队列和宏队列中去\
      • 面试题输出判断:同步任务先执行 → 微任务执行 → 宏任务执行 → 宏任务产生的微任务执行...\
    • ✔1.5 ***闭包 (概念, 用途, 手写)\

      • 概念:\

        • 闭包:一个函数和它的周围状态的引用捆绑在一起的组合(返回值为函数的函数)\
        • 闭包就是通过某种方式获取函数内部的变量,然后暴露到函数外部,并在将来的某个节点还可以继续操作这个变量\
        • 闭包 是指内部函数总是可以访问其所在的外部函数中声明的变量和参数,即使其外部函数被return(结束生命周期)之后\
        • 闭包就是嵌套函数,内部函数引用外部函数值就能形成闭包,闭包可以延长函数的生命周期\
        • 闭包会产生一种幽灵变量,感觉不到变量但变量确实存在着\
        • 总结:闭包函数内部的参数在外部不能访问\
      • 用途:\

        • 闭包可以延长函数的生命周期\
        • 优点:可以防止污染全局作用域\
        • 常用场景:settimeout\
      • 缺点:\

        • 可能会导致内存泄漏的问题(低版本IE中)\
      • 手写闭包\
    • ✔1.7 继承 (extends继承, 原型链继承, 构造函数继承, 组合继承, 寄生组合继承)\

      • extends关键字作用:类继承\

        • 语法:class 子类函数 extends 父类函数\
        • 底层:替换原型继承(替换的是原型的原型,不会覆盖自身原型Child.prototype.proto = Parent.prototype)\
      • 原型链继承实现了共享\
      • 构造函数继承不能实现共享\
      • 组合继承既可以实现共享,又可以解决原型链继承的一些问题\
    • ✔原型链\

      • 概述:\

        • 如果const stu1=new Student('张三')\
        • 则Student.prototype === stu1.proto\
      • 每个函数function都有一个prototype,即显式原型(属性)\

        • 在定义函数时自动添加的, 默认值是一个空Object对象\
      • 每个实例对象都有一个__proto__,可称为隐式原型(属性)\

        • 创建对象时自动添加的, 默认值为构造函数的prototype属性值\
      • 为什么会有原型链?\

        • 1.为了实现继承,简化代码,实现代码重用\
        • 2.只要是这个链条上的内容,都可以被访问和使用到\
      • 原型链是怎么体现的?\
    • ✔1.8深拷贝和浅拷贝(数组里的concat方法、slice方法、Array.from方法、展开运算符)\

      • 深拷贝:对复制的数组操作不会影响原数据\
      • 浅拷贝:对复制的数组操作会影响原数据\
      • 实现浅拷贝的方法:const listCope = Object.assign({}, list),展开运算符\
      • 属于浅拷贝【对于原始值是深拷贝,对于引用值是浅拷贝(对于数组是深拷贝,对于对象是浅拷贝)】\

        • concat方法\

          • const listCope = [].concat(xxx)\
          • 会创建一个拷贝当前数组的副本,然后把参数添加到副本末尾\
          • 如果不添加参数,就相当于直接拷贝副本,返回新构建的数组\
          • 对复制的数组操作不会影响原数组\
        • slice方法(与concat方法对应)\

          • const listCope = list.slice()\
          • 如果不传入参数,返回一个新的数组,并包含所有元素\
          • 进行元素的添加不会影响原数组\
        • Array.from方法\

          • const listCope = Array.from(list)\
          • 进行元素的添加不会影响原数组,实现了拷贝\
        • 展开运算符\

          • const listCope = [...list]\
      • 实现深拷贝\

        • 使用JSON的方法:\

          • const listCope = JSON.parse(JSON.stringify(list))\
          • 先使用JSON.stringify方法,把JS对象变成JSON字符串\
          • 在使用JSON.parse方法,把JSON字符串生成为JS对象\
        • 数组还有其他方法,map,filter,reduce会造成浅拷贝,可以用JSON解决\
    • ✔1.9 ***Promise\

      • Promise对象可以将异步操作以同步的流程表达出来\
      • 为什么要用promise(好处)\

        • 支持链式调用, 可以解决回调地狱问题\
        • 指定回调函数的方式更加灵活\
        • 语法非常简洁/Promise 对象提供了简洁的API,使得异步操作更加容易\
      • 关键问题\

        • 如何修改对象的状态\
        • 能否执行多个回调\
        • 改变状态与指定回调的顺序问题\
        • then方法返回结果由什么决定\
        • 串联多个任务\
        • 异常穿透\
        • 如何中断promise链\
      • promise的方法\

        • Promise.all()\
        • Promise.race()\
        • Promise.allSettled()\
        • Promise.any()\
      • 手写promise的all方法、race方法\
      • promise状态 PromiseState(pending 未决定的、resolved 成功、rejected 失败)\
    • ✔async异步 与 await等待 与 defer推迟\

      • 构造函数时,使用async和await实现异步任务\
      • script标签的defer和async的区别\

        • 遇到script标签,就会停下来先执行script标签的内容,如果有外部文件,就必须等外部文件下载执行\
        • async适合第三方脚本\
        • defer适合于DOM有关联的脚本\
    • ✔Ajax请求过程\

      • AJAX是异步 JS 和 XML\
      • Ajax可以使网页实现异步更新。在不重新加载整个网页的情况下,对网页的某部分进行更新\
      • (1)创建 XMLHttpRequest 对象,也就是创建一个异步调用对象;(1.创建对象)\
      • (2)创建一个新的 HTTP 请求,并指定该 HTTP 请求的方法、 URL 以及验证信息;(2.初始化)\
      • (3)设置响应 HTTP 请求状态变化的函数;\
      • (4)发送 HTTP 请求;(3.发送)\
      • (5)获取异步调用返回的数据;(4.处理响应结果)\
      • (6)使用 JavaScript 和 DOM 实现局部刷新。\
      • 手写Ajax\
    • ✔Axios工具库\

      • 基于 Promise 操作方式的一个AJAX的封装的包\
    • ✔AMD、CMD、CommonJs、ES6的对比\

      • 他们都是用于在模块化定义中使用的,AMD、CMD、CommonJs是ES5中提供的模块化编程的方案,import/export是ES6中定义新增的\
    • ✔require,import和import()函数的区别\

      • require是运行时加载模块,只有运行时才知道,同步动态加载\
      • import命令会被 JavaScript 引擎静态编译,先于模块内的其他模块执行(叫做”连接“更合适)。\
      • import()函数,完成动态加载,返回值是一个Promise类型的对象。异步动态加载\
      • 不同之处:\

        • 1.遵循的规范不同(import是es6的)\
        • 2.调用时间不同(require运行时,import编译时)\
        • 3.本质(require是赋值拷贝,import是解构引用)\
    • ✔forEach方法和map方法\

      • 共同点:\

        • 1.都只能循环数组,都循环数组的每一项\
        • 2.每次循环的匿名函数都有三个参数(item当前项,index索引,input原始数组)\
        • 3.匿名函数中的this都指向window\
      • 区别:\

        • forEach没有返回值,map有返回值\
        • forEach改变原数组,map原数组不变\
        • forEach无法跳出循环(return),map返回新数组(当数组中元素是基本类型,map不会改变原数组;当是引用类型object/function,则可以改变原数组)\
      • 用途:\

        • forEach方法:不改变数据,只是用数据做事情,它return出来接收到是undefined\
        • map方法:你需要返回新数组,可以正常return\
    • ✔数组内置的方法\

      • 1.push()从后面添加元素\
      • 2.pop()从后面删除元素\
      • 3.shift()从前面删除元素\
      • 4.unshift()从前面添加元素\
      • 5.【splice(i索引,n个数)】删除从i索引开始的之后的n个数据\
      • 6.【arr1.concat(arr2)】连接两个数组,返回新数组\
      • 7.【str.split()】把字符串转化为数组\
      • 8.【forEach(callback)】遍历,无return\
      • 9.【map(callback)】映射,有return返回新数组\
      • 10.【indexOf()】查找某个元素的索引\
      • 11.【find(callback)】找到第一个符合条件的数组成员\
      • 【reverse()】反转数组\
      • 【reduce()】累加器,返回的是一个单值,该单值是由每一项计算出来的\
      • 【sort()】按照Unicode编码排序\

        • 当数组中的元素为字符串时(arr1.sort())\
        • 将数组中的数字按照从小到大排序,会导致[1,11,2,3,4]\

          • 升序arr1.sort((a, b) => a - b)\
          • 降序arr1.sort((a, b) => b - a)\
    • ✔ES6新增\

      • 概述:let/const、模板字符串、箭头函数、解构赋值{}、展开运算符...、字符串方法、proxy、Promise、Async和Await、Class、ES Modules\
      • ***Proxy(代理:对象级别的拦截)\

        • 通过Vue2 和 Vue3 对比\

          • ES5中有一个 Object.defineProperty ,可以监视属性的读写过程,Vue2 就是通过这个实现数据双向绑定\
          • ES6提供了 Proxy,可以监视对象的读写过程,Vue3.0 通过 Proxy 实现数据绑定\
          • Vue2的响应式核心是通过defineProperty写的,Vue3的响应式核心是通过Proxy来写的(性能提升)\
        • Proxy 对比 Object.defineProperty(属性级别的拦截)\

          • Proxy 能监视更多对象操作:delete\
          • 使用Object.defineProperty定义getter和setter方法(需要循环进行监听的绑定)\
          • ***Proxy当中不仅能使用get/set方法,也能使用apply方法,可以操作数组(例如封装负数组索引)\
        • Proxy 能解决的问题\

          • 在原有函数上进行修改是很危险的操作,可能破环代码\
          • 1.通过Proxy代理可以在不修改原有函数的情况下,实现附加功能\
          • 2.可以使用Proxy代理实现负数组索引(array[-5]从后往前5位)\
        • 缺点:兼容性差\
        • 优点:性能比defineProperty高很多\
      • for-of循环(解决for-in的缺陷)\

        • for (const item of arr) { console.log(item); }\

          • for-of 是新的遍历方法,规避了for-in循环缺陷,也可以正确响应 break、continue 和 return 语句\
          • for-of 循环不仅支持数组,字符串遍历,还支持大多数类数组对\
          • 实现Iterable结构就是for...of的前提\
        • for (const item in arr) { console.log(item); }\

          • 遍历对象的属性\
        • 两者差别:\

          • for in遍历的是数组的索引(键名),而for of遍历的是数组的值(键值)\
          • 所以for in更适合遍历对象,不适合for in数组\
      • Set、Map\

        • Set\

          • Set是一系列无序、没有重复值的数据集合(类似没有重复成员的数组)\
          • 重复元素会被忽略\
          • Set的属性和方法\

            • size:获取元素数量\
            • add(value):添加元素,返回 Set 实例本身\
            • delete(value):删除元素,返回一个布尔值,表示删除是否成功\
            • has(value):返回一个布尔值,表示该值是否是 Set 实例的元素\
            • clear():清除所有元素,没有返回值\
        • Map\

          • Map的属性和方法\

            • size:获取成员的数量\
            • set:设置成员 key 和 value\
            • get:获取成员属性值\
            • has:判断成员是否存在\
            • delete:删除成员\
            • clear:清空所有\
      • Reflect\

        • Reflect属于静态类(如 Math ),不能 new,只能调用静态方法:Reflect.get()\
        • Reflect 成员方法就是 Proxy 处理对象的默认实现\
      • 展开运算符(...)\

        • console.log(...arr); // foo bar baz\
        • console.log([...arr]); // 浅拷贝 ['foo', 'bar', 'baz']\
        • console.log({ ...arr }); // {0: 'foo', 1: 'bar', 2: 'baz'}\
      • 字符串方法\

        • includes()返回布尔值,表示是否找到了参数字符串\
        • startsWith()返回布尔值,表示参数字符串是否在原字符串的头部\
        • endsWith()返回布尔值,表示参数字符串是否在原字符串的尾部\
      • Promise\
      • Async、Await\
      • Class\

        • 新的语法形式class Name {...}\
      • ES Modules\

        • import { fn1, fn2 } from './util2.js'\
      • Symbol\

        • 主要作用就是为对象添加独一无二的属性名\
      • BigInt\

        • 新的基础数据类型,表示大的整数(早期JS不能正确表示过大的数字)\
    • ✔this\

      • 构造函数内部this指向构造函数本身,可以直接this拿\
      • 绑定规则:默认绑定、隐式绑定、硬绑定、构造函数绑定\
      • this的指向\

        • this在普通函数里是动态的,谁调用就指向谁\
        • 箭头函数的this值取决于外部普通函数里的this值\
    • ✔防抖和节流\

      • 防抖:一直触发事件不会执行,停止触发一段时间后执行\
      • 节流:判断触发的事件是否在时间间隔内,如果在就不触发事件,否则触发\
      • 总结:\

        • 两者本质上都是控制事件执行的频率,但是触发事件的时机本质上有区别\
        • 防抖是在用户多次触发事件,当用户停止触发事件,将事件执行一次\
        • 节流是用户多次触发事件,会在多次触发的过程中,间隔执行事件\
      • 手写防抖和节流\