Javascript基础
1. 原始数据类型、内置对象
原始类型存储的是值,对象类型存储的是地址(指针)
(1)原始类型包含:boolean、null、undefined、number、string、symbol
(2)对象类型:Object、数组、函数
(3)理解typeof 和 instanceof
- typeof:是判断参数是什么类型的实例,返回值为说明运算数类型的字符串。
- 返回值结果:“number”、“string”、“boolean”、“object”、“function”、“undefined”
- 若参数为引用类型,始终返回“object”,对于Array、null始终返回“object”,所以用typeof来判断参数类型有很大的局限性。
- instanceof:用来判断一个对象在其原型链中是否存在一个构造函数的prototype属性
- a instanceof b:判断a是否为b的实例,可以用于继承关系中
- b是c的父对象,a是c的实例,a instanceof b 与 a instanceof c 结果均为true
2. 类型转换
在 JS 中类型转换只有三种情况,分别是:
-
转换为布尔值:Boolean() 除了以下6个转化为false,剩下都是true
- undefined
- null
- -0
- +0
- NaN
- ‘’(空字符串)
-
转换为数字:Number()
-
转换为字符串
- String() :该方法可用于任何类型的数字,字母,变量,表达式
- toString()
-
加法运算符不同于其他几个运算符,它有以下几个特点:
- 运算中其中一方为字符串,那么就会把另一方也转换为字符串
- 如果一方不是字符串或者数字,那么会将它转换为数字或者字符串
3. this
- 默认绑定
- 适用于没有明确的调用对象,this指向全局对象,即window对象
- 严格模式下为 (undefined)
- 隐式绑定
- 通过对象调用方法,this指向此对象
- 显式绑定
- 使用apply和call函数
- 使用bind 函数
- new 绑定
- 箭头函数
4. 错误处理
- Error 对象
- 常见 Error 类型
-
EvalError:eval函数没有被正确执行时,会抛出EvalError错误
-
InternalError:示出现在JavaScript引擎内部的错误,是当它有太多数据要处理并且堆栈增长超过其关键限制时
- “too many switch cases”(过多case子句)
- “too many parentheses in regular expression”(正则表达式中括号过多);
- “array initializer too large”(数组初始化器过大);
- “too much recursion”(递归过深)。
-
SyntaxError:语法错误
- 例子:var 123
-
TypeError:类型错误,在作用域中找到了但是做了不是自己该做的事情
- 例子:var fn1; fn1();
-
URIError: URI相关函数的参数不正确时抛出的错,主要涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()这六个函数。
- 例子:decodeURI('%2')
-
ReferenceError: 引用错误 ,在作用域中找不到,引用了不存在的变量而发生了错误。
-
范围错误:范围错误,超出有效范围时发生的错误
- 例子:[].length = -20;
-
- 异常和错误区别:错误对象只有在抛出时才会变成异常
- 使用 try / catch / finally
- 使用 Promise 处理异常: .then / .catch / .finally
5. 理解 == 和 ===
===严格相等,会比较两个值的类型和值==抽象相等,比较时,会先进行类型转换,然后再比较值
6. 闭包
- 闭包的定义其实很简单:函数 A 内部有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包。
7. 正则表达式
正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式,一般用于文本搜索和文本替换。
(1)正则表达式相关方法: test、exec、match
- test:方法用于正则表达式模式在字符串中运行查找,如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null
- exec:用于检索字符串中的正则表达式的匹配。
返回值是一个数组,但是此数组的内容和正则对象是否是全局匹配有着很大关系
- 没有g修饰符: 此函数的作用和match()函数是一样的,只能够在字符串中匹配一次,如果没有找到匹配的字符串,那么返回null,否则将返回一个数组,数组的第0个元素存储的是匹配字符串
- 具有g修饰符 : 此函数返回值同样是一个数组,并且也只能够在字符串中匹配一次。不过此时,此函数一般会和lastIndex属性匹配使用,此函数会在lastIndex属性指定的字符处开始检索字符串,当exec()找到与表达式相匹配的字符串时,在匹配后,它将lastIndex 属性设置为匹配字符串的最后一个字符的下一个位置。可以通过反复调用exec()函数遍历字符串中的所有匹配,当exec()函数再也找不到匹配的文本时,它将返回null,并把lastIndex 属性重置为0。
- match : 检索字符串 stringObject,以找到一个或多个与 regexp 匹配的文本。
(2)常用的标志(flags)或修饰符(modifiers)
- g: 全局搜索,当成功匹配后不会直接返回。
- i: 不区分大小写搜索。
(3)常见正则表达式书写
8. 深浅拷贝(所谓拷贝,就是赋值)
(1)浅拷贝
-
定义:加了一个指针指向已存在的内存地址
-
方法 :
- 1. 手写浅拷贝
function shallowCopy(obj) { if (typeof obj === 'object' && obj != null) { let copy = Array.isArray(obj) ? [] : {}; for (var p in obj) { copy[p] = obj[p]; } return copy; } else { return obj; } }- 2.对象 Object.assign() Object.assign(target, ...sources) 来实现浅拷贝,第一个参数 target是目标对象,后面的参数...sources是原对象 注: Object.assign() 一般用于对象的浅拷贝,用来处理数组时,会把数组视为对象。
// Object.assign 把数组视为属性名为 0、1、2 的对象 // 源数组的 0 号属性 7 覆盖了目标数组的 0 号属性1,以此类推 Object.assign([1,2,3], [7,8]); // [7,8,3] Object.assign([1,2], [6,7,8]); // [6,7,8]- 3. 数组 Array.concat()
- 4. 扩展运算符{...obj}
(2)深拷贝
-
定义:是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存
-
方法
- 1. 浅拷贝+递归
//递归浅拷贝 function recursiveShallowCopy (obj){ var copy = Array.isArray(obj) ? [] : {}; for(let p in obj){ if(typeof obj[p] ==='object'){ copy[p] = recursiveShallowCopy(obj[p]) }else{ copy[p] = obj[p]; } } return copy; } //深拷贝 function deepCopy(obj) { if (typeof obj === 'object' && obj != null) { return recursiveShallowCopy(obj); } else { return obj; } }- 2. JSON.parse(JSON.stringify())
先通过**JSON.stringify()把原对象序列化成一个 JSON 字符串,再通过JSON.parse()**生成一个新对象。
缺陷:
1.如果原对象中有undefined、Symbol、函数时,会导致该键值被丢失
2.如果原对象中有正则,会被转换为空对象{}
3.如果原对象中有Date,会被转换成字符串
4.会抛弃原对象的constructor,都会被转换成Object
5.如果对象中存在循环引用的情况,无法正确处理
注:使用JSON.parse(JSON.stringify()实现深拷贝的前 4 个缺陷,可以通过递归+浅拷贝的深拷贝方式解决,但递归+浅拷贝不能解决第 5 点循环引用的问题
9. 原型、原型链
10. var、let、const 区别
- ES5只有 var,ES6 引入了let 和 const,在开发中应该避免使用 var
- var 允许变量提升,可以在申明前使用,let 和 const 不允许
- var 允许重复申明,let 和const不允许
- var、let不需要初始值,const需要初始值
- let和const支持块级作用域,var不支持
11. 继承
- class 的本质还是函数,只是语法糖
- 原型如何实现继承
- Class 如何实现继承
参考: juejin.cn/post/684490… juejin.cn/post/684490…
12. map, filter, reduce 用法
- map 作用是生成一个新数组,遍历原数组,将每个元素拿出来做一些变换然后放入到新的数组中
- filter 的作用也是生成一个新数组,在遍历数组的时候将返回值为 true 的元素放入新数组
- reduce 可以将数组中的元素通过回调函数最终转换为一个值
14. 异步编程
(1) 回调函数 Callback
例如
function step1(cb) {
console.log("step1");
cb()
}
function step2(){
console.log("step2");
}
step1(step2); // step1 step2
(2) Generator
(3) Promise
理解三种状态 Pending、Resolved、Rejected 理解和使用 then / catch / finally 使用async / await
15. 定时器函数
setTimeout setInterval requestAnimationFrame
16. EventLoop
宏任务 / 微任务概念 而宏任务一般是:包括整体代码script,setTimeout,setInterval、setImmediate。 微任务:原生Promise(有些实现的promise将then方法放到了宏任务中) 4. 前端安全 XSS XSS 简单点来说,就是攻击者想尽一切办法将可以执行的代码注入到网页中 防御方法 用于不要新人用户的输入。最普遍的做法就是转义输入输出的内容,对于引号、尖括号、斜杠进行转义 CSP,本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行
CSRF CSRF 中文名为跨站请求伪造。原理就是攻击者构造出一个后端请求地址,诱导用户点击或者通过某些途径自动发起请求。如果用户是在登录状态下的话,后端就以为是用户在操作,从而进行相应的逻辑。防范 CSRF 攻击可以遵循以下几种规则: Get 请求不对数据进行修改 不让第三方网站访问到用户 Cookie 阻止第三方网站请求接口 请求时附带验证信息,比如验证码或者 Token 中间人攻击 中间人攻击是攻击方同时与服务端和客户端建立起了连接,并让对方认为连接是安全的,但是实际上整个通信过程都被攻击者控制了。攻击者不仅能获得双方的通信信息,还能修改通信信息。如何防御: 不建议使用公共的 Wi-Fi 使用HTTPS 来防御中间人攻击
- 兼容性 移动端兼容性问题 移动端点击延时300ms的问题 移动端 300ms 延时的由来(支持双击缩放,需要延时300ms来检测是点击还是双击) 使用fastclick库,原理: 在touchend之后生成一个click事件,并立即触发这个click,再取消原本的click事件 通过禁用缩放(缺点:无法使用缩放效果) 设置viewport默认宽度为device-width(浏览器认为该网站做过移动端适配,所以无需双击缩放) 移动设备浏览器上常用的内核: iPhone 和 iPad 等苹果 iOS 平台主要是 WebKit Android 4.4 之前的 Android 系统浏览器内核是 WebKit Android 4.4 系统浏览器切换到了Chromium,内核是 Webkit 的分支 Blink IE 兼容性问题 polifill 是指通过一段代码来实现浏览器暂未提供的一些特性,以下常用API在IE都不支持,需要做 Polyfill: Promise Fetch API Object.assign Array.from ... React 15起,官方停止React Dom对IE8 的支持 最新版本的React可以通过官方的polyfill支持IE9、IE10、IE11