javascript 基础汇总

javascript 汇总

Javascript 由三部分组成

  • ECMAScript 语法
  • DOM 页面文档对象模型
  • BOM 浏览器对象模型

继承, 继承可以使得子类别具有父类的的各种方法和属性(六种)

  • 原型类继承
//  每个构造函数都有一个原型对象,原型都有一个原型对象,原型对象又包含一个指向构造函数的指针,而实例则包含一个原型对象的指针
function Parent(){
  this.name = 'parent'
  this.play = [1,2,3]
}

function Child(){
  this.type = 'child'
}

Child.prototype = new Parent()

var c1 = new Child()
var c2 = new Child()
c1.play.push(4)
// c1 、 c2 实例使用的是同一个原型对象,内存空间是共享的
console.log(c1.play,c2.play) // [1,2,3,4] [1,2,3,4]
  • 构造函数继承(借助call)
// 构造函数继承
// 只能继承父类的实例属性和方法,不能继承原型属性或者方法
function Parent(){
  this.name = 'parent'
}

Parent.prototype.getName = function(){
  return this.name
}

function Child(){
  Parent.call(this)
  this.type = 'child'
}

let child = new Child()
console.log(child) // 没问题
console.log(child.getName()) // 会报错
  • 组合继承
// Parent 执行了两次,造成了多构造一次的性能开销
function Parent(){
  this.name = 'parent'
  this.play = [1,2,3]
}

Parent.prototype.getName = function(){
  return this.name
}

function Child(){
  Parent.call(this)
  this.type = 'child'
}

// 第一次调用 Parent()
Child.prototype = new Parent()
// 手动挂上构造器,指向自己的构造函数
Child.prototype.constructor = Child

var c1 = new Child()
var c2 = new Child()

c1.play.push(4)
console.log(c1.play,c2.play) // 互不影响
console.log(c1.getName())  // parent
console.log(c2.getName()) // parent
  • 原型式继承
// Object.create 方法是浅拷贝
let parent = {
  name: 'parent',
  friends: ['p1','p2','p3'],
  getName: function(){
    return this.name
  }
}

let child1 = Object.create(parent)
child1.name = 'zhangsan'
child1.friends.push('lisi')

let child2 = Object.create(parent)
child2.friends.push('wangwu')

console.log(child1.name) // zhangsan
console.log(child1.name === child1.getName()) // true
console.log(child2.name) // parent
console.log(child1.friends) // [ 'p1', 'p2', 'p3', 'lisi', 'wangwu' ]
console.log(child2.friends) // [ 'p1', 'p2', 'p3', 'lisi', 'wangwu' ]
  • 寄生式继承
// Object.create 方法是浅拷贝
let parent = {
  name: 'parent',
  friends: ['p1','p2','p3'],
  getName: function(){
    return this.name
  }
}

function clone(obj){
  let clone = Object.create(obj)
  clone.getFriends = function(){
    return this.friends
  } 
  return clone
}

let child = clone(parent)

console.log(child.getName()) // parent
console.log(child.getFriends()) // [ 'p1', 'p2', 'p3' ]
  • 寄生组合方式继承
// 最优
function clone(parent,child){
  child.prototype = Object.create(parent.prototype)
  child.prototype.constructor = child
}
function Parent(){
  this.name = 'parent'
  this.play = [1,2,3]
}
Parent.prototype.getName = function(){
  return this.name
}
function Child(){
  Parent.call(this)
  this.friends = 'child'
}

clone(Parent,Child)
Child.prototype.getFriends = function(){
  return this.friends
}

let c1 = new Child()
console.log(c1) // Child { name: 'parent', play: [ 1, 2, 3 ], friends: 'child' }
console.log(c1.getName()) // parent
console.log(c1.getFriends()) // child

闭包

「函数」和「函数内部能访问到的变量」的总和,就是一个闭包。
可以在一个内层函数中访问到其外层函数的作用域
使用场景:

  • 创建私有变量
  • 延长变量的生命周期

在浏览器中从输入Url并回车发生了什么?

  • 输入网址
  • 发送到 DNS 服务器域名解析,获得真实IP地址
  • 与服务器建立 TCP 连接
  • 浏览器向 web 服务器发送 HTTP 请求
  • 服务器处理请求,并返回响应结果(指定 URL 数据,或者错误信息,或重定向新的 URL 地址)
  • 浏览器下载 web 服务器返回的数据及解析 html 源文件
  • 生成 DOM 树,解析 css 和 js ,渲染页面,直至显示完成

XSS 跨域脚本注入

CSRF(跨站请求伪造)

https://blog.csdn.net/stpeace/article/details/283
(1)验证 HTTP Referer 和 Origin 字段
(2)在请求地址中添加 token 并验证
(3)在 HTTP 头中自定义属性并验证

Referer

https://blog.csdn.net/shenqueying/article/details/79426884

原生javaScript

DOM 操作

  • 创建节点 :createElement
  • 查询节点:queryELement
  • 更新节点:innerHTML
  • 添加节点:appendChild
  • 删除节点:removeChild

获取DOM

console.dir("对象")
document.getElementById("id值")
document.getElementsByTagName("标签名")
document.getElementsByClassName("类名")
document.querySelector("选择器")//返回指定的第一个元素对
document.querySelectorAll("")
document.body
document.documentElement

排他算法
先干掉所有人,然后操作指定元素

阻止链接跳转

<a href="javascript:void(0);">单击此处什么都不会发生</a><br>//阻止链接跳转 javascript:void(0); 或者  javascript:;

获取自定义属性

element.getAttribute("属性")
element.setAttribute("属性","值")
element.removeAttribute("属性")
// H5新增获取自定义属性,只能以 data- 开头的,IE 11开始支持,如果自定义属性里有多个 - 单词,获取的时候采用驼峰命名法
#data-index  data-index-name
element.dataset.index 
element.dataset.indexName
element.dataset['index']
element.dataset['indexName']



// scrollIntoView()方法将调用它的元素滚动到浏览器窗口的可见区域
element.scrollIntoView 

节点

创建元素的三种方式

  1. document.write() //不推荐,会导致页面重绘
  2. element.innerHTML() //不要拼接字符串,采用数组形式效率高
  3. document.createElement()

节点类型
nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)

// 输出节点名称,需要先判断节点类型
nodeType = 1 //元素节点
nodeType = 2 //属性节点
nodeType = 3 //文本节点(文字、空格、换行)

父子兄层级关系

//父子节点 : node.parentNode 离它最近的父级节点,找不到返回null
parentNode.childNodes //返回的是所有节点(包含属性节点 和 文本节点)**不提倡**
parentNode.children //获取所有的子元素节点

//获取第一个和最后一个节点
parentNode.firstChild  //获取第一个节点,不推荐(包含属性节点 和 文本节点)
parentNode.lastChild  //获取最后一个节点

//要求兼容性 IE 9 以上
parentNode.firstElementChild //获取第一个元素节点,
parentNode.lastElementChild //获取的最后一个元素节点, IE 9 以上

//开发过程中,获取第一个和最后一个节点实际写法
node.children[0]
node.children[node.children.length - 1]

//兄弟节点
node.nextSibling //下一个节点包含 元素 节点或者 文本节点
node.previousSibling //上一个节点

//要求兼容性 IE 9 以上
node.nextElementSibling //下一个元素节点
node.previousElementSibling //上一个元素节点

//实际过程中,自己封装一个函数
function getNextElementSibling(element) {
    var el = element;
    while (el = el.nextSibling) {
        if(el.nodeType === 1){
            return el ;
        }
    }
    return null;
}

节点操作

//添加节点------1.创建元素节点,2.添加到页面上
var newEl = document.createElement("")
//在节点后插入
node.appendChild(child)//node 父级 child 子级,类似 数组 push
parent.appendChild(newEl)
//在节点之前插入
node.insertBefore(child,node)

//删除节点
mode.removeChild(child)//node 父级 child 子级,

<!--复制节点----1.复制节点,2.添加到页面上
    false 浅拷贝,只复制标签,不复制里面的内容;
    true 深拷贝,复制标签和复制里面的内容 -->
node.cloneNode(Boolean) 

事件(事件源、事件类型、事件处理类型)
1.获取事件源
2.注册事件,绑定事件
3.添加事件处理程序

传统注册事件
1.利用on开头的事件

  • btn.onclick = function(){}
  • 特点:注册事件的唯一性,后面的注册处理函数会覆盖前面的注册处理函数
  • 事件源.事件类型 = 事件方法,

2.方法监听注册事件 (w3c标注 推荐方式)

  • eventTarget.addEventListener(type,listener[,canUpdate])
  • 特点:同一个元素,同一个事件可以注册多个监听器 ,多个事件处理程序
  • type 事件类型字符串,不带on
  • listener 事件处理函数
  • seCapture:可选参数,布尔值,默认为false,表示在事件冒泡阶段调用事件处理程序(从最外层到最内层);如果为true,则表示在事件捕获阶段调用事件处理程序(从最内层到最外层)

3.淘汰的 attachEvent()非标准,不建议在生产环境中使用

  • eventTarget.attachEvent(eventNameWithOn,callback)
  • eventNameWithOn 事件类型字符串要带上on
  • callback 事件处理函数
// 删除事件
eventTarget.onclick = function(){}
eventTarget.onclick = null

<!-- 推荐写法 -->
eventTarget.addEventListener('click',fn)//fn不需要()调用
eventTarget.removeEventListener('click',fn[,canUpdate])

eventTarget.attachEvent('onclick',fn)
eventTarget.detachEvent('onclick',fn)

冒泡和捕获
DOMException 事件流,事件发生时会在元素节点之间按照特定的顺序传播的传播过程

标准事件模型,事件流描述的是从页面中接收事件的顺序,可以分成三个阶段
1.捕获阶段;
2.当前目标阶段;
3.冒泡阶段

事件冒泡:IE 最早提出,事件开始由最具体的元素接收,然后逐级向上传播到DOM最顶层的过程
事件捕获: 网景最早提出,由DOM最顶层节点开始,然后主机向下传播到具体元素接收的过
1.JS代码中只能执行捕获或者冒泡的其中一个阶段
2.onclick 和 attachEvent 只能得到冒泡阶段
3.addEventListener(type,listener[,canUpdate]),第三个参数==true 表示捕获阶段,==false,默认不写就是false 表示冒泡阶段
4.实际开发过程中很少用到捕获,我们只需要关注冒泡
5.有些事件是没有冒泡的,比如 onblur,onfocus,onmouseenter,onmouseleave

事件对象
function(event)
1.event就是一个事件对象,写到我们的侦听函数里,写在小括号里,当形参看
2.事件对象只有有了事件才会存在,系统自动会创建,不需要我们传递参数
3.事件对象 是 我们事件的一系列相关数据的集合
4.事件对象可以自己命名
5.事件对象也有兼容性问题,IE 6 7 8 通过 window.event, 兼容性写法 e = e || window,event常见的事件对象和属性。
e.target 返回的是触发事件的对象(元素),(点击了哪个元素,就返回了那个元素), this 返回的是绑定事件的对象(元素)
e.srcEleMent (IE 6 7 8) === e.target
兼容性写法

div.onclick = function(e){
    e = e || window.event
    var target = e.target || e.srcElement
}

currentTarget 跟 this 很相似,但是IE 6 7 8 不认识

e.type 事件类型
阻止事件的默认行为

e.preventDefault() //方法,组织时间默认行为,DOM 标准写法
e.returnValue; //属性,只支持IE 6 7 8 
return false  //没有兼容

阻止事件冒泡
标准写法: 利用事件对象里面的 e.stopPropagation()方法,IE 6 7 8 不支持
非标准 e.cancelBubble = true

事件委托、委派 click 、mousedown 、mouseup、kedown、keyup、keypress
不是每个子节点单独设置事件监听器,而是事件监听器设置在起父节点上,然后利用冒泡原理影响设置每个子节点
作用 : 减少操作DOM次数,提高程序性能

  • 减少整个页面所需的内存,提升整体性能
  • 动态绑定,减少重复工作

例子(e.target 获取当前点击的元素对象):

<ul>
    <li>点击1</li>
    <li>点击2</li>
    <li>点击3</li>
    <li>点击4</li>
    <li>点击5</li>
</ul> 
<script>
    //使用事件委托的代码
    var ul = document.getElementsByTagName('ul')[0];
    ul.addEventListener('click', function(e){
        alert(e.target.innerHTML)
    }, false);
    //不使用事件委托,循环给li添加click事件
    var li = document.getElementsByTagName('li');
    for(var i = 0; i < li.length; i++){
        li[i].onclick = function () {
            alert(this.innerHTML);
        }
    }
</script>

事件模型

  • 原始事件模型(DOM0级别)直接绑定或者通过 js 绑定 onclick
  • 标准事件模型 (DOM2 级别)事件监听函数 addEventListener
  • IE 事件模型 (基本不用)

鼠标事件
contextmenu 禁止右键菜单
selectstart 禁止选中文字

鼠标坐标
client 鼠标在浏览器可视区域X,Y
page 文档页面的X,Y IE9+ 支持
screen 电脑屏幕

键盘事件

  • keyup //不区分大小写,文字已经在输入框里面
  • keydown //不区分大小写
  • keypress //区分大小写,不识别功能键

执行顺序: keyup => keypress => keydown

BOM 浏览器对象模型

window =>( document location navigator screen history)

  • location对象提供了与当前窗口中加载的文档有关的信息以及一些导航功能;
  • navigator对象用来描述浏览器本身,包括浏览器的名称、版本、语言、系统平台、用户特性字符串等信息;
  • screen对象用来表明客户端显示器的能力。多用于测定客户端能力的站点跟踪工具中。
  • history对象保存着从窗口被打开起的历史记录,每个浏览器窗口、标签页、框架都有自己的history对象;

window.name => 是一个特殊属性,所以 命名变量的时候不推荐 变量名name

window.onload => 是窗口(页面)加载事件,当文档内容完全加载完成后会触发该事件,包括样式表、图标,只能执行一次,以最后一个为准
window.addEventListener(‘load’,fn) 没有限制个数
document.addEventListener(‘DOMContentLoaded’,fn) //当DOM 加载完毕后完成,不包括样式表、图片,IE9以上

resize 浏览器窗口大小事件,window.innerWidth 当前浏览器窗口宽度

定时器

setTimeout(callback,3000)//定时炸弹
clearTimeout()
setInterval()// 反复调用
clearInterval() 

js 执行机制(单线程)

同步和异步

  • 同步任务: 同步任务都在主线程上执行,形成一个执行栈
  • 异步任务:通过回调函数实现,会把相关回调函数添加到任务队列中(消息队列)
    1. 普通事件,如click、resize
    2. 资源加载,如load、error
    3. 定时器

执行机制:

  1. 先执行 执行栈中的同步任务
  2. 异步任务(回调函数)放入任务队列中
  3. 一旦执行栈中的所有同步任务执行完毕,系统会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行

event loop 事件循环
由于主线程不断地重复获得任务、执行任务、再获取任务、再执行,所以这种机制叫做 事件循环

ES6事件循环
JS是有两个任务队列的,一个叫做宏任务,一个叫做(微任务)
Macrotask Queue(宏观任务): 在浏览器端,其可以理解为该任务执行完后,在下一个macrotask执行开始前,浏览器可以进行页面渲染。触发macrotask任务的操作包括

  • script(整体代码)
  • setTimeout、setInterval、setImmediate
  • I/O、UI交互事件
  • postMessage、MessageChannel

Microtask Queue(微观任务):可以理解为在macrotask任务执行后,页面渲染前立即执行的任务。触发microtask任务的操作包括:

  • Promise.then
  • MutationObserver
  • process.nextTick(Node环境)
  • await
console.log('script start');
setTimeout(function() {
  console.log('timeout');
}, 0);
Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});
console.log('script end');
//输出结果
// script start > script end > promise1 > promise2 > timeout

其实事件循环做的事情如下:

  1. 执行一个macrotask(包括整体script代码),若js执行栈空闲则从任务队列中取
  2. 执行过程中遇到microtask,则将其添加到micro task queue中;同样遇到macrotask则添加到macro task queue中
  3. macrotask执行完毕后,立即按序执行micro task queue(微任务队列)中的所有microtask;如果在执行microtask的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行;
  4. 所有microtask执行完毕后,浏览器开始渲染,GUI线程接管渲染
  5. 渲染完毕,从macro task queue(宏任务队列)中取下一个macrotask开始执行

简单来讲,整体的js代码这个macrotask先执行,同步代码执行完后有microtask执行microtask,没有microtask执行下一个macrotask,如此往复循环;

location 对象
统一资源定位符 URL

location.href //获取或者设置整个URL
location.host //获取主机(域名)
location.port //获取端口号
location.pathname //返回路径
location.search //返回参数
location.hash //返回片段
location.assign() //跳转页面,记录浏览器历史,可后退
location.replace() //重定向,不计入历史不可后退
location.reload()  //页面重载,可以加 true 强制刷新

navigator 对象
浏览器的信息 userAgent 浏览器类型

history 对象

history.back() //后退
history.forward() //前进
history.go() //前进后退功能,1前进一个页面,-1后退一个页面
history.length 获取历史记录数

元素偏移量 offset 元素的位置、偏移
element.offsetTop 、element.offsetLeft// 以带有定位的父亲元素为准,找不到父亲,返回body,不返回单位,
element.offsetWidth、elementHeight 包括padding、broder、内容区的宽度高度
offset 和 style 区别

offsetstyle
可以得到任意样式表中的样式值只能得到行内样式表中的样式值
数值没有单位.数值有单位字符串
offset.Width 包含padding、broder、width;只有width
offset.Width等属性只读,不能赋值style.width 可读写
适合获取元素大小位置适合改变元素的大小位置,client 元素边框大小、元素大小、不包含边框

数组

会改变原数组:push\pop、shift\unshift、sort\reverse、splice
不会改变元素组: map、forEach、filter、some、every、join、concat、slice、indexOf、reduce

遍历数组


// for 最优写法
for(var i , len = arr.length; i<len; i++){
    //耗时最短,性能最高
}

arr.forEach(function(e){
    //ES 5 加上的
    //数组自带的方法,不推荐
})


for(var i in arr){
    //多用于遍历对象,性能低下,不推荐
}

arr.map(function(e){
    //好看不实用,性能比forEach还低
})

for(let value of arr){
    //需要ES6 支持,性能好于 for in ,但比不上普通的for循环
}

// every (return false 跳出循环,return true 也需要写)
//当内部return false时跳出整个循环
let list = [1, 2, 3, 4, 5];
list.every((value, index) => {
    if(value > 3){
        console.log(value)// 4
        return false;
 
    }else{
        console.log(value)// 1 2 3
        // 如果没有return true 的话,直接输出 1 后,跳出循环
        return true;
    
    }
 
});

// some( return true 跳出整个循环)
let list2 = [1, 2, 3, 4, 5];
list2.some((value, index) => {
	if(value === 3){
	    return true;//当内部return true时跳出整个循环
	}
	console.log(value)// 1 2 
});

// for of 遍历数组
// for in 遍历对象

for 循环和 for in 、for of 能正确的响应 break、continue 和 return ,forEach 不行

遍历对象

对象如何找属性 | 方法:
先在对象本身找 => 构造函数中找 => 对象原型中找 => 构造函数原型中找 => 对象上一层原型查找


var mySymbol  = Symbol()
var obj = {
    0 : 'a',
    1 : 'b',
    2 : 'c'
}
// 可枚举属性
Object.defineProperty(obj,'4',{
    value: 'IS123',
    enumerable: true
})
//定义不可枚举属性
Object.defineProperty(obj,'person',{
    value: '123',
    enumerable: false
})
//定义symbol 属性
obj[mySymbol] = 'hello';




//1. Object.keys() 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)
Object.keys(obj).forEach((key)=>{
    console.log(key,obj[key]);
})
// 0 a
// 1 b
// 2 c
// 4 IS123


//2. for in 遍历 循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)
for(var i in obj){
    console.log(i, ':', obj[i]);
}
// 0 a
// 1 b
// 2 c
// 4 IS123

//3. Object.getOwnPropertyName(obj)  返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)
Object.getOwnPropertyNames(obj).forEach((key)=>{
    console.log(key,obj[key]);
})
// 0 a
// 1 b
// 2 c
// 4 IS123

// 4. Reflect.ownKeys(obj) 返回一个数组,包含对象自身的所有属性,不管属性名是Symbol或者字符串,也不管是否可枚举
Reflect.ownKeys(obj).forEach((key)=>{
    console.log(key,obj[key]);
})
// 0 a
// 1 b
// 2 c
// 4 IS123
// person 123
// Symbol() 'hello'

作用域

作用域,即变量(变量作用域又称 上下文)和函数生效(能被访问)的区域或集合

1.在函数内部没有声明直接赋值的变量属于全局变量
2.全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
3.局部变量:只在函数内部使用,当其多所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此就更节约内存空间

作用域链

作用域链:一组对象列表,包含 父级和自身的变量对象,因此可以通过作用域链访问到父级 ( 逐层查找 ) 里声明的变量或者函数。( 就近原则 )

原型、原型链、继承

  1. 原型: 所有的函数都有 prototype 属性,所有的对象都有 proto 属性
  2. 在 JavaScript 中,每个函数都有一个原型属性 prototype 指向自身的原型,而由这个函数创造的对象也有一个 proto 属性指向这个原型,而函数的原型是一个对象,所以这个对象也会有一个 proto 指向自己的原型,这样逐层深入到 Object 对象原型,这样就形成了原型链。

JS 垃圾回收机制

  1. JS 的垃圾回收机制是为了防止内存泄漏( 已经不需要的某一块内存还一直存在着 ),,垃圾回收机制就是不停歇的寻找这些不再使用的变量,并且释放掉它所指向的内存
  2. 变量的生命周期: 当一个变量的生命周期,它所指向的内存就会被释放。JS 有两种变量,局部变量和全局变量,局部变量是在他当前的函数中产生作用,当该函数结束之后,该变量内存会被释放,全局变量则会一直存在,直到浏览器关闭为止。
  3. JS 垃圾回收方式:
    **标记清除:**大部分浏览器使用这种垃圾回收,当变量进入执行环境(声明变量)的时候,垃圾回收器将该变量离开环境的时候,将其再度标记,随之进行删除。
    **引用计数:**这种方式常常会引起内存泄露,主要存在于低版本的浏览器。它的机制就是跟踪一个值得引用次数,当声明一个变量并且将一个引用类型赋值给变量的时候引用次数加 1 ,当这个变量指向其他一个时引用次数减 1 ,当为 0 时触发回收机制进行回收

函数表达式(匿名函数)

var fn = function(){}

this

  1. this 总是指向函数的直接调用者
  2. 如果有 new 关键字,this 指向 new 出来的对象
  3. 在事件中,this 指向这个事件的对象

绑定规则

  • 默认绑定
  • 隐式绑定
  • new 绑定
  • 显式绑定
    优先级: new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定

this 指向问题

  1. 全局作用域或者普通函数中 this 指向是全局对象 window (定时器中的this也是执行window)
  2. 方法调用中谁调用 this 指向谁
  3. 构造函数中 this 指向构造函数的实例
  4. 箭头函数: 箭头函数的 this 绑定看的是 this 所在函数定义在哪个对象下,就绑定哪个对象。如果有嵌套的情况,则 this 绑定到最近的一层对象上
  5. apply 、call、bind 可以改变 this 的指向。

New 构造函数

  1. 创建一个新对象;
  2. 新对象会被执行 [[ prototype ]] 原型连接 ( proto => prototype )
  3. 新对象和函数调用的 this 会被绑定起来
  4. 执行构造函数中的代码
  5. 如果函数没有返回值,就自动返回这个新对象

深拷贝、浅拷贝

基本数据类型(名值存储于栈内存中):string、number、boolean、null、undefined、symbol、BigInt(ES10)
引用数据类型(名在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值):有常规名值的无需对象{a:1}、数组[1,2,3]、函数

  • 拷贝对象变了,浅拷贝
  • 不影响拷贝对象,深拷贝
  • 可以使用 lodash 插件实现深拷贝( _.cloneDeep() )
    数组可用 JSON.stringify()和JSON.parse()实现深拷贝

预解析

字符串

// substring(start,end) 用数学表达式表达区间的话就是截取[start,end);
// substring(start) 没有end相当于[start,最后一个字符];
let str = "hello world"
console.log(str.substring(0,3)) // hel
console.log(str.substring(3)) // lo world

// slice(start,end) -> start不能大于end,否则返回空字符串;
// slice可以接受参数是负数,如果是负数的话,规则将按照:字符串的长度和赋值相加,替换掉这个值。举例如下:
console.log(str.slice(0,3)) // hel
console.log(str.slice(3)) // lo world
console.log(str.length)
console.log(str.slice(11)) // 空字符串
console.log(str.slice(1,2)) 
console.log(str.slice(1,-9)) // e, 等价于 str.slice(1,(11-9)) === str.slice(1,2)
console.log(str.slice(7,-10)) // 空字符串,等价于 str.slice(7,(11-10)) === str.slice(7,1)

// 已经废弃
// substr(start,length) -> 截取的字符串区间为:[start,start+length)->从start开始,算上start数length个字符串;
// substr(start) -> 截取的字符串区间为:[start,最后一个字符]

console.log(str.substr(0,2)) // he


// 字符串转数组
console.log(str.split(''))
let arr = str.split('')
// 数组转字符串
console.log(arr.join(''))

浏览器的同源策略( 跨域 )

1.协议 ( protocol )
2.域名 ( host )
3.端口号 ( port )

为什么利用多个域名来存储网站资源会更有效

1.CDN 缓存更方便
2. 突破浏览器并发限制
3. 节约 cookice 带宽
4. 节约主域名的连接数,优化页面响应速度
5. 防止不必要的安全问题

如何解决跨域

  1. jsonp 跨域
  2. document.domain + iframe 跨域
  3. node.js 中间件代理跨域 (服务器代理)
  4. 后端在头部信息里设置安全域名 (CORS)【Access-Control-Allow-Origin】

项目优化

减少 HTTP 请求
减少 DNS 查询
使用 CDN
避免重定向
图片懒加载
减少 DOM 元素数量
减少 DOM 操作
使用外部 JavaScript 和 CSS
压缩 JavaScript 、CSS、字体、图片
优化 CSS Sprite
使用 iconfont
多域名分发划分内容到不同域名
尽量减少 iframe 使用
避免图片 src 为空
把样式表放在 link 中
把 JavaScript 放在页面底部

什么是单线程,和异步有什么关系

单线程:只有一个线程,只能做一件事
原因: 避免 DOM 渲染的冲突
浏览器需要渲染 DOM,JS 可以修改 DOM 结构,JS 执行的时候,浏览器 DOM 渲染会停止,两段 JS 也不能同时执行( 都修改 DOM 就冲突了 )
webworker 支持多线程,但是不能访问 DOM
解决方案: 异步

attribute 和 property 的区别

attribute 是 DOM 元素在文档中作为 html 标签拥有的属性
property 是 DOM 元素在 js 中作为对象拥有的属性
对于 html 的标准属性来说,attribute 和 property 是同步的,是会自动更新的

WebWorker

在后台运行的 Javascript ,独立于其他脚本,不会影响页面性能。(多线程)

// index.html
const worker = new worker('worker.js')
worker.onmessage = e =>{
  console.log(e)
}

// worker.js
self.postMessage('hello worker!!')

call、apply、bind 区别

  • 三者都可以改变函数的 this 对象指向
  • 三者的第一个参数都是 this 要指向的对象,如果没有这个参数或参数为 undefined 或 null ,则默认指向全局 window
  • apply 第二个参数是数组,call 和 bind 有多个参数需要挨着写
  • call、apply 可以立即执行。bind 是返回绑定 this 之后的函数,不会立即执行

sort 背后的原理

现在是冒泡排序,之前是插入排序和快排

null 和 undefined 的区别

  1. 作者在设计 js 的时候都是先设计的 null (最初设计 js 的时候借鉴了 java )
  2. null 会被隐式转换成 0 ,不容易发现错误
  3. 先有的 null 后有的 undefined
    Javascript 的最初版本是这样区分的:null 是一个表示 “无” 的对象(空对象指针),转换数值时为 0 ;undefined 是一个表示未定义的值,转为数值时为 NaN

== 和 === 有什么不同

相等操作符(==)比较规则:

  • 两个都为简单类型,字符串和布尔值都会转换成数值,再比较
  • 简单类型与引用类型,对象转化成其原始类型的值,再比较
  • 两个都为引用类型,则比较它们是否指向同一个对象
  • null 和 undefined 相等
  • 存在 NaN 则返回 false

区别:

  • == 等于操作符,比较的时候会隐式转换(通过 valueOf() 方法转换 )
  • === 全等操作符,类型相同,值也相同

除了在比较对象属性为 null 或者 undefined 的情况下,使用 相等操作符,其他的情况都使用 全等操作符

slice 和 splice 的区别

  1. slice 只能是用来截取的
    参数可以是 slice(1)、slice(1,3)、slice(-1)
    返回的是一个新的数组
  2. splice 功能有: 插入、删除、替换
    返回的是改变元素后的数组

typeof 和 instanceof 区别

typeof 操作符返回一个字符串,表示未经计算的操作数的类型
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

区别:

  1. typeof 会返回一个变量的基本类型,instanceof 返回的是一个布尔值
  2. instanceof 不能准确判断
  3. typeof 不能判断 null ,引用类型除(function)之外,其他的也不能准确判断
typeofinstanceof
作用检测数据类型检测对象之间的关联性
返回小写字母字符串布尔值
操作数简单数据类型、函数或者对象左边必须是引用类型右边必须是函数
操作数数量1个2个

ES5 继承和 ES6 继承 的区别

  • ES5 继承的实质是先创建子类的实例对象,然后再将父类的方法添加到 this 上 ( Parent.apply( this ) ), 然后再原型链继承
  • ES6 继承是先创建父类的实例对象( 所以必须调用父类的 super() 方法,才可使用 this 关键字,否则报错),然后再用子类的构造函数修改 this 实现继承

异步编程解决方案

  • 回调函数
  • Promise 对象
  • Generator 对象
  • async / await
    区别:
  • Promise 和 async/await 是专门用于处理异步操作的
  • Generator 并不是为异步而设计出来的,它还有其他功能(对象迭代、控制输出、部署 interator 接口…)
  • Promise 编写代码相比 Generator 、async 更为复杂化,且可读性也稍差
  • Generator 、async 需要与 Promise 对象搭配处理异步情况
  • async 实质上 Generator 的语法糖,相当于会自动执行 Generator 函数
  • async 使用上更为简洁,将异步代码以同步的形式进行编写,是处理异步编程的最终方案

22. defer 和 async

defer 阻塞,文档解析完毕后执行
async ,html5 新属性,异步下载脚本,下载完毕后立即解释执行代码

JavaScript 中执行上下文和执行栈是什么

简单的来说,执行上下文是一种对 JavaScript 代码执行环境的抽象概念
分成三种类型:

  • 全局执行上下文:JavaScript 代码运行起来会首先进入该环境
  • 函数执行上下文:当函数被调用执行时,会进入当前函数中执行代码
  • Eval 函数执行上下文 (不建议使用,可忽略)
    生命周期:创建阶段------》 执行阶段-----》 回收阶段
    执行栈,也叫调用栈,具有 LIFO ( 后进先出 )结构,用于存储在代码执行期间创建的所有执行上下文
  • 创建全局上下文请压入栈
  • first 函数被调用,创建函数执行上下文并压入栈
  • 执行 first 函数过程遇到 second 函数,在创建一个函数执行上下文并压入栈
  • second 函数执行完毕,对应函数执行上下文被推出执行栈,执行下一个执行上下文 first 函数
  • frist 函数执行完毕,对应的函数执行上下文也被推出执行栈,然后执行全局上下文
  • 所有代码执行完毕,全局上下文也会推出栈,程序结束

ajax 原理

Ajax 通过 XmlHttpRequest 对象服务器发异步请求,从服务器获得数据,然后用 JavaScript 来操作 DOM 而更新页面
过程:

  • 创建 Ajax 和核心对象 XMLHTTPrequest 对象
  • 通过 XMLHTTPrequest 对象的 open() 方法与服务器简历连接
  • 构建请求所需的数据内容,并通过 XMLHTTPRequest 对象的 send() 方法发送给服务端
  • 通过 XMLHTTPRequest 对象提供的 onreadystatechange 事件监听服务器端的通信状态
  • 接受并处理服务器端向客户端响应的数据结果
  • 处理结果更新到 HTML 页面中

正则表达式

正则表达式用来匹配字符串

async 与 await

function f() {
  return Promise.resolve('test')
}
// 等价于
async function asyncF() {
  return 'test'
}
console.log(f(), asyncF())
// Promise { 'test' } Promise { 'test' }

不管 await 后面跟着什么,await 都会阻塞后面的代码

async function fn1 (){
  console.log(1)
  await fn2()
  console.log(2) // 被阻塞
}

async function fn2 (){
  console.log('fn2')
}

fn1()
// 1  fn2 2

cookie 、sessionStorage 和 localStorage 区别

cookiesessionStoragelocalStorage
大小4kb5MB10MB
兼容H4/H5H5H5
访问任何窗口同一窗口任何窗口
有效期手动设置到窗口关闭
存储位置浏览器或者服务器浏览器浏览器
与请求一起发送
语法复杂简易简易

尾递归

递归:需要有边界条件、递归前进阶段和递归返回阶段
尾递归,多了两个特征:

  • 在尾部调用的是函数自身
  • 可通过优化,使得计算仅占用常量栈空间
// 递归
function factorial(n) {
  if (n === 1) return 1;
  return n * factorial(n - 1)
}


// 尾递归
function factorialNew(n, total = 1) {
  if (n === 1) return total
  return factorialNew(n - 1, n * total)
}
console.log(
  factorial(5),
  factorialNew(5)
)  // 120 120

说说 JavaScript 数字精度丢失的问题

toPrecision 凑整并 parseFloat

console.log(parseFloat(2.80000000000000000002.toPrecision(12)) === 2.8)

如何判断一个元素是否在可视区域中

实现方式:

  • offsetTop、scrollTop
  • getBoundingClientRect
  • Intersection Observer

大文件上传如何做断点续传

分片上传:

  1. 将需要上传的文件按照一定的分割规则,分割成相同大小的数据块
  2. 初始化一个分片上传任务,返回本次分片上传唯一标识
  3. 按照一定的策略(串行或并行)发送各个分片数据块
  4. 发送完成后,服务端根据数据上传是否完整,如果完整则进行数据块合成得到原始文件

断点上传:
每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或者下载的部分开始继续上传或下载未完成的部分,而没有必要从头开始上传下载。用户可以节省时间,提高速度

如何实现上拉加载、下拉刷新

触底公式:scrollTop + clientHeight >= scrollHeight

  • scrollTop : 滚动视窗的高度距离 window 顶部的距离,它会随着往上而不断增加,初始值是 0 ,它是一个变化的值
  • clientHeight: 它是一个定值,标识屏幕可视区域的高度
  • scrollHeight:页面不能滚动时是不存在的,body 长度超过 window 时才会出现,所表示 body 所有元素的长度

下拉刷新:

  • 监听原生 touchstart 事件,记录其初始位置,e.touches[0].pagey
  • 监听原生 touchmove 事件,记录并计算出当前滑动的位置与初始位置的差值,大于 0 表示向下拉动,并借助 CSS3 的 translateY 属性使元素跟随手势往下滑动对应的差值,同时也应设置一个允许滑动的最大值
  • 监听原生的 touchend 事件,若此时元素滑动达到最大值,则触发 callback ,同时 translateY 重设为 0,元素回到初始位置

什么是单点登录

SSO 是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统
实现:
1. 同域名下的单点登录:
cookie 的 domain 属性设置为当前域的父域,并且父域的 cookie 会被子域所共享,path 属性默认为 web 应用 的上下文路径。
只要将 Cookie 的 domain 属性设置为父域的域名(主域名),同时将 Cookie 的 path 属性设置为根路径,将 Session ID (或 Token )保存到父域中。这样所有的子域应用就可以访问到这个 Cookie
不过这要求应用系统的域名需要建立在一个共同的主域名之下。

2. 不同域名下的单点登录 (一)
部署一个认证中心,用于专门处理登录请求的独立 web 系统
3. 不同域名下的单点登录 (二)
可以选择将 Session ID (或者 Token )保存到浏览器的 localstorage 中,让前端在每次向后端请求时,主动加 localstorage 的数据传输给服务端
具体实现:前端通过 iframe + postMessage() 方式,将同一份 Token 写入到多个域的 localstorage 中。

web 常见的攻击方式有些

  • XSS (Cross site script)跨站脚本攻击
  • CSRF (Cross-site request forgery)跨站请求伪造
  • SQL 注入攻击

XSS:

  • 存储型: 存到数据库
  • 反射型:存到 URL
  • DOM 型: 恶意代码由浏览器执行
    预防:
    主要通过过滤

CSRF
攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击者发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,打到冒充用户对被攻击者的网站执行某项操作目的
特点:

  • 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击的发生;
  • 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据;
  • 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是‘冒用’
  • 跨站请求可以用各种方式: 图片URL 、超链接、CORS、From 提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中。难以进行追踪
    预防
  • 阻止不明外域的访问: 同源检测;Samesite Cookie
  • 提交是要求附加本域才能获取信息:CSRF Token;双重 Cookie 验证

SQL 注入

  • 严格检查输入变量的类型和格式
  • 过滤和转移特殊字符
  • 对访问数据库的 web 应用程序采用 web 应用防火墙

Object 类

属性名定义默认值
writable属性是否可以被重写false
enumerable属性是否可以被枚举false
configurable属性是否可以被再次修改false

Object.assign() : 用于将所有可枚举属性的值从一个或者多个源对象分配到目标对象
Object.create() : 创建一个新对象,使用现有对象提供新创建的对象的 proto
Object.defineproperty() : 在对象上定一个新属性或者修改对象现有属性(不能被重写 writable)

Object.defineproperties() : 在一个对象上定义新的属性或修改现有属性

Object.entries() : 返回一个给定对象自身可枚举属性的键值对数组
Object.is() : 判断两个值是否为同一个
Object.key() : 返回一个给定对象的自身可枚举属性组成的数组
Object.values() : 返回一个给定对象的所有可枚举属性值的数组
Object.getOwnPropertyDescriptor() : 返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上查找的属性)
Object.getProtopertyOf() : 返回指定对象的内部原型

link 和 import 的区别

  • 从属关系区别:@import 是 CSS 提供的语法规则,只有导入样式的作用;link 是 HTML 提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等;
  • 加载顺序区别:加载页面时,link 标签引入 CSS 被同时加载;@import 引入的 CSS 将在页面加载完毕后被加载
  • 兼容性区别:@import 是 CSS2.1 才有的语法,故只可在 IE5+ 才能识别;link 作为 HTML 元素,不存在兼容性问题;
  • Dom 可控性区别:可以通过 JS 操作 DOM ,插入 link 标签来改变样式;由于 DOM 方法是基于文档的,无法使用 @import 方式插入样式
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值