JS+BOM+DOM汇总
文章目录
- 前言:JavaScript的发展史
- 第一章:BOM
- 1.1、概念
- 1.2、组成:window、Navigator、Screen、 History、Location
- 1.3、方法
- 第二章:DOM
- 2.1、概念
- 2.2、核心DOM模型
- 2.3、属性
- 2.4、DOM事件模型(先捕获后冒泡)
- 2.5、事件委托/事件代理
- 2.6、事件监听机制 及鼠标、键盘事件
- 2.7、文档碎片
- 第三章:JS
- 1、数据类型
- 2、判断数据类型 有四种
- 判断数组类型的4种方法
- 3、数据类型转换
- 4、null和undefined区别
- 5、var let const区别
- 6、匿名函数、箭头函数、普通函数、立即执行函数
- 7、this指向问题
- 8、arguments
- arguments 与实参的关系
- 9、闭包是什么,有什么特性,对页面有哪些影响
- 10、深拷贝,浅拷贝
- 11、js常见的内存泄漏
- 12 、js垃圾回收方式
- 13、防抖节流
- 14、作用域与作用域链
- 15、原型、原型链
- 16、javaScript页面跳转,页面重定向
- 17、ajax如何使用
- 18、Date
- 19、Math
- 20、string
- 21、Array数组方法
- 22、js对象
- 23、异步编程实现方法
- promise与async await区别
- 注:什么是单线程,和异步的关系?
- 24、如何解决跨域
- 25、Global
- 26、Unicode与utf-8区别
- 27、严格模式的限制
- 28、性能优化
- 29、负载均衡
- 30、什么是执行栈,什么是执行上下文?
- 31、JS 中的常用的继承方式
- 32、宏任务和微任务,如何执行
- 33、nextTick原理
- 34、exports和module.exports有什么区别?
- 35、AMD 和 CMD 的区别,ES6 Module 和 commonjs 的区别
- 36、函数柯里化
- 37、websocket
- 38. 设计模式知道那些?具体用法
- 39. == 与 ===的区别
- 40、JSON序列化 与 反序列化
- 41、indexOf与includes区别
- 42、JS延迟加载的方法有哪些
- 43、new操作符的原理
- 44、9个高级JavaScript方法
- 45、JS获取鼠标点击下的innerHtml的值
前言:JavaScript的发展史
Nombase公司 | 1992 | 开发出第一门客户端脚本语言,专门用于表单校验,命名为C–,后来更名为ScriptEase |
---|---|---|
Netscape(网景)公司 | 1995 | 客户端脚本语言:LiveScript,请来SUN公司专家,修改LiveScript为JavaScript |
微软 | 1996 | 抄袭JavaScript开发JScript语言 |
ECMA(欧洲计算机制造商协会) | 1997 | 统一了三家的,ECMAScript,就是所有客户端脚本语言标准。JavaScript=ECMAScript+JavaScript自己特有的东西(BOM+DOM) |
BOM管的: A区(浏览器的标签页,地址栏,搜索栏,书签栏,窗口放大还原关闭按钮,菜单栏等等)B区(浏览器的右键菜单)C区(document加载时的状态栏,显示http状态码等)D区(滚动条scroll bar)
DOM管的:E区
第一章:BOM
1.1、概念
BOM:浏览器对象模型,与浏览器交互的方法和接口,通过JS操作浏览器window / navigator / history / screen
1.2、组成:window、Navigator、Screen、 History、Location
① window:窗口对象,window也是网页中的全局对象
window对象不需要创建,可以直接使用window使用。window.方法名();
②History:历史记录对象
//创建(获取)
window.history
//方法
back(): 加载history列表中的前一个URL
forward():加载history列表中的下一个URL
go(参数): 加载history列表中某个具体页面正数:前进几个历史记录 go(1)=forward()负数:后退几个历史记录 go(-1)=back()
//属性
length:返回的是当前窗口历史列表中的 URL数量。
③Location:地址栏对象
//创建(获取)
window.location
//方法
reload():重新加载当前文档,刷新
//属性
href 设置或返回完整的URL
var href = location.href;
④ Navigator:浏览器对象,包含大量有关Web浏览器的信息,在检测浏览器及操作系统上非常有用
window.navigator.appCodeName //浏览器代码名
window.navigator.appName //浏览器步伐名
window.navigator.appMinorVersion //浏览器补钉版本
window.navigator.cpuClass //cpu类型 x86
window.navigator.platform //操作体系类型 win32
window.navigator.plugins
window.navigator.opsProfile
window.navigator.userProfile
window.navigator.systemLanguage //客户体系语言 zh-cn简体中文
window.navigator.userLanguage //用户语言,同上
window.navigator.appVersion //浏览器版本(包括 体系版本)
window.navigator.userAgent//用户代理头的字符串表示
window.navigator.onLine //用户否在线
window.navigator.cookieEnabled //浏览器是否撑持cookie
window.navigator.mimeTypes
⑤Screen:用于获取某些关于用户屏幕的信息,也可用window.screen引用它
window.screen.width //屏幕宽度
window.screen.height //屏幕高度
window.screen.colorDepth //屏幕颜色深度
window.screen.availWidth //可用宽度(除去任务栏的高度)
window.screen.availHeight //可用高度(除去任务栏的高度)
1.3、方法
①弹出框相关
alert():显示带有一段消息和一个确认按钮的警告框
confirm():显示带有一段消息以及确认按钮和取消按钮的对话框
prompt():可以弹出一个提示框,显示可提示用户输入的对话框//提示用户输入信息,接受两个参数,即要显示给用户的文本和文本框中的默认值,将文本框中的
②打开关闭
close():关闭浏览器窗口
open():打开一个新的浏览器窗口
③定时器
setTimeout():在指定的毫秒数后调用函数或计算表达式,返回值:唯一标识,用来取消定时器
clearTimeout():取消setTimeout()方法设置的timtout
setInterval():按照指定的周期(以毫秒计)来调用函数或计算表达式
clearInterval():取消由setInterval()设置的timeout
注:
如果文档包含框架(frame 或 iframe 标签),浏览器会为 HTML 文档创建一个 window 对象,并为每个框架创建一个额外的 window 对象。
② window.frames 返回窗口中所有命名的框架
③parent是父窗口(如果窗口是顶级窗口,那么parentselftop)
top是最顶级父窗口(有的窗口中套了好几层frameset或者iframe)
self是当前窗口(等价window)
opener是用open方法打开当前窗口的那个窗口
第二章:DOM
2.1、概念
文档对象模型,document object model,通过dom就可以随意更改web页面元素
2.2、核心DOM模型
针对任何结构化文档的标准模型
XML DOM:针对XML文档的标准模型
HTML DOM:针对HTML文档的标准模型
1)、 Document:文档对象
2)、Element:获取元素对象
getElementById():根据id属性值获取元素对象,id属性值一般唯一
getElementsByTagName():根据元素返回值是数组
getElementsByClassName():根据class属性值获取元素对象,返回值是数组
getElementByName():根据name属性值获取元素对象,返回值是一个数组document.querySelector(选择器) //符合条件的第一个dom对象
document.querySelectorAll(选择器) //符合条件的所有dom对象组成的类数组
3)、创建DOM对象
createElement() //创建标签节点
createTextNode //创建文本节点
cloneNode(deep) //复制一个节点,属性、值都复制。deep是true,连后代节点一起复制,否则只复制当前节点
createDocumentFragment //创建一个文档碎片节点
createTextName() //appendChild //追加子元素
insertBefore //将元素插入前面
replaceChild //替换子元素getAttribute //获取节点属性
createAttribute(name) //创建属性
setAttribute //设置节点属性
removeAttribute //删除节点属性
element.attributes //将属性生成类数组对象
createComment():
4)Text:文本对象
5)Comment:注释对象
6) Node:节点对象,其它5个的父对象
2.3、属性
1)Element:元素对象
获取 创建:通过document来获取和创建
removeAttribute():删除属性 setAttribute():设置属性
var element_a = document.getElementsByTagName("a")[0];
element_a.setAttribute("href","http://www.baidu.com");
2) Node:节点对象,其它五个的父对象
特点:所有DOM对象都可以被认为是一个节点
分类:文档节点、元素节点、 属性节点、文本节点
appenchild():向节点的子节点列表的结尾添加新的子节点;
insertBefore()
removechild():删除(并返回)当前节点的指定子节点
replacechild():用新节点替换一个子节点
parentNode:返回节点的父节点
2.4、DOM事件模型(先捕获后冒泡)
DOM事件流:事件发生时交互在元素节点间按特定顺序传播,这个传播过程是DOM事件流,在页面中接收事件的顺序
分为三个阶段:捕获阶段->当前目标阶段->冒泡阶段
1)冒泡型事件模型(IE事件流): button->div->body 1-2-3,IE9+冒泡到window
2)捕获型事件模型(Netscape事件流): body->div->button 3-2-1
var father = document.querySelector('.father');
var son = document.querySelector('.son');
document.addEventListener('click',()=>{alert('document');
},false);
father.addEventListener('click',()=>{alert('father');
},false);
son.addEventListener('click',()=>{alert('son');
},false); false:冒泡阶段;true:捕获阶段
注意:
1.Js代码中只能执行捕获或者冒泡其中的一个阶段
2.Onlick 和attachEvent 只能得到冒泡阶段
3.addEventlistener(type,listenert,usecapture)第三个参数如果是true,表示事件
捕获阶段调用事件处理程序;如果是false(默认),表示事件冒泡阶段调用事件处理程序。
4.实际开发中很少使用事件捕获,事件冒泡更值得关注
5.有些事件是没有冒泡的,比如onblur、onfocus、onmouseenter、onmouseleave
6.事件冒泡有时会带来麻烦,有时会很巧妙的做某些事件
取消事件冒泡和捕获
bubbles || stopPropagation || stopImnediatepropagation || cancleBubble;
2.5、事件委托/事件代理
子集的事件委托给父集处理
<ul><li >1</li><li >2</li><li >3</li>
</ul>
let ul = document.querySelector('ul')
ul.onclick = function (e) {ul.removeChild(e.target) //只给ul绑定删除事件,li可以用到父集的方法
}
2.6、事件监听机制 及鼠标、键盘事件
1)、概念:某些组件被执行了某些操作后,触发某些代码的执行。
事件:某些操作,如单击、双击、键盘按下、鼠标移动
事件源:组件,如:按钮、文本输入框。。。
注册监听:将事件、事件源、监听器结合在一起,当事件源上发生了某件事,则触发执行某个监听器代码。
2)、事件类型 Event
onclick 单击事件 doubleclick 双击事件 //点击事件
onblur 失去焦点 onfocus 元素获得焦点 //焦点事件
onload:一张页面或一副图像完成加载 //加载事件
onchange 域的内容被改变 //选中和改变
onselect 文本被选中
onsubmit 确认按钮被点击 //表单事件
onreset 重置按钮被点击
鼠标事件
onmousedown //鼠标按钮被按下
onmouseup //鼠标按钮被松开
onmousemove //鼠标被移动
onmouseout //鼠标从某元素移开
onmouseover //鼠标移到某元素之上
mouseleave //鼠标离开某个元素边界时触发
键盘事件
onkeydown //某个键盘按钮被按下
onkeyup //某个键盘按钮被松开
onkeypress //某个键盘按钮被按下或松开
鼠标事件的各个坐标
js中元素视图的各个尺寸
window视图的各个尺寸
Document 文档视图的各个尺寸
2.7、文档碎片
一个容器,用于暂时存放创建的dom元素,使用document.createDocumentFragment()创建
作用:将需要添加的大量元素,先添加到文档碎片中,再将文档碎片添加到需要插入的位置,减少dom操作,提高性能
var oFragmeng = document.createDocumentFragment();
for(var i=0;i<10000;i++)
{ var op = document.createElement("span"); var oText = document.createTextNode(i); op.appendChild(oText); oFragmeng.appendChild(op); //先附加在文档碎片中
}
document.body.appendChild(oFragmeng); //最后一次性添加到document中
第三章:JS
1、数据类型
①基本数据类型:number / boolean / string / null / undefined / Symbol(ES6) / BigInt(ES10)
②引用类型:object(包含Function、Date、Math、Array、RegExp)
③在JS中提供3种包装类,可以将基本数据类型转换为对象,String()、 Number()、 Boolean()
注:
基本类型:保存的是数值,直接存储在栈中
基本数据经常被频繁使用,存在栈中,占用空间小,大小固定
引用类型:保存的是地址值,存储在堆中,在栈中保存数据的引用地址,这个引用地址指向的是对应的数据,以便快速查找到堆内存中的对象。
引用类型同时存在栈和堆中,占用空间大,大小不固定,在栈中存储指针指向堆中实体的起始
栈内存是自动分配内存的。而堆内存是动态分配内存的,不会自动释放。所以每次使用完对象的时候都要把它设置为null,从而减少无用内存的消耗
地址,解释器寻找引用值时,先在栈中找地址,获得地址后从堆中获得实体
var number = new Number(3); //object
var boolean = new Boolean(true);
var string = new String("ok");
number.b = 34 //Number(3,b:34)
js的数据存储是使用二进制,如果二进制前三位都是0,是object类型,null的二进制全是0,(type null 是object)
000:对象
1:整型
010:双精度类型
100:字符串
110:布尔类型
2、判断数据类型 有四种
1)typeof:判断基本数据类型返回对应的类型;判断引用类型,一律返回object,不能区分null/undefined
2)instanceof:判断实例是否属于某种类型,A instanceof B(A是B实例,返回True,不然false)
缺点:只能判断对象是否存在于目标对象的原型链上
原理:查找目标对象的原型链
var a = []
a instanceof Array //true
3)constructor
缺点:不能判断null和undefined;
当一个函数F被定义时,JS引擎会为F添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向F的引用
var b = []
console.log(b.constructor,b.constructor === Array) //true
var fn = new F()
console.log(F.prototype, fn.constructor == F)
4)Object.prototype.toString.call():(这个是判断类型最准的方法)
toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],(String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,… )基本上所有对象的类型都可以通过这个方法获取到。
var c = []
Object.prototype.toString.call(c) //[object Array]
注:
a、所有原型链都指向Object,必须通过Object.prototype.toString.call获取
b、instanceof与constructor判断数组对象的弊端----不能判断iframe
var iframe = document.createElement('iframe')
document.body.append(iframe)
var xArray = window.frames[window.frames.length - 1].Array
var arr = new xArray(1,2,3)
console.log(arr instanceof Array) //true
console.log(arr.constructor === Array) //true
判断数组类型的4种方法
let arr = [1,2,3,4]
console.log(arr instanceof Array) //true
console.log(Array.isArray(arr)) //true
console.log(arr.constructor) //[Function: Array]
console.log(Object.prototype.toString.call(arr)) //[object Array]
3、数据类型转换
1)、转数字:Number()方法,parseInt(),parseFloat()
Number()
Number('true') //NaN
Number('3') //3
parseInt()
parseInt('23hv') //23
parseFloat()
parseFloat()把字符串转换成浮点数,parseFloat()和parseInt非常相似,不同之处在与parseFloat会解析第一个. 遇到第二个.或者非数字结束如果解析的内容里只有整数,解析成整数。
隐式转换:
var str="123";
var num=str-0; //Number
2)、转布尔值:Boolean()方法
0、空字符串、null、undefined、NaN 都转成false,其他都是true
隐式转换
var vvv = 'dfd'
var bool = !!vvv;
console.log(bool,typeof bool) //true 'boolean'
3)、转字符串:toString(),String()、隐式
toString():不可以转null和underfined
var a = true
a.toString() //'true',String类型
String():都可以转
console.log(String(null));
隐式转换:'+'两边一个是字符串类型,一个是其他类型,会先把其他类型转换为字符串,在拼接,最后是字符串类型
var a = true;var str = a+ ''
console.log(str) //'true'
4、null和undefined区别
相同点:用if判断,两个值都转为false
不同点:使用number()方法判断,number(null)为0 number(undefined)为NaN
null是定义后赋值为null
undefined是定义后未赋值
var a a->undefined typeof a -> ‘undefined’
null的用处:
①赋值为null,是为了给赋值为空对象 var a = null
②让不被引用的赋值为null,将被垃圾回收机制回收
注:判断一个数据是不是NaN
首先,它不是数字,typeof(NaN)–>number
利用NaN的定义,用typeof判断是否为number类型并且判断是否满足isNaN
利用NaN是唯一一个不等于任何自身的特点 n!==n
5、var let const区别
var定义的变量可以修改,如果不初始化会输出undefined,不会报错。
const定义的变量不可以修改,而且必须初始化。
let是块级作用域,函数内部使用let定义后,对函数外部无影响。
Var声明的变量会挂载在window上,而let和const声明的变量不会
Var声明的变量存在变量提升,let和const不存在变量提升
同一作用域下var可以声明同名变量,let和const不可以
Let和const声明会形成块级作用域
Let暂存死区
const定义的是常量,不能修改,但是如果定义的是对象,可以修改对象内部的数据
6、匿名函数、箭头函数、普通函数、立即执行函数
JS定义函数的三种方法
//1、函数关键字(function)语句:
function fun(x){console.log(x)
}
//2、函数字面量(function Literals):
var fun = function(x){console.log(x)}
//3、function构造函数:
var fun = new Function('x',console.log(x))
后面两种把函数复制给变量fun,而这个函数没有名字,即匿名函数,很多编程语言都有匿名函数
匿名函数
优点:
- 匿名函数可以有效的保证在页面上写入Javascript,而不会造成全局变量的污染。
- 这在给一个不是很熟悉的页面增加Javascript时非常有效,也很优美。
箭头函数
箭头函数是匿名函数,不能被作为构造函数,不能被new
箭头函数不绑定aruguments,用rest参数解决
箭头函数不绑定this,会捕获上下文的this,作为自己的this
箭头函数通过call() apply()调用函数,只传入一个参数,对this没有影响
箭头函数没有原型属性
立即执行函数
又被称为立即调用的函数表达式(IIFE),类似于函数声明,但被包含在括号中,会被解释为函数表达式,紧跟第一组后面的第二组括号会立即调用前面的函数表达式。在ES6以前,为了防止变量定义外泄,采用IIFE函数
//非匿名执行函数
var a = 1; //window.a = 1
(function a () {'use strict' //增加严格模式,会报错Assignment to constant variable. 因为严格模式下只读变量不能被赋值a = 2; //window.a = 2console.log(a); //执行结果是:a函数:a=2;console.log(a)
})();
//匿名执行函数
var a = 1;
(() => {a = 2;console.log(a); //执行结果是:变量a=2
})();
原理:
函数声明优先于变量声明,所有打印的a是一个函数
非匿名执行函数,函数是只读的,不能进行赋值
7、this指向问题
以函数调用,this就指向windows
以方法的形式调用,this就是调用方法的那个对象
以构造函数的形式调用时,this是新创建的那个对象
使用call和apply调用时,this指向的那个对象
this的值是浏览器传过来的,指向很多,谁调用就指向谁
2)改变this指向的函数:call、apply、bind
区别:
- 第一点是关于函数立即执行,call() 函数与apply() 函数在执行后会立即调用前面的的数,而bind()函数不会立即调用,它会返回一个新的函数,可以在任何时候进行调用。
- 第二点是关于参数传递,call()函数与bind()函数接收的参数相同,第一个参数表示将要改变的函数执行主体,即this的指向,从第二个参数开始到最后一个参数表示的是函数接收的参数;而对于apply()函数。第一个参数与call()函数,bind() 函数相同,第二个参数是一个数组,表示的是接收的所有参数,如果第二个参数不是一个有效的数组或者arguments对象,则会抛出一个TypeError异常。
const add = function (x,y){return x+y
}
const calladd = function(x,y){return add.call(this,x,y)
}
const applyadd = function(x,y){return add.apply(this,[x,y])
}
const bindadd = function (x,y){var returnbind = add.bind(this,x,y)return returnbind()
}
console.log(add) //函数
console.log(calladd(1,2)) //3
console.log(applyadd(3,3)) //6
console.log(bindadd(2,2)) //4
①call和apply实现思路主要是:
判断是否是函数调用,若非函数调用抛异常
通过新对象(context)来调用函数:给context创建一个fn设置为需要调用的函数;结束调用完之后删除fn
call
Function.prototype.myCall = function (context) {if (typeof this !== 'function') { // 先判断调用myCall是不是一个函数,这里的this就是调用myCall的throw new TypeError("Not a Function")}context = context || window// 不传参数默认为windowcontext.fn = this// 保存thislet args = Array.from(arguments).slice(1) //Array.from 把伪数组对象转为数组let result = context.fn(...args) // 调用函数delete context.fnreturn result
}
apply
Function.prototype.myApply = function (context) {if (typeof this !== "function") { // 判断this是不是函数throw new TypeError("Not a Function")}let resultcontext = context || window// 默认是windowcontext.fn = this// 保存thisif (arguments[1]) { // 是否传参result = context.fn(...arguments[1])} else {result = context.fn()}delete context.fnreturn result
}
②bind实现思路
判断是否是函数调用,若非函数调用抛异常
返回函数:判断函数的调用方式,是否是被new出来的,new出来的话返回空对象,但是实例的__proto__指向_this的prototype
完成函数柯里化 Array.prototype.slice.call()
Function.prototype.myBind = function(context){if(typeof this !== "function") { // 判断是否是一个函数throw new TypeError("Not a Function")}const _this = this // 保存调用bind的函数const args = Array.prototype.slice.call(arguments,1) // 保存参数return function F () { // 返回一个函数if(this instanceof F) { // 判断是不是new出来的 ,如果是new出来的,返回一个空对象,return new _this(...args,...arguments) // 创建出来的实例的__proto__指向_this的prototype,且完成函数柯里化}else{ // 如果不是new出来的改变this指向,且完成函数柯里化return _this.apply(context,args.concat(...arguments))}} }
8、arguments
调用函数时,浏览器每次都会传入两个隐含的参数,this,arguments
arguments是一个类数组对象,可以通过索引操作数组,也可以获取长度
在调用函数时,传递的实参都会封装到arguments中
function fun() {console.log(arguments) //[Arguments] { '0': 'hello', '1': 'ok' }console.log(arguments instanceof Array ) // falseconsole.log(arguments instanceof Object) //trueconsole.log(Object.prototype.toString.call(arguments)) //[object Arguments]console.log(arguments.length) //2console.log(arguments[0]) //helloconsole.log(arguments.callee) //[Function: fun] arguments.callee=fun;指向arguments对象所在函数的指针,找到对应的函数对象,console.log(arguments.callee === fun) //true
}
fun("hello","ok")
arguments 与实参的关系
严格模式与非严格模式 ( ‘use strict’)
- 严格模式:arguments和实参不会相互影响
- 非严格模式:arguments和实参相互影响
function side(arr) {arr[0] = arr[2]
}
//严格模式
function fn(a,b,c=3) { //c有初始值,ES6解构赋值,是严格模式c=10;side(arguments); //arguments是[1,1,1]return a+b+c; //a:1,b:1,c:10
}
console.log(fn(1,1,1)) //12
//非严格模式
function fn(a,b,c) { //c没有初始值,是非严格模式c=10;side(arguments); //arguments是[1,1,10]console.log(arguments)return a+b+c; //a:10,b:1,c:10
}
console.log(fn(1,1,1)) //21
9、闭包是什么,有什么特性,对页面有哪些影响
父函数中返回的子函数,一个函数和它周围状态的引用捆绑在一起的组合
闭包是指有权访问另一个函数作用域中的变量的函数
优点: 延长外部函数局部变量的生命周期;避免全局变量污染
缺点:变量不会销毁,容易造成内存泄露
注意: 合理的使用闭包,用完闭包要及时清除(销毁)
var str = 'wl'
var obj ={str:'eeee',getData:function(){console.log('第1个函数',this) //this指向object,包含return function(){console.log('第二个函数',this) //this指向windowreturn this.str}}
}
console.log(obj.getData()()) //wl
console.log(obj.getData()) //ƒ (){ return this.str}
console.log(obj.getData) //ƒ (){return function(){return this.str}}
闭包的应用
- 设计模式中的单例模式
- for循环中的保留i的操作
- 防抖和节流
- 函数柯里化
10、深拷贝,浅拷贝
数值类型在栈内存存储,会实现深拷贝
引用类型在栈、堆存储,栈存储的是指向堆的地址,浅拷贝导致obj1和obj2指向同一个地址,得用具体的方法才能实现深拷贝,方法各有优缺点
第一种、JSON.parse(JSON.stringify())
问题:函数无法拷贝; 正则无法拷贝;undefined 无法拷贝
优点: 二级以下也可以实现深拷贝
let obj1 = {a:1,say(){console.log('1')},reg:/\d/,data:undefined,person:{name:"wl"}
}
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.person.name = "lxy"; //拷贝之后修改
console.log(obj2)
第二种、object.assign()
优点;可以拷贝函数;可以拷贝正则 ;可以拷贝undefined
问题:二级以下无法实现深拷贝
let obj2 = {}Object.assign(obj2,obj1)
第三种、递归
优点:可以拷贝函数;可以拷贝正则 ;可以拷贝undefined,二级以下可拷贝
var obj= { "name":"豪豪", "age":22, "job":"程序员", "height":175,"type":{"character":"tender"}}
obj.__proto__.say=function(){ };
function deepCopy(obj){var copyObj={ };for(var key in obj){if(obj.hasOwnProperty(key) == true){if(obj[key] instanceof Object){copyObj[key] = deepCopy(obj[key])}else{copyObj[key] = obj[key]}}}return copyObj;
}
var obj2 = deepCopy(obj)
console.log(obj2)
11、js常见的内存泄漏
程序中己动态分配的堆内存由于某种原因程序未释放或无法释放引发的各种问题
js中可能出现的内存泄漏情况:结果:变慢,崩溃,延迟大等
原因:
意外的全局变量
dom 清空时,还存在引用
定时器未清除
子元素存在引起的内存泄露
闭包
12 、js垃圾回收方式
1)怎么确定是垃圾:当一个对象没有任何的变量引用指向它的时候,再也无法操作它,这种对象在堆内存中存储过多时,会导致内存卡顿,就需要被清理
2)回收目的:防止内存泄漏(已经不需要的某一块内存还一直存在着),垃圾回收机制就是不停歇的寻找这些不再使用的变量,并且释放掉它所指向的内存。
3)怎么清除:JS垃圾回收机制自己回收
①标记清除:大部分浏览器使用这种垃圾回收,当变量进入执行环境(声明变量)的时候,垃圾回收器将该变量进行了标记,当该变量离开环境的时候,将其再度标记,随之进行删除。
②引用计数:这种方式常常会引起内存的泄露,主要存在于低版本的浏览器。它的机制就是跟踪某一个值得引用次数,当声明一个变量并且将一个引用类型赋值给变量得时候引
13、防抖节流
一个函数执行一次后,只有大于设定的执行周期才能执行第二次
在规定时间内,只让函数触发的第一次生效,后面不生效
防抖:设置setTimeout,在一定时间间隔内,多次触发变成一次触发
function debounce(fn,delay) {var timer = null;return function () {//清除上一次的延迟器clearTimeout(timer)//重新设置新的延时器timer = setTimeout(function () {fn.apply(this)},delay);}
}
document.getElementById('btn').onclick = debounce(function () {console.log("当前事件被触发流"+Date.now())
},1000)节流:减少一段时间的触发频率
function throttle(fn,delay) {var lasttime =0;return function () {var nowTime = Date.now();if(nowTime-lasttime > delay){fn.call(this);lasttime = nowTime;}}
}
document.onscroll = throttle(function () {console.log('throttle函数被触发流'+Date.now())
},200);
14、作用域与作用域链
规定变量和函数的可使用范围称作作用域,分两种,全局作用域和函数作用域
全局作用域
打开页面时,全局作用域创建,关闭页面时全局作用域销毁
创建的变量,是windows的属性
创建的函数,是windows的方法
变量要提前声明,再使用。function函数声明和var会提前被浏览器解析到,所以,调用的位置在创建函数前和后都能找到对应的定义。
函数作用域
调用函数时,函数作用域创建,调用结束,函数作用域销毁
函数作用域可以访问到全局作用域 ;全局作用域访问不到函数作用域
在函数作用域中操作一个变量,会在自己作用域范围找,没有,就去上一层找
作用域链:每个函数都有一个作用域链,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链。
15、原型、原型链
所有的函数都有prototype属性(原型),显示原型,定义函数时自动添加
所有的对象都有__proto__属性,隐式原型,创建对象时自动添加
显示原型与隐示原型
student.__proto__ === Student.prototype //true
隐式原型 显示原型
在Javascript中,每个函数都有一个原型属性prototype指向自身的原型,而由这个函数创建的对象也有一个proto属性指向这个原型,而函数的原型是一个对象,所以这个对象也会有一个proto指向自己的原型,这样逐层深入直到Object对象的原型,这样就形成了原型链。
16、javaScript页面跳转,页面重定向
window.location.replace("url") //不保存历史数据,不能回退到上一个页面
window.location.href="url" //保存历史记录,可用回退到上一个页面
window.open('url') //重新打开一个浏览器页面//单击实现页面跳转
function to () {let route = router.resolve({name:'detail', query:{id:'detail/1'}});window.open(route.href, '_blank'); //重新打开一个页面
}
replace的优势是不会跳转记录并不会保留在历史会话中,这就是说用户可以通过后退按钮回到上一个正常页面,而不是进入到无休止的回退→跳转的流程。
如果是想模拟用户点击链接进行跳转,建议使用window.location.href
如果是想模拟HTTP重定向,建议使用window.location.replace()
17、ajax如何使用
用来实现异步请求,好处是在不加载整个页面的情况下实现局部网页加载
一个完整的请求包含5个步骤
- 创建XMLHTTPRequest对象
- 使用open方法创建http请求,并设置请求地址xhr.open(get/post,url,async,true(异步),false(同步))经常使用前三个参数
- 设置发送的数据,用send发送请求
- 注册事件(给ajax设置事件)
- 获取响应并更新页面
最实用的异步请求是axios
var xhr = new XMLHttpRequest()
xhr.open('get', 'http://127.0.0.1:3000/ajax')
xhr.send()
xhr.onload = function() {console.log(xhr.responseText)}
18、Date
1、创建:var date = new Date();
2、方法:tolocaleString():返回当前data对象对应的时间本地字符串格式getTime();获取毫秒值。返回当前时期对象描述的时间到1970.1.1零点的毫秒值
19、Math
1、创建*特点:Math对象不用创建,直接使用。 Math.方法名();2、方法random():返回0-1之间的随机数;[0.0-1.0)ceil(x):对数进行下舍入,向上取整floor(x):对数进行上舍入,向下取整round(x):把数四舍五入为最接近的整数3、属性 PIparseInt(125.8)->125直接砍掉小数Math.ceil(Math.random()*10); // 获取从 1 到 10 的随机整数,取 0 的概率极小。
Math.round(Math.random()); // 可均衡获取 0 到 1 的随机整数。
Math.floor(Math.random()*10); // 可均衡获取 0 到 9 的随机整数。
Math.round(Math.random()*10); // 基本均衡获取 0 到 10 的随机整数,其中获取最小值 0 和最大值 10 的几率少一半。
20、string
trim()
repeat()
match()
indexOf()返回字符串索引指定字符第一次出现的位置
lastIndexOf()返回字符串索引指定字符最后一次出现的位置
includes() 字符串中有没有包含指定字符,有返回true无返回false 区分大小写
let ss = 'hello'
ss.substr(1,4) //ello
ss.substring(1,4) //ell 区别:substr(取头取尾) substring(取头不取尾)let a = ' wdsjs'
console.log(a.match(/s/g).join('')) //ss
console.log(a.indexOf('d')) //1
console.log(a.lastIndexOf('s')) //4
console.log(a.includes('j')) //true
console.log(a.trim()) //删除字符串两端的空白符
console.log(a.replace('s','x')) // wdxjs
console.log(a.replace(/s/g,'1')) //wd1j1
21、Array数组方法
返回新数组的方法:filter 、concat、 slice
添加数据:array[0] = 1;array.push(2,3,4)
array.length 数组长度
array[array.length] = 678 //这个方法总给数组最后一个赋值
arr.push()/arr.pop() 末尾推入和弹出,改变原数组, 返回是推入/弹出值的元素
arr.unshift()/arr.shift():头部推入和弹出,改变原数组,返回操作项,只能操作一个数
arr.concat() 连接两个数组 返回值为连接后的新数组,不影响原数组, 浅拷贝
arr.sort()/arr.reverse() 排序/反转,改变原数组,返回操作项,
str.split() 将字符串转化为数组
slice(start, end) : 返回截断后的新数组,不改变原数组
splice(start,number,value…): 返回删除元素组成的数组,value 为插入项,改变原数组,将原数组从索引往后数n个删除并返回切出来的arr.forEach(callback) 遍历数组,无return 即使有return,也不会返回任何值,
arr.map(callback) 映射数组(遍历数组),有return 返回一个新数组 。
arr.filter(callback) 过滤数组,返回一个满足要求的数组 var arr = [2,4,6,23,12,4];var newArr = arr.filter(item => item>20)
arr.indexOf(value, fromIndex)/arr.lastIndexOf(value, fromIndex) // 查找数组项,返回对应的下标
reduce / reduceRight(fn(prev,cur),defaultPrev) //两两执行,prev 为上次化简函数的return 值,cur 为当前值(从第二项开始)
arr.includes(item) //includes判断数组有没有item,有返回true,没有返回false
数组对象删除指定值
var list = [{"key":'1',"value":"预约"},{"key":'2',"value":"预约2"},{"key":'3',"value":"预约3"}]
for (let i=0;i<list.length;i++){if((list[i].key).indexOf('1')>-1){index = i;list.splice(index,1)}
}
list删除指定的key为1
数组去重练习,也可用set集合特点
var arr = [2,3,4,5,4,3,2,3,2]
for(i=0;i<=arr.length;i++){console.log(arr[i])for(j=i+1;j<=arr.length;j++){if(arr[i]==arr[j]){arr.splice(j,1)}}
}
数组的遍历
let arr = [1,2,3,4,5,6]
//for of
for (let i=0;i<arr.length;i++){console.log(i)
}
//forEach
arr.forEach(function (item,index,array) {console.log(item,index,array) //1 0 Array(5)[1, 2, 3, 4, 5]
})
//map函数返回新数组,不改变原数组,接收参数和foeEach一样,
var array = arr.map(function (item ){ console.log(item*item,index,array) //1 0 (5) [1, 2, 3, 4, 5]return item*item //给数组的每个值做平方运算}) //array: [1, 4, 9, 16, 25]
//filter遍历
Array.prototype.filter = Array.prototype.filter ||function (fn,context) {var arrs = []for(let i=0,length=this.length;i<length;i++){if(typeof fn === 'function' && Object.prototype.hasOwnProperty.call(this,i)){fn.call(context,this[i],i,this) && arrs.push(this[i])}}return arrs;
}
//some函数
//every函数
注:map函数的回调函数中要有return返回值
22、js对象
对象,是一种复合数据类型,可以保存多个不同数据类型的属性
对象就像一个塑料袋,把不同数据类型的属性封装到一起,使其之间具有联系
对象的分类
内建对象:在ES中定义的,Math,String,Function,Number
宿主对象:在JS运行环境中提供,BOM,DOM
自定义对象:开发自己定义怎么使用对象呢
1、创建对象 var obj = new Object()
2、给对象赋值 obj.name = "wl"
3、取对象的值 obj.属性名
4、修改对象的属性值 obj.属性名 = 属性值
5、删除对象的属性 delete obj.属性名对象的属性名定义,可以是任意命名
对象与变量的存储变量存在栈内存中,存变量与值对象存在堆内存,在堆内存开辟存储空间,定义的对象引用在栈内存存储新建的对象的指向地址,指向存放对象的堆内存
obj[propName]= value 使用['属性名']的方式
23、异步编程实现方法
1)回调函数
- 优点:简单、容易理解
- 缺点:不利于维护、代码耦合高
2)事件监听
- 优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数
- 缺点:事件驱动型,流程不够清晰
3)发布/订阅(观察者模式)
- 类似于事件监听,但是可以通过‘消息中心’,了解现在有多少发布者,多少订阅者
4)promise
promise有三个状态:pending、resolve、reject,三个状态的转换
const p1 = new Promise((resolve,reject) => { //promise的状态pending})const p2 = new Promise((resolve, reject) => { //promise的状态是resolve,===fulfilledsetTimeout(()=>{resolve()},10000)})const p3 = new Promise(((resolve, reject) => { //promise的状态是rejectreject()}))
快捷创建promise
const p1 = Promise.resolve()
const p2 = Promise.reject()
p1.then(()=>{throw new Error('err')console.log('p1 then')
}).catch(()=>{console.log('p1 catch')
})
then、catch
没有抛出异常 p.then、p.catch返回都是resolved状态的Promise
抛出异常 返回的都是一个rejected 状态的Promise
例子
const pp = Promise.resolve()pp.then(()=>{console.log(1)throw new Error()}).catch(()=>{console.log(2)}).then(()=>{console.log(3)})
1、2、3 //结果
这个promise可以解决异步的问题,本身不能说promise是异步的 ,把一层一层向内嵌套调用的方法,给拉成一串连续调用的方法,promise成为js的原生的内容,具体使用的时候,要包装一下,使用第三方,一些浏览器不支持它
- 优点:可以利用 then 方法,进行链式写法;可以书写错误时的回调函数
promise是用来解决两个问题的:
1.回调,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
2.promise可以支持多并发的请求,获取并发请求中的数据
- 缺点:
1)无法取消Promise,一旦新建它就会立即执行,无法中途取消
2)如果不设置回调函数,Promise内部抛出的错误,不会反映到外部
3)当处于pending(等待)状态时,无法得知目前进展到哪一个阶段,是刚刚开始还是即将
const promise = new Promise((resolve,reject) => {let num = Math.random();console.log(num);if(num>0.5){resolve("num="+num);}else {reject("num="+num);}
});
promise.then(msg = > {alert("success:"+msg);
}).catch(msg =>{alert("error:"+msg);
})
5)Generator函数
- 优点:函数体内外的数据交换、错误处理机制
- 缺点:流程管理不方便
6)await和async函数
await关键字
1)await只能在async函数内部使用:不能放在普通函数里面,否则会报错;
2)await关键字后面跟Promise对象:在Pending状态时,相应的协程会交出控制权,进入等待状态,这是协程的本质;不加 return
3)await是async wait的意思: wait的是resolve(data)的消息,并把数据data返回,比如下面代码中,当Promise对象由Pending变为Resolved的时候,变量a就等于data,然后再顺序执行下面的语句console.log(a),这真的是等待,真的是顺序执行,表现和同步代码几乎一模一样;
async init(){const params = {pageLength: this.page.pageLength,flag: this.page.flag,rowKey: this.page.rowKey,spacecraftId: this.spacecraft.id}let {data, code, message} = await driftPYHList(params);if(code === 200){this.table.data = data.list;// this.dataLength = data.list.length;}
},
promise与async await区别
①Promise的出现解决了传统callback函数导致的“地域回调”问题,但它的语法导致了它向纵向发展行成了一个回调链,遇到复杂的业务场景,这样的语法显然也是不美观的。而async await代码看起来会简洁些,使得异步代码看起来像同步代码,await的本质是可以提供等同于”同步效果“的等待异步返回能力的语法糖,只有这一句代码执行完,才会执行下一句。
②async await与Promise一样,是非阻塞的。
③async await是基于Promise实现的,可以说是改良版的Promise,它不能用于普通的回调函数。
注:什么是单线程,和异步的关系?
js单线程
因为JS里面有可视的Dom,如果是多线程的话,这个线程正在删除DOM节点,另一个线程正在编辑Dom节点,导致浏览器不知道该听谁的,为了避免DOM渲染冲突
JS运行机制
1、首先判断JS是同步还是异步,同步就进入主进程,异步就进入event table
2、异步任务在event table中注册函数,当满足触发条件后,被推入event queue
3、同步任务进入主线程后一直执行,直到主线程空闲时,才会去event queue中查看是否有可执行
的异步任务,如果有就推入主进程中
以上三步循环执行,这就是事件循环event loop
解决方案:异步
24、如何解决跨域
浏览器的同源策略:协议、端口、域名必须完全一致,只要一个不一样,就会跨域
有三种解决方案:
1、JSONP:利用动态创建script标签请求后端接口地址,然后传递callback参数,后端接收callback。经过处理,返回callback函数调用的形式,callback中的参数就是json
2、CROS(跨域资源共享):由后端工程师设置后端代码来实现前端跨域请求
3、服务器代理:VUE3中有proxyTable配置跨域
4、nodejs中间件代理跨域
var script = document.createElement('script'); //创建script标签
function getData(data) { //设置回调函数console.log('data');
}
script.src = "http://localhost:3000?callback=getData";//设置script的src属性,设置请求地址
document.body.appendChild(script); //让script生效
注:请解释JSONP的工作原理,以及它为什么不是真正的AJAX?
JSONP(JSON with Padding)是一个简单高效的跨域方式,HTML中的script标签可以加载并执行其他域的javascript,于是我们可以通过script标记来动态加载其他域的资源,例如我要从域A的页面pageA加载域B的数据,那么在域B的页面pageB中我以JavaScript的形式声明pageA需要的数据,然后在pageA中用script标签把pageB加载进来,那么pageB中的脚本就会得以执行。JSONP在此基础上加入了回调函数,pageB加载完之后会执行pageA中定义的函数,所需要的数据会以参数的形式传递给该函数。JSONP易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以算改页面内容,截获敏感数据,但是在受信任的双方传递数据,JSONP是非常合适的选择。
AJAX是不跨域的,而JSONP是一个是跨域的,还有就是二者接收参数形式不一样!
let proxyObj= {}
proxyObj['/']={ws:false, //websockettarget:'http://localhost:8081',changeOrigin:true, //发送请求头host会被设置targetpathRewrite:{ //不重写请求地址'^/':'/'}
}
module.exports={devServer:{host:'localhost',port:8080,proxy:proxyObj}
}
25、Global
1、特点:全局变量,这个Global中封装的方法不需要对象就可以直接调用。方法名();
2、方法:
encodeURI():url编码 decodeURI():url解码
encodeURIComponent():url编码 decodeURIComponent():url解码
eval() //将JS字符串,并把它作为脚本代码来执行
var str ="cdsf";
var encode = encodeURI(str);
document.write(encode+"<br>");
var decode = decodeURI(encode);
document.write(decode+"<br>");
26、Unicode与utf-8区别
ASCII是127个的字符集,A65 a97
Unicode 是“字符集”,UTF-8 是“编码规则”,1992年诞生。
Unicode给每个字符都定义了对应的编码,编码范围 0x000000-0x10FFFF,有110多万,每个字符都有唯一的Unicode编号。编号是16进制,前面加U+,例如:“马”的 Unicode 是U+9A6C。Unicode 就相当于一张表,建立了字符与编号之间的联系。
编码规则定义了从字符到储存在计算机的内容
UTF-8,是一套以8位为一个编码单位的可变长编码,会将一个码位编码为1到4个字节。
在JS中的用法:\u编码:是16进制 \u2620,查询Unicode的函数:js的codePointAt函数
在网页中的用法:&#编码:编码是10进制 ☠
必须把unicode从16进制转化为10进制,
UTF-8 的编码规则是:
UTF-8 就是使用变长字节表示,顾名思义,就是使用的字节数可变,这个变化是根据 Unicode 编号的大小有关,编号小的使用的字节就少,编号大的使用的字节就多。使用的字节个数从 1 到 4 个不等。
- 对于单字节的符号,字节的第一位设为 0,后面的7位为这个符号的 Unicode 码,因此对于英文字母,UTF-8 编码和 ASCII码是相同的。
- 对于n字节的符号(n>1),第一个字节的前 n 位都设为 1,第 n+1 位设为 0,后面字节的前两位一律设为10,剩下的没有提及的二进制位,全部为这个符号的 Unicode 码 。
优点:兼容ASCII
节约空间
27、严格模式的限制
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用 with 语句
- 禁止 this 指向全局对象
28、性能优化
更快的网络通道
1、服务器通信层面,使用 CDN,全局负载均衡和缓存系统
2、资源合并、域名分片
3、使用http缓存,强缓存,协商缓存
4、数据压缩层面-压缩
①gzip与新的br
代码文件压缩
②HTML/CSS/JS中的注释、空格、长变量名等等
静态资源
③字体图标,
去除元数据,缩小尺寸及分辨率,使用jpg或者webp格式
④头与报文
httpl.1中减少不必要的头
·减少cookie数据量
5、使用http2
更高效的数据处理
性能分析工具:
ab-c客户端数 -n请求次数 -t持续时间地址
node-prof.\http.js
node–prof-process.\isoxxxxxxx-v8.log>xxxx.txt
Chrome Devtool
https:/www.webpagetest.org/
前端代码
1:HTML 语义化标签加强DOM解析
2:多使用伪元素,减少JS多DOM的查找遍历
3:能用HTML/CSS实现的效果就不要用JS,js会调引擎
4:逻辑与展示解耦,避免不必要的JS引擎启动
5:减少作用域查找和闭包,避免==,使用块级作用域
客户端渲染方案(CSR)
“白屏”时间更长,用户体验不好
HTML中无内容,SEO不友好
服务端渲染(SSR)
主流服务端渲染工具
Next.js //采用 React + Next + Webpack 的技术栈做 SSR 渲染。
Nuxt.js //采用 Vue + Nuxt + Webpack 的技术栈做 SSR 渲染
静态站点生成方案,专门的SSG方案(框架)
Gatsby,例如:https://reactis.org
Gridsome
Web类型应用的优化方式有很多,但是大体分两类…
从加载层面,我们可以…
从执行层面,我们可以使用…
减少 HTTP 请求数
减少 DNS 查询
避免重定向
图片懒加载
使用外部 JavaScript 和 CSS
压缩 JavaScript、CSS、字体、图片等
优化 CSS Sprite
使用 iconfont
多域名分发划分内容到不同域名
尽量减少 iframe 使用
避免图片 src 为空
把样式表放在 link 中
29、负载均衡
单台服务器共同协作,不让其中某一台或几台超额工作,发挥服务器的最大作用
http 重定向负载均衡:调度者根据策略选择服务器以 302 响应请求,缺点只有第一次有效果,后续操作维持在该服务器 dns 负载均衡:解析域名时,访问多个 ip 服务器中的一个(可监控性较弱)原因 - 避免 DOM 渲染的冲突
反向代理负载均衡:访问统一的服务器,由服务器进行调度访问实际的某个服务器,对统一的服务器要求大,性能受到 服务器群的数量
30、什么是执行栈,什么是执行上下文?
1)执行上下文分为:
①全局执行上下文
创建一个全局的window对象,并规定this指向window,执行js的时候就压入栈底,关闭浏览器的时候才弹出
②函数执行上下文
每次函数调用时,都会新创建一个函数执行上下文
执行上下文分为创建阶段和执行阶段
*创建阶段:函数环境会创建变量对象:arguments对象(并赋值)、函数声明(并赋值)、变量声明(不赋值),函数表达式声明(不赋值);会确定this指向;会确定作用域
*执行阶段:变量赋值、函数表达式赋值,使变量对象编程活跃对象
③eval执行上下文
2)执行栈:
首先栈特点:先进后出
当进入一个执行环境,就会创建出它的执行上下文,然后进行压栈,当程序执行完成时,它的执行上下文就会被销毁,进行弹栈。
栈底永远是全局环境的执行上下文,栈顶永远是正在执行函数的执行上下文
只有浏览器关闭的时候全局执行上下文才会弹出
31、JS 中的常用的继承方式
原型继承、组合继承、寄生组合继承、ES6的extend
原型继承
把父类的实例作为子类的原型 缺点:子类的实例共享了父类构造函数的引用属性 不能传参
var person = {friends: ["a", "b", "c", "d"]}var p1 = Object.create(person)p1.friends.push("aaa")
组合继承
在子函数中运行父函数,但是要利用call把this改变一下, 再在子函数的prototype里面new Father() ,使Father的原型中的方法也得到继承,最后改变Son的原型中的constructor
缺点:调用了两次父类的构造函数,造成了不必要的消耗,父类方法可以复用 优点可传参,不共享父类引用属性
function Father(name) {this.name = namethis.hobby = ["篮球", "足球", "乒乓球"]
}
Father.prototype.getName = function () {console.log(this.name);}
function Son(name, age) {Father.call(this, name)this.age = age
}
Son.prototype = new Father()
Son.prototype.constructor = Son
var s = new Son("ming", 20)
console.log(s);
寄生组合继承
function Father(name) {this.name = namethis.hobby = ["篮球", "足球", "乒乓球"]
}
Father.prototype.getName = function () {console.log(this.name);
}
function Son(name, age) {Father.call(this, name)this.age = age
}
Son.prototype = Object.create(Father.prototype)
Son.prototype.constructor = Son
var s2 = new Son("ming", 18)
console.log(s2);
extend
子类只要继承父类,可以不写 constructor ,一旦写了,则在 constructor 中的第一句话,必须是 super 。
class Son3 extends Father { constructor(y) {super(200) // super(200) => Father.call(this,200)this.y = y}
}
32、宏任务和微任务,如何执行
执行一个宏任务,过程中如果遇到微任务,就将其放到微任务的【事件队列】里
当前宏任务执行完成后,会查看微任务的【事件队列】,并将里面全部的微任务依次执行完
重复以上2步骤,结合event loop(1) event loop(2) ,就是更为准确的JS执行机制了。
微任务与宏任务都是异步,微任务优先级高
1)宏任务:script、setTimeOut、setInterval、setImmediate、requrestAnimationFrame
1.宏任务所处的队列就是宏任务队列
2.第一个宏任务队列中只有一个任务:执行主线程的js代码
3.宏任务可以有多个
4.宏队列任务执行完后,先查看微任务队列并将其执行完;如果没有查看是否有宏任务队列
微任务:promise.then、process.nextTick、Object.observe、MutationObserver
1.微任务所处的队列就是微任务队列
2.只有一个微任务队列
3.在上一个任务队列执行定毕后如果有微任务队列就会执行微任务队列中的所有任务
注意:Promise是同步任务
2)怎么执行的
执行宏任务script,
进入script后,所有的同步任务主线程执行
所有宏任务放入宏任务执行队列
所有微任务放入微任务执行队列
先清空微任务队列,
再取一个宏任务,执行,再清空微任务队列
依次循环
案例
var date = new Date()
console.log(1,new Date() - date) //同步
setTimeout(()=>{console.log(2, new Date() - date) //添加到宏任务
},500)
Promise.resolve().then(console.log(3, new Date() - date) //.then立即执行
)
Promise.resolve().then(()=>{console.log(4, new Date() - date) //添加到微任务队列
})
console.log(5, new Date() - date) //同步
1 -0 //结果
3 -4
5 -4
4 -5
2 -517
33、nextTick原理
nextTick 就是设置一个回调,用于异步执行。
就是把你设置的回调放在 setTimeout 中执行,这样就算异步了,等待当时同步代码执行完毕再执行。
Vue实现nextTick的原理
在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,是vue的全局函数,用来处理DOM操作
34、exports和module.exports有什么区别?
导出方式不一样
exports.xxx='xxx'
module.export = {}
exports是module.exports的引用,两个指向的是用一个地址,而require能看到的只有module.exports
35、AMD 和 CMD 的区别,ES6 Module 和 commonjs 的区别
模块化 | 代表应用 | 特点 |
---|---|---|
AMD | require.js | 1. AMD的api默认一个当多个用 ;2. 依赖前置,异步执行 |
CMD | sea.js | 1. CMD的api严格区分,推崇职责单一 ;2. 依赖就近,按需加载,同步执行 |
ES6和commonjs的区别
Commonjs是拷贝输出,ES6模块化是引用输出
Commonjs是运行时加载,ES6模块化是编译时输出接口
Commonjs是单个值导出,ES6模块化可以多个值导出
Commonjs是动态语法可写在函数体中,ES6模块化静态语法只能写在顶层
Commonjs的this是模块化,ES6模块化的this是undefined
commonjs:同步运行,不适用于前端浏览器
var math = require('math')
math.add(1,2)
因为,在第一行运行完,必须等math.js加载完成。而加载时间取决于网速,等待时间浏览器会处于假死状态,因此,浏览器的模块不能采用同步加载,只能采用异步加载,这就是AMD规范诞生的背景
36、函数柯里化
是把接收多个参数的函数变换成接收一个单一参数的函数,并且返回接收余下的参数而且返回结果的新函数技术。
function add(x,y){return x+y
}
function curryingAdd(x){return function(y){return x+y}
}
add(1,2) //3
curryingAdd(1)(2) //3
1)如果参数同名,柯里化实现 参数复用
2)延迟执行
3)箭头函数使用柯里化
4)Function.prototype.bind 函数柯里化
function sayKey(key){console.log(this[key])
}
const person={name:'Sunshine',age:23
}
// call 不是柯里化
sayKey.call(person,'name') // 立即输出 Sunshine
// bind是柯里化
const say = sayKey.bind(person) // 不执行
say('name') // 输出 Sunshine
37、websocket
后台服务重启,前端socket断了
此时,刷新页面才能建立连接,但大屏可视化不允许刷新页面,前端需要发现socket断了,并发起连接
解决办法:在webSocket的生命周期onclose和onerror时调用重连函数,增加心跳检测。
如果连接上,就不再重连,直接return出去
38. 设计模式知道那些?具体用法
单例模式:就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象。
观察者模式: 观察者的使用场合就是:当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式。
工厂模式解决了重复实例化的问题,缺点,创建不同对象其中属性和方法都会重复建立,消耗内存;还有函数识别问题等等。
39. == 与 ===的区别
== 用于比较两者是否相等,忽略数据类型。
=== 用于更严谨的比较,值和值的数据类型都需要同时比较。
40、JSON序列化 与 反序列化
JSON序列化指:将JSON对象 ======> JSON字符串
法1:JSON.stringify()
let data = {name:'ww',age:33,agent:null,ccc:undefined,y:Object}console.log(JSON.stringify(data)) //{"name":"ww","age":33,"agent":null}
- 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
- 布尔值,字符串,数字的包装对象在序列化过程中会被转换为对应的原始值。
- JSON.stringify 不能处理函数、undefinded
法2:toJSON() 对象自定义的函数
toJSON()函数用于更精准的控制序列化,可以看做是对 stringify() 函数的补充。
let data = {name:'ww',age:33,toJSON:function () {return{Name:this.name,Age:this.age}}}console.log(JSON.stringify(data)) //{"Name":"ww","Age":33}
JSON反序列化:将JSON字符串 ====== > JSON对象
JSON.parse()
eval()
let json = '{"name":"sss"}'
console.log(eval("(" + json + ")")) //{name: 'sss'}
console.log(JSON.parse(json)) //{name: 'sss'}
41、indexOf与includes区别
includes //可检测NaN
indexOf //不能检测NaN
let arr = [1,2,NaN,undefined,'22']
arr.indexOf(NaN) //-1
arr.includes(NaN) //true
42、JS延迟加载的方法有哪些
1、<script async src="script.js"></script>:
给script标签加async属性,则加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)
2、<script defer src="script.js"></script>:
给script标签加defer属性,加载后续文档元素的过程将和script.js的加载并行进行(异步),但是script.js的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成
3、动态创建script标签:
等到DOMContentLoaded 事件触发时,生成一个script标签,渲染到页面上
4、setTimeout定时器延迟代码执行
43、new操作符的原理
function myNew (fn,...argument){const obj = {name:'ww',age:11}obj.__proto__ = fn.prototypefn.apply(obj,argument)return obj
}
//1、创建空对象
//2、继承构造函数的原型
//3、this指向obj,并调用构造函数
//4、返回对象
44、9个高级JavaScript方法
- getBoundingClientRect
- IntersectionObserver
- createNodeIterator
- getComputedStyle
- requestAnimationFrame
- requestIdleCallback
- DOMContentLoaded
- MutationObserver
- Promise.any
45、JS获取鼠标点击下的innerHtml的值
<template v-for="(item,index) in state.letter" :key="index" ><span @click="letterSort($event)">{{item}}</span>
</template>
function letterSort(e) { //字母排序alert(e.target.innerHTML)
}
JS+BOM+DOM汇总相关推荐
- JS,BOM,DOM(六)
## JavaScript1. ECMAScript: 基础语法2. BOM3. DOM:1. 事件## DOM简单学习:* 功能: 控制html文档的内容* 代码: 获取页面标签(元素)对象 Ele ...
- js bom dom
javascript组成: 1. ECMAScript 基本语法. 2. BOM (浏览器对象模型) 3. DOM (文档对象模型) 转载于:https://www.cnblogs.com/jenta ...
- day03_js学习笔记_03_js的事件、js的BOM、js的DOM
day03_js学习笔记_03_js的事件.js的BOM.js的DOM ================================================================ ...
- js中DOM, DOCUMENT, BOM, WINDOW 区别
全栈工程师开发手册 (作者:栾鹏) js系列教程6-BOM操作全解 js系列教程7-DOM操作全解 js中DOM, DOCUMENT, BOM, WINDOW 区别 DOM 全称是 Document ...
- web前端-JS(DOM、BOM)
web前端-JS(DOM.BOM) 1. DOM- 操作元素 1.1 获取元素 1.2 事件基础 1.3 操作元素 1.3.1 改变元素的内容 1.3.2 常见元素的属性操作 1.3.3 表单元素的属 ...
- JS面试题汇总(四)
往期点这里:↓ JS面试题汇总(一) JS面试题汇总(二) JS面试题汇总(三) 31. JS 单线程还是多线程,如何显示异步操作 参考答案: JS 本身是单线程的,他是依靠浏览器完成的异步操作. 解 ...
- 【java学习之路】(javaWeb篇)005.Js之DOM、对象、函数上下文
节点树 节点[element]即为标签 概述:静态页面骨架是由标签组成,标签之间关系很像一颗大树,简称为节点树. 如下图:静态页面标签之间关系图,很像一颗大树,因为前端人称之为节点树. 认识DOM 概 ...
- 前段之BOM ----DOM
前段之BOM ----DOM 一.介绍 BOM(Browser Object Model)是指浏览器对象模型,它使 JavaScript 有能力与浏览器进行"对话". DOM (D ...
- 原生JS学习 DOM (案例)
文章目录 1.JS的DOM是什么? 2.DOM的用处 3.查询DOM对象 3.1 基础查询函数(常见DOM操作) 3.2 查询其他标签 3.3思考:备注:什么是标签?什么是节点? 3.4标签对象操作 ...
最新文章
- JSON.parse 函数应用 (复制备忘)
- windows7访问03文件服务器慢
- Echart的angularjs封装
- 传统方法怎么玩计算机审美
- 最常见的读入数据方法集锦
- Python Django 之 Views HttpRequest HttpReponse
- Win10的远程桌面
- bigdecimal 科学计数转普通计数_项目实践篇二:S71500高速脉冲计数及工程应用
- 营业执照编码验证规则(15位和18位)
- _itemmod_extract_enchant随机附魔提取
- jenkins AWS CodeDeploy不停机部署
- linux下自动删除文件夹,如何在Linux中自动删除或清理/tmp文件夹内容?
- Java面试官最爱问的垃圾回收机制,mysql密码忘记
- 如何重新认知性能优化及其度量方法
- 安卓多媒体开发!Android高级工程师面试实战,系列篇
- 未能加载文件或程序集“XXX.dll”或它的某个依赖项的解决方法
- linux下用vi,vim编辑时退出编辑模式(wq)无法保存退出
- 2023年EasyRecovery数据恢复还会收费吗?
- 纯 CSS 的多级菜单
- 奥塔在线:Centos下使用RPM方式安装JDK1.8
热门文章
- 知乎引流推广运营全攻略
- 【Stereo R-CNN 解读】基于立体R-CNN的自动驾驶三维目标检测
- infiniband获悉
- 自动控制原理第4章——根轨迹法(思维导图)
- CocosCreator Effect (Shader) - 斜条纹如何画
- 谁来帮帮我!!!急!急!急!
- 语音信号线性预测分析(MATLAB实战篇)
- HDU 2047 阿牛的EOF牛肉串的java实现思路
- win7系统老是弹窗怎么解决_win7系统右下角经常弹广告怎么办|win7系统右下角弹出广告的屏蔽方法...
- Win10系统VS2022开发环境中(X86)Win32汇编(MASM32)环境配置和一些示例源码及解释