1、基本数据类型: Undefined、Null、Boolean、Number、String、还有在 ES6 中新增的 Symbol 类型。
2、引用数据类型:对象、数组、函数、日期和正则等等
基本类型判断:typeOf
引用类型判断:Object.prototype.toString.call
对象类型判断:instanceof
对象转字符串 JSON.stringify(obj)
字符串转对象或数组 JSON.parse(str)
null,返回 0。
undefined,返回 NaN。
布尔值,true 转换为 1,false 转换为 0。
数值,直接返回。
字符串:只有数字,转成数字;空字符串转0;其他转NaN
1、原型(为对象实例定义一些公共属性和方法的对象模板。)
构造函数原型:每一个构造函数内部都有一个 prototype 属性,这个属性是一个指针,指向另一个对象,这个对象包含了该构造函数的所有实例共享的属性和方法。
对象原型:当我们使用构造函数新建一个对象后,在这个对象的内部将包含一个指针,这个指针指向构造函数的 prototype 属性对应的值,这个指针称为对象的原型。
2、原型链
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念
意外的全局变量(使用了未声明的变量,意外地创建了一个全局变量,而使这个变量一直留在内存中无法被回收
被遗忘的计时器或者回调函数
脱离DOM引用(获取一个dom元素的引用,而后面这个元素被删除,由于我们一直保留了对这个元素的引用,所以它也无法被回收
闭包
闭包:有权访问另一个函数作用域中变量的函数。
创建:在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。
满足条件
访问所在作用域
函数嵌套
在所在作用域外被调用
好处
可以让我们函数外部能够访问到函数内部的变量。
闭包函数保留了使用变量对象的引用,保证变量对象不会被回收。
注意点
过多使用:会导致大量的变量都被保存在内存中,内存消耗很大,造成网页的性能问题,且容易造成内存泄漏。解决方法:退出函数之前,将不使用的局部变量全部删除。
应用场景
构造函数的私有属性
在函数中使用var来创建变量,此时在函数外部就无法获取到这个变量
函数节流、防抖
节流:指在一段时间内只允许函数执行一次。我们可以使用定时器实现节流。
防抖:一个事件回调函数在一段时间后才执行,如果在这段时间内再次调用则重新计时。
const 与 let、var、块级作用域
var是函数作用域,会变量提升。
变量会被提升至作用域的顶端,同时,函数声明也会被提升。当同一作用域内同时出现变量和函数声明提升时,变量仍在函数前面;
let是块级作用域,不会变量提升。
const用于定义常量,是块级作用域,不会变量提升
块级作用域是比函数作用域更小的作用域,例如for循环、i语句的{}
Symbol类型
它表示独一无二的值。最大的用途:定义对象唯一的属性名,保证不会出现同名的属性,还能防止某一个属性被不小心覆盖。
用法:通过Symbol()方法可以生成一个symbol,里面可以带参数或不带参数
注:Symbol 函数前不能使用 new 命令,否则会报错。
箭头函数
ES6 中,箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体;
与普通函数的区别
箭头函数不能使用arguments、super和new.target,可以使用rest参数访问参数列表
箭头函数没有prototype属性,不能用作构造函数
普通函数可以使用call修改this。但箭头函数不能用call、apply修改里面的this
箭头函数的this指向,定义箭头函数的上下文
async/await
async:声明一个function是异步的;而await则可以认为是 async await的简写形式,是等待一个异步方法执行完成的。
基础使用
async 表示这是一个async函数, await只能用在async函数里面,不能单独使用
async 返回的是一个Promise对象,await就是等待这个promise的返回结果后,再继续执行
await 等待的是一个Promise对象,后面必须跟一个Promise对象,但是不必写then(),直接就可以得到返回值
特点
Async作为关键字放在函数前面,普通函数变成了异步函数
返回的是promise成功的对象,
Async函数配合await关键字使用
优点
方便级联调用
同步代码编写方式
Promise使用then函数进行链式调用,是一种从左向右的横向写法;async/await从上到下,顺序执行,就像写同步代码一样,更符合代码编写习惯;
多个参数传递
同步代码和异步代码可以一起编写
基于协程
是对promise的优化
使用场景
需求:执行第一步,将执行第一步的结果返回给第二步使用。例如:在ajax中先拿到一个接口的返回数据,后使用第一部返回的数据执行第二步操作的接口调用,达到异步操作。
首先创建了一个新的空对象
设置原型,将对象的原型设置为函数的 prototype 对象。
让函数的 this 指向这个对象,执行构造函数的代码。
判断函数return的是否为Object,若为Object则返回该object,否则返回创建的新对象
共同点:改变this的指向
区别
call:接受一个上下文对象,参数列表,返回函数执行后的值
apply:接受一个上下文对象,参数数组,返回函数执行后的值
bind:接受一个上下文对象,参数列表,返回新函数
场景:封装防抖函数
指向优先级:箭头函数 > new > call/apply/bind > 对象 > 直接调用
箭头函数的this,指向定义箭头函数的上下文,即指向外层的 this 。
new 对象,this 指向新创建的对象。
call、bind、apply修改this指向,指向这个传入的context上下文,不传指向window
通过obj.某函数调用,this指向Obj
在全局上下文中调用,非严格模式下,this指向windows,严格模式下指向undefined。如果不在全局,被谁调用 this 指向谁。
匿名函数、自动执行函数的this,指向window。
宏任务
1、script整体代码
2、setTimeout、setInterval
3、node环境的setImmediate
4、输入输出和UI render
微任务
1、node环境的process.nextTick
2、Promise的回调函数
3、MutationObserver的回调
4、await后面的代码
执行过程:执行宏任务,执行该宏任务产生的微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。微任务执行时机更早
所有任务都在主线程上执行,形成一个执行栈
主线程发现有异步任务,如果是微任务就把他放到微任务的消息队列里,如果是宏任务就把他放到宏任务的消息队列里
执行栈所有同步任务执行完毕
执行微任务队列,之后再执行宏任务队列
轮询第四步
深拷贝是将一个对象从内存中完整的拷贝一份出来,开辟一个新的内存空间存放新对象,且修改新对象不会影响原对象。
实现深拷贝:如果是对象,创建结果数组,遍历对象,对当前值进行递归拷贝。
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
实现浅拷贝:Object.assign(),可以把源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
Set.prototype.keys():返回键名的遍历器
Set.prototype.values():返回键值的遍历器
Set.prototype.entries():返回键值对的遍历器
Set.prototype.forEach((item,key)=>{}):使用回调函数遍历每个成员
foreach:只用来遍历数组,不改变其数据
map:只用来遍历数组并改变数据,返回新数组
entries() 返回数组的可迭代对象。
every() 检测数值元素的每个元素是否都符合条件。
fill() 使用一个固定值来填充数组。
filter() 检测数值元素,并返回符合条件所有元素的数组。
find() 返回通过测试(函数内判断)的数组的第一个元素的值。
findIndex() 返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
forEach() 数组每个元素都执行一次回调函数。
from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组。
类数组对象想转真正数组的条件
该类数组对象必须具有 length 属性,用于指定数组的长度。如果没有 length 属性,那么转换后的数组是一个空数组。
该类数组对象的属性名必须为数值型或字符串型的数字
indexOf() 搜索元素在数组的位置,从前往后查找,返回它所在的位置,没找到返回-1。接收两个参数:查找元素、开始查找位置。
lastIndexOf() 搜索元素在数组的位置,从后往前找,返回它所在的位置,没找到返回-1。接收两个参数:查找元素、开始查找位置。
join() 把数组的所有元素放入一个字符串。
map() 通过指定函数处理数组的每个元素,并返回处理后的数组。
pop() 删除数组的最后一个元素并返回删除的元素。
push() 向数组的末尾添加一个或更多元素,并返回新的长度。
reduce() 接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
some() 检测数组元素中是否有元素符合指定条件。
splice(index,deletenum,additem1,additem2…) 从数组中添加或删除元素。
slice(start,[end]) 选取数组的一部分,并返回一个新数组。
shift() 删除并返回数组的第一个元素。
unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
for循环可以使用break跳出循环,但forEach不能。
for循环可以控制循环起点(i初始化的数字决定循环的起点),forEach只能默认从索引0开始
for循环过程中支持修改索引(修改 i),但forEach做不到(底层控制index自增,无法左右它
捕获阶段
事件会从最外层开始发生,直到最具体的元素。
目标阶段
冒泡阶段
事件会从最内层的元素开始发生,一直向上传播,直到document对象。
事件代理是将事件监听函数加到父元素上,利用事件冒泡来处理多个子元素相同事件的方式。因为在事件冒泡中,子元素的事件触发会冒泡到父元素中,触发父元素相同的事件。所以我们只需给父元素添加事件监听即可。
应用场景:当要给一组子元素添加相同事件时,可以直接添加给父元素。
阻止冒泡
给子级加 event.stopPropagation( )
在事件处理函数中返回 false
阻止默认事件
event.preventDefault( )
return false
JS是单线程,浏览器是多线程,js通常在浏览器中运行;如:定时器、事件监听都交给WebAPI处理,有结果后将回调函数放入任务队列等待js去取。
DOM是文档对象模型,BOM是浏览器对象模型。
DOM是将页面抽象成了节点,节点组成DOM树。
BOM提供的API,用于支持访问和操作浏览器的窗口。
垃圾回收程序会定期找出不再继续使用的变量,然后释放其内存。
标记清除
垃圾回收程序运行时,会标记内存中存储的所有变量。然后,它将在上下文中的所有变量,以及被在上下文中的所有变量引用 的变量的标记去掉。故仍有标记的变量便是待删除变量,随后垃圾回收程序做一次内存清理,销毁带标记的变量并收回它们的内存。
引用计数
引用计数是指每个值被引用的次数。将一个引用类型A值赋给已声明变量时,则A值的引用次数就是1。如果A值又被赋给另一个变量,则A值的引用次数加1。相反,如果引用A值的变量取得了另外一个B值,则A值的引用次数减1。当A值的引用次数变成0时,则无法再访问A值,因而可以将其占用的内存空间回收。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。(例:Vuex中的Store、 Mobx的Store
策略模式:不同的参数命中不同策略
代理模式:为一个对象提供一个占位符,方便控制,(场景:图片预加载,先通过一张loading图占位,然后通过异步的方式加载图片,等图片onload加载好后,再把完成的图片加载到img标签里面。
观察者模式:定义对象间一对多的依赖关系,一个对象维持一系列依赖于它的Observer对象,当状态发生变更时,通知一系列 Observer 对象进行更新。
发布-订阅模式是指:发布对象通过发布主题事件通知订阅该主题的对象。订阅对象通过自定义事件订阅多个主题
代码压缩:css、js代码代码压缩
推迟非关键资源的加载:异步加载的三种方式——async和defer、动态脚本创建
利用浏览器缓存,减少服务器压力。
使用CDN
图片优化:懒加载、预加载。
针对一些行为进行节流和防抖,防止频繁向服务器发请求。
减少回流和重绘。
路由懒加载
低耦合,提高复用能力。要考虑更加通用的场景,而不是满足特定的开发需求。
比如,数据不要写死,通过参数化配置传入;或者发送请求的API通过参数传入等。
统一的状态管理。可以把组件中特定功能的逻辑和数据抽离出来,用一个Store进行管理。
State或Props不要嵌套太深,3层以内。
使用封装组件的组件无感知,所有逻辑处理都在组件内。使用的组件不需要特殊处理。
web scoket通信,服务器作为中间介,进行消息转发。
使用localStorage进行通信。一个页面修改数据,另一个页面监听localStorage变化,拿到最新数据。
ajax:实现客户端与服务器端的异步通信效果,实现页面的局部刷新
如何创建
创建XMLHttpRequest对象,也就是创建一个异步调用对象
创建一个新的HTTP请求,并指定该请求的方法、URL及验证信息
设置响应HTTP请求状态变化的函数
发送HTTP请求
获取异步调用返回的数据
使用JS和DOM实现局部刷新
为什么需要跨域:浏览器对js实施的安全限制
解决
jsonp:利用动态创建script标签请求(只能是get请求)后端接口地址(例如link、img、iframe、script),然后传递callback参数,后端接手callback,经过处理,返回callback函数调用的形式,callback中的参数就是json
proxy代理:通过vueCli的config中的index文件来配置,有个proxyTable来配置跨域
正向代理
用户发送请求到自己的代理服务器
自己的代理服务器发送请求到服务器
服务器将数据返回到自己的代理服务器
自己的代理服务器再将数据返回给用户
反向代理
用户发送请求到服务器(访问的其实是反向代理服务器,但用户不知道)
反向代理服务器发送请求到真正的服务器
真正的服务器将数据返回给反向代理服务器
反向代理服务器再将数据返回给用户
CORS(跨域资源共享):后台工程师设置后端代码来实现前端跨域请求
ready:表示文档结构已经加载完成(不包含图片等非文字媒体文件
只要标签加载完成,不用等该图片加载完成,就可以设置图片的属性或样式等。
在原生JavaScript中没有Dom ready的直接方法。
onload:指示页面包含图片等文件在内的所有元素都加载完成
DOM load在加载图片等非文字媒体文件之后,表示在document文档加载完成后才可以对DOM进行操作,document文档包括了加载图片等非文字媒体文件。
例如,需要等该图片加载完成,才可以设置图片的属性或样式等。
在原生JavaScript中使用onload事件。
文档加载的顺序:域名解析-->加载HTML-->加载JavaScript和CSS-->加载图片等非文字媒体文件。
setTimeout() :在指定的毫秒数后调用函数或计算表达式,只执行一次。
setInterval() :按照指定的周期(以毫秒计)来调用函数或计算表达式。方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。
在DOM元素上绑定onclick、onmouseover、onmouseout、onmousedown、onmouseup、ondblclick、onkeydown、onkeypress、onkeyup等。
在 JS 代码中(即 script 标签内)绑定事件可以使 JS 代码与HTML标签分离,文档结构清晰,便于管理和开发。document.getElementById("btn").onclick = function(){
alert("hello world!");
}
绑定事件方法2
用 addEventListener() 或 attachEvent() 来绑定事件监听函数。
XSS(跨站脚本攻击)攻击
原理:攻击者会在web页面中插入一些恶意的script代码
防范
设置httpOnly,防止窃取cookie
输入检查--不要相信用户的所有输入
输出检查--存的时候转义或者编码
CSRF(跨站点请求伪造)攻击
理解:攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,故完成了攻击者的操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。
防范
验证码
Referer Check
添加token验证
es5
原型继承:将父类的实例作为子类的原型
构造函数继承:将父类构造函数的内容复制给了子类的构造函数。这是所有继承中唯一一个不涉及到prototype的继承。
组合继承:既可以调用父类实例的属性又能调用父类原型的属性
原型式继承:原型式继承的object方法本质上是对参数对象的一个浅复制。
寄生式继承:使用原型式继承获得一个目标对象的浅复制,然后增强这个浅复制的能力。
es6
class继承:在子类中,调用extends方法,可以调用父类的属性,用eat调用父类的方法
location.href
location.replace
sIice、splice都是对于数组对象进行截取,slice、splice第一个参教都是截取开始位置,但slice第二个参数是截取的结束位置(不包含),而splice第二个参数(表示这个从开始位置截取的长度).slice不会对原数组产生变化.而splice会直接剔除原数组中的截取数据
该模式下,不能使用隐式声明,或为只读属性赋值,或向不可扩展的对象添加属性
可以通过在文件,程序或函数的开头添加“use strict”来启用严格模式
使用JSON.stringify()将对象转换为json字符串;
JSON.stringify(obj) === '{}'
使用for...in循环遍历对象除Symbol以外的所有可枚举属性,当对象有属性存在返回false, 否则返回 true
Object.getOwnPropertyNames() 方法会返回该对象所有可枚举和不可枚举属性的属性名(不含Symbol 属性)组成的数组。然后再通过判断返回的数组长度是否为零,如果为零的话就是空对象。
Object.getOwnPropertyNames(obj).length === 0
Object.keys() 是 ES5 新增的一个对象方法,该方法返回一个数组,包含指定对象自有的可枚举属性(不含继承的和Symbol属性)。用此方法只需要判断返回的数组长度是否为零,如果为零的话就是空对象。
for...in
基本语法是 for( 变量 in 对象 ){ 循环体程序 }
Object.keys( 对象 )返回一个数组 是 当前对象 所有键名组成的数组
Object.value( 对象 )
返回一个数组 是 当前对象 所有键值组成的数组
`for in` 用于遍历对象的键(`key`),`for in`会遍历所有 自身的和原型链上的可枚举属性。如果是数组,for in会将数组的索引(index)当做对象的key来遍历,其他的object也是一样的。
`for of`是`es6`引入的语法,用于遍历所有迭代器iterator,其中包括`HTMLCollection`,`NodeList`,`Array`,`Map`,`Set`,`String`,`TypedArray`,`arguments`等对象的值(`item`)。
懒加载
懒加载(延迟加载):延迟加载网络资源或符合某些条件时才加载资源。常见的就是图片延时加载。
意义:懒加载主要目的是为服务器前端优化,减少请求数或延迟请求数。
实现方式
第一种是纯粹的延迟加载,使用setTimeOut或setInterval进行加载延迟.
第二种是条件加载,符合某些条件,或触发了某些事件才开始异步下载。
第三种是可视区加载:加载用户可看到的区域,这个主要由监控滚动条来实现,一般会在距用户看到某图片前一定距离遍开始加载,这样能保证用户拉下时正好能看到图片。
懒加载对服务器前端有一定的缓解压力作用
预加载
提前加载图片,当用户需要查看时可直接从本地缓存中渲染。
预加载则会增加服务器前端压力。预加载应用如广告弹窗等
token通常放在本地存储中。token的存在只关心请求的安全性,而不关心token本身的安全,因为token是服务器端生成的,可以理解为一种加密技术。但如果存在cookie内的话,浏览器的请求默认会自动在请求头中携带cookie,所以容易受到csrf攻击。
编译环境不一样,sass是服务器端处理的,可以用Ruby、node-sass来编译;less需要引入less.js来处理输出,也可以使用工具在服务器端处理成css。
变量定义符不一样,less用的是@,而sass用$。
sass支持分支语句,less不支持
强制缓存
当客户端第二次向服务器请求相同的资源时,不会向服务器发送请求,而是直接从内存/硬盘中间读取。缓存由服务器的响应头里 cache-control 和 expires 两个字段决定
协商缓存
当客户端第二次向服务器请求相同的资源时,先向服务器发送请求"询问"该请求的文件缓存在本地与服务器相比是否更改,如果更改,则更新文件,如果没有就从内存/硬盘中读取。协商缓存由 last-modified 和 etag两个字段决定
作用域:在代码执行过程中,形成一个独立的空间,让空间内的变量不会邪泄露在空间外,也让独立空间内的变量函数在独立空间内运行,而不会影响到外部的环境。
作用域分为全局作用域和局部作用域;理解:本来有一个巨大的空间,空间内定义的函数内部,就形成了一个独立的小空间,全局作用域是最大的作用域。
作用域链:当独立空间内的数据不能满足需求时,可以从外部获取数据的,独立空间之间可以有层级关系,外部的空间不可以从内部的空间获取数据,但内部的空间可以。当子级空间在父级空间中获取数据时,父级空间没有的话,父级空间也会到他的父级空间中查找数据,直到找到最大的作用域-全局,如果全局也没有就报错。这样形成的链式结构叫作用域链
给一个变量赋值时,要先在自己作用域中查找变量的定义,如果没有就在上一级作用域中查找,直到全局,如果全局作用域中也没有这个变量的定义,就在全局定义这个变量并赋值。
计算机内部存储数据使用2进制存储,两个数字进行的数学运算,首先是将这两个数字以2进制形式,存储在计算机内部,然后在计算机内部使用两个2进制数字进行计算,最后将计算结果的2进制数字转为10进制展示出来。
由于10进制的小数在转2进制的时候,规则是小数部分乘以2,判断是否得到一个整数,如果得到整数,转换完成;如果没有得到整数,则继续乘以2判断。所以,0.1和0.2在转换2进制的时候,其实是一个无限死循环,也就是一直乘以2没有得到整数的时候,但计算机内部对于无线死循环的数据,会根据一个标准保留52位。也就是说,计算机内部在存储0.1和0.2的时候,本来就不精准,两个不精准的小数在计算后,距离精准的结果是有一定误差的。
解决
将小数乘以10的倍数,转为整数,然后计算,计算完成后,再缩小10的倍数
使用数字的toFixed方法,强制保留小数点后多少位
自定义数字运算方法,当需要进行数学运算的时候,不直接进行,调用自定义的方法进行
思想:将不同功能的代码封装在不同的文件中, 再互相引用时不会发生命名冲突的一种思想, 大多数情况下, 一个文件就是一个模块
CommonJS:每个文件就是一个模块,拥有自己的作用域,文件中的变量、函数都是私有的,与其他文件相隔离;模块导出:module.exports=数据,模块导入:require('模块文件路径')
ES6的模块化:
主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
AMD
特点: 提倡依赖前置,在定义模块的时候就要声明其依赖的模块:导入模块require([module],callback);定义模块:define('模块名称', 函数)。
CMD
提倡就近依赖(按需加载),在用到某个模块的时候再去require。定义模块:define(function (require, exports, module) {}),使用模块:seajs.use()
基本语法是 document.cookie = ‘键名=键值';expires=时间对象;path=路径’ ;
时效 如果不设定 默认是 seeion 会话时效
路径 如果不设定 默认是 当前文件所在文件夹
常见属性
键名 cookie键值对的键名
键值 cookie键值对的键值
expires cookie的时效 分为 session会话时效 时间时效 时间时效是服务器时间也就是世界标准时间
path 路径 符合路径的文件才能访问cookie
httponly 设置 为 true 了之后可以防止js程序访问 防止 xss攻击 增加cookie的安全性
secure 设置 为 true 了之后cookie只能通过https协议发送 http协议是不能发送的 这样也是为了增加cookie的安全性