因为本人仍是一个前端菜鸟,因此是很是有可能出错误的,热烈欢迎指正!javascript
运行在浏览器的V8引擎中的脚本语言,不要编译就能够由解释器直接运行的,此外变量松散定义,属于弱类型语言。html
<script>
元素中设置defer属性,至关于告诉浏览器马上下载,延迟执行。会等页面解析完后,按指定顺序执行原始类型有:boolean,string,number,null,undefined,symbol 6种。前端
null不是对象,typeof null会输出object,是由于之前32为系统会将000开头的表明为对象,但null表示为全零因此被错误判断成objectjava
1.原始类型存储的是值,引用类型存储的是指针。 2.原始数据类型直接存储在栈中,引用数据类型存储在堆中。node
undefined,string,number,boolean,object,function面试
typeof只能区分除null的原始类型,引用类型只能区分function。算法
在计算机中,数字以二进制形式存储。在JavaScript中数字采用IEEE754的双精度标准进行存储,由于存储空间有限,当出现没法整除的小数时会取一个近似值。编程
在0.1+0.2中0.1和0.2都是近似表示的,因此相加时两个近似值进行计算致使最后结果为0.3000,0000,0000,0004,此时对于JS来讲不够近似于0.3,因此出现了0.1+0.2!=0.3json
解决方法:parseFloat((0.1+0.2).toFixed(10)) === 0.3 // true后端
undefine: 表示变量被声明了但没有赋值。
null:变量被定义赋值了,可是为空,没有任何属性方法和值
做为属性名的使用
var mySymbol=Symbol();
var a={};
a[mySymbol]='hello'
复制代码
==会进行类型转换后再比较,===不会,尽可能都用===.
如下两种状况能够用==
var obj={}
if(obj.a == null){
// 至关于obj.a===null || obj.a===undefined
}
复制代码
function fn(a, b){
if(b == null){
// 至关于b===null || b===undefined
}
}
复制代码
Object.is()能够说是升级版,Object.is(NaN,NaN)会返回true,Object.is(-0,+0)返回false
1.判断是否具备数组某些方法
if(arr.splice){}
2.instanceof(某些IE版本不正确)
arr instanceof Array
3.Array.isArray()
4.Object.prototype.toString.call(arr); // '[object Array]'
5.constructor方法
arr.constructor === Array
let arrayLike = {
'0' : 'a',
'1' : 'b',
'2' : 'c',
length : 3
};
let arr1 = Array.prototype.slice.call(arrayLike);
let arr2 = [].slice.call(arrayLike);
let arr3 = Array.from(arrayLike);
复制代码
// 会改变原数组
pop() // 末尾删除
push() // 末尾新增
shift() // 开头删除
unshift() // 开头新增
reverse() // 数组反转
sort() // 排序
splice() // 修改数组(删除插入替换)
// 不会改变原数组
concat() // 合并数组
slice() // 选择数组的一部分
indexOf() // 顺序查找指定元素下标
lastIndexOf() // 倒序查找指定元素下标
复制代码
// 迭代方法
// every()查询数组是否每一项都知足条件
// some()查询数组中是否有知足条件的项
// filter()过滤,返回true的项组成的数组
// map()对每一项运行给定函数,返回每次函数调用结果组成的数组
// forEach()对每一项运行给定函数,无返回值
var numbers = [1,2,3,4,5,4,3,2,1];
numbers.every(function(item,index,array){
return item>2;
}) // false
numbers.some(function(item,index,array){
return item>2;
}) // true
numbers.filter(function(item,index,array){
return item>2;
}) // [3,4,5,4,3]
numbers.map(function(item,index,array){
return item*2;
}) // [2,4,6,8,10,8,6,4,2]
numbers.forEach(function(item,index,array){
// 执行某些操做
}) // 无返回值
复制代码
// 归并方法
// reduce()从第一项开始逐个遍历到最后
// reduceRight()从最后一项开始向前遍历到第一项
var values = [1,2,3,4,5];
values.reduce(function(prev,cur,index,array){
return prev+cur;
}) // 15
// reduceRight()结果同样,顺序相反
复制代码
插入排序和快速排序结合的排序算法
[1,NaN,NaN]
由于parentInt须要两个参数(val,radix),radix表示解析进制,而map传入三个(element,index,array)致使对应的radix不合法致使解析错误。
function formatDate(dt){
if(!dt){
dt=new Date()
}
var year = dt.getFullYear();
var month = dt.getMonth()+1;
var day = dt.getDate();
if(month<10){
month= '0'+month;
}
if(day<0){
day = '0'+day;
}
var formatDt = year+'-'+month+'-'+day
return formatDt;
}
复制代码
getHour() // 返回时
getMinutes() // 返回分
getSeconds() // 返回秒
getDay() // 返回星期天数
getTime() // 返回毫秒数
复制代码
解析器会先读取函数声明,提高到最前。而函数表达式会等到执行到它所在的代码才真正被解释执行
// 函数声明
function sum(a,b){
return a+b;
}
// 函数表达式
var sum = function(a,b){
return a+b;
}
复制代码
this引用函数执行的环境对象,老是指向函数的直接调用者,在执行时才能肯定值
1.默认绑定,在浏览器中为window,在node中是global
2.隐式绑定 例:window.a()
3.显式绑定
4.new绑定
5.箭头函数
这里写的不是很详细,推荐看JavaScript深刻之史上最全--5种this绑定全面解析
相同点
不一样点
callee是arguments对象的一个属性,指向arguments对象的函数即当前函数。递归可使用arguments.callee()。 箭头函数中this做用域与函数外一致,且没有arguments对象,因此箭头函数没有callee
function factorial(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1)
}
}
复制代码
caller是函数对象的一个属性,指向调用当前函数的函数,好比A调用B,则B.caller指向A()。全局做用域下调用当前函数,caller的值为null
toFixed()按指定小数位返回数值的字符串表示
var num=10; num.toFixed(2); // '10.00'
// charAt()根据字符位置返回所在位置的字符串
// charCodeAt()根据字符位置返回所在位置字符串的字符编码
var str = 'hello world';
str.charAt(1); // 'e'
str.charCode(1); // '101'
// fromCharCode() 接收字符编码转为字符串
String.fromCharCode(104,101,108,108,111) //'hello'
// concat()将字符拼接起来获得新字符串
var str="hello"
str.concat(' world'); // "hello world"
// indexOf()和lastIndexOf() 返回字符位置
// trim() 删除空格
// toLowerCase() 转小写,toUpperCase() 转大写
// localeCompare() 根据字母表比较排序
复制代码
slice和substring接收的是起始位置和结束位置,substr接收的是起始位置和所要返回的字符串长度
对于负数,slice会将负数与字符串长度相加,substr会将负的第一个参数加上字符串长度,第二个参数转为0,substring会将全部负数转为0
join()将数组中的元素放入一个字符串中,split将字符串分割成数组
var arr=[1,2,3];
var str=arr.join('|'); // '1|2|3'
str.split('|'); // [1,2,3]
复制代码
URI编码方法
encodeURI和encodeURICcomponent encodeURI和decodeURICcomponent
eval的做用?
功能是将对于字符串解析出JS代码执行。要避免使用eval,不安全且很是消耗性能
var max=Math.max(3,54,32,16); // 54
复制代码
构造函数特色:函数名首字母大写,它就相似一个模板,能够new出多个实例
var a={} // var a=new Object()的语法糖
var a=[] // var a=new Array()的语法糖
function Foo(){} // var Foo=new Function()的语法糖
复制代码
instanceof判断引用类型属于哪一个构造函数
f instanceof Foo的判断逻辑:f的__proto__一层层往上,可否找到Foo.prototype。
可是由于原型链上全部特殊对象的__proto__最终都会指向Object.prototype,因此instanceof判断类型也不彻底准确
function _new(){
let obj = {};
let con=[].shift.call(arguments);
obj.__proto__ = con.prototype;
let res = con.apply(obj, arguments);
return res instanceof Object ? res : obj;
}
复制代码
更推荐字面量的方式建立对象,性能和可读性都更好。使用var o=new Object()和var o={}的区别是前者会调用构造函数
hasOwnProperty判断该对象自己是否有指定属性,不会到原型链上查找。
使用方法:object.hasOwnProperty(proName)
利用它能够循环对象自身属性
for(let item in f){
if(f.hasOwnProperty(item)){
console.log(item)
}
}
复制代码
访问一个对象的属性时,先在基本属性中查找,若是没有,再沿着__proto__这条链向上找,这就是原型链
function createPerson(name, age){
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function(){
console.log(this.name)
}
return o;
}
var person1 = createPerson('chen',21)
复制代码
没有显示建立对象,直接将属性方法赋给this,没有return语句
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name)
}
}
var person1 = new Person('chen',21)
复制代码
缺点:每一个方法都要在每一个实例上从新定义一遍,没法获得复用
function Person(){}
Person.prototype.name="chen"
Person.prototype.age=21
Person.prototype.sayName=function(){
console.log(this.name)
}
var person1 = new Person()
复制代码
缺点:全部实例都取得相同属性值
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype = {
constructor: Person,
sayName: function(){
console.log(this.name)
}
}
var person1=new Person('chen',21)
复制代码
JavaScript经过原型链实现继承
function Parent(){
this.name = 'parent'
}
Parent.prototype.sayName = function(){
return this.name
}
function Child(){
}
// 继承了Parent
Child.prototype = new Parent();
var child1=new Child();
child1.say();
复制代码
缺点:对象实例共享全部继承的属性和方法
function Parent(){
this.arr=[1,2,3]
}
function Child(){
// 继承了Parent
Parent.call(this)
}
var child1 = new Child();
child.arr.push(4); // [1,2,3,4]
var child2 = new Child();
child.arr; // [1,2,3]
复制代码
使用原型链继承共享的属性和方法,经过借用构造函数继承实例属性
function Parent(name){
this.name = name;
this.arr = [1,2,3]
}
Parent.prototype.sayName = function(){
console.log(this.name)
}
function Child(name,age){
// 继承属性
Parent.call(this, name)
this.age=age
}
// 继承方法
Child.prototype = new Parent()
Child.prototype.constructor = Child;
Child.prototype.sayAge = function(){
console.log(this.age)
}
var child1=new Child('chen',21);
child1.arr.push(4); //[1,2,3,4]
child1.sayName() // 'chen'
child1.sayAge() // 21
var child2=new Child('miao', 12)
child2.arr // [1,2,3]
child2.sayName() // "miao"
child2.sayAge() // 12
复制代码
缺点:不管在什么状况都会调用两次父构造函数,一次是建立子类型原型,另外一次是在子构造函数内部
var person = {
name: 'chen',
arr: [1,2,3]
}
var person1 = Object.create(person);
person1.name = 'run'
person1.arr.push(4)
var person2 = Object.create(person);
person2.name = 'miao'
person2.arr.push(5)
person.arr; // [1,2,3,4,5]
复制代码
function create(original){
// 经过调用函数建立一个新对象
var clone = object(original);
// 以某种方式加强对象
clone.sayHi = function(){
console.log('hi')
}
return clone;
}
var person = {
name: 'chen'
}
var person1 = create(person);
person1.sayHi();
复制代码
function Parent(name){
this.name = name;
this.arr = [1,2,3]
}
// 将共享的属性/方法放到原型上
Parent.prototype.sayName = function(){
console.log(this.name)
}
// 借用构造函数加强子类实例属性(支持传参和避免篡改)
function Child(name,age){
// 继承属性
Parent.call(this, name)
this.age=age
}
function inheritPrototype(Child, Parent){
var prototype=Object.create(Parent.prototype);
prototype.constructor=Child;
Child.prototype=prototype;
}
// 将父类原型指向子类
inheritPrototype(Child, Parent);
Child.prototype.sayAge=function(){
console.log(this.age)
}
var child1=new Child('chen',21);
child1.arr.push(4); //[1,2,3,4] 继承自父类实例属性
child1.sayName() // 'chen' 继承自父类原型方法
child1.sayAge() // 21 继承自子类原型方法
var child2=new Child('miao', 12)
child2.arr // [1,2,3]
child2.sayName() // "miao"
child2.sayAge() // 12
复制代码
class只是语法糖,本质是函数
class Parent{
constructor(value){
this.val=value
}
getValue(){
console.log(this.val)
}
}
class Child extends Parent{
constructor(value){
super(value)
this.val = value
}
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
复制代码
核心:使用extends代表继承自哪一个父类,而且在子类构造函数中必须使用super,能够看作是Parent.call(this,value)
面向过程就是分析出解决问题所需的步骤,而后用函数把这些步骤一步步实现,使用的时候一个个依次调用
面向对象是把构成问题的事务分解成各个对象,奖励对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
优势:易维护,可读性高,易扩展,继承性高,下降重复工做量,缩短了开发走起
闭包指有权访问另外一个函数内部变量的函数,当在函数内部定义了其余函数,也就建立了闭包
使用闭包能够模仿块级做用域
优势:能够避免全局变量的污染,实现封装和缓存;
缺点:闭包会常驻内存,增大内存使用量,使用不当很容易形成内存泄漏。解决方法:在退出函数以前,将不适用的局部变量设为null。
闭包最大的两个用处:1.能够读取函数内部的变量;2.使这些变量始终保存在内存中;3.封装对象的私有属性和私有方法
做用域链的做用是保证执行环境里有权访问的变量和函数是有序的,做用域链的变量只能享受访问,访问到window对象即被终止。
简单来讲,做用域就是变量和函数的可访问范围
alert(),prompt(),confirm(),open(),close(),print(),focus(),blur(),moveBy(),moveTo(),resizeBy(),resizeTo(),scrollBy(),scrollTo(),setInterval(),setTimeout(),clearInterval(),clearTimeout()
history.go(-1); // 后退一页
history.go(1); // 前进一页
history.back(); // 后退一页
history.forward(); // 前进一页
复制代码
var leftPos=(typeof window.screenLeft == 'number') ? window.screenLeft : window.screenX;
var topPos=(typeof window.screenTop == 'number') ? window.screenTop : window.screenY;
复制代码
moveTo():接收新位置的x,y坐标值
moveBy():接收在水平垂直方向上移动的像素数
outerWidth和outerHeight返回浏览器窗口自己的尺寸,innerWidth和innerHeight返回容器视图区的大小
使用navigator.userAgent
var ua = navigator.userAgent;
var isChrome = ua.indexOf('Chrome')
复制代码
使用location的属性
history.go(1)
复制代码
由于DOM属于渲染引擎的东西,JS又是JS引擎的东西,当咱们经过JS操做DOM的时候,涉及到两个线程间的通讯,并且操做DOM可能会带来重绘回流的状况,因此就致使了性能问题。
解决方法:
重绘是当节点改变样式而不影响布局,回流是当布局或几何属性须要改变
回流一定会发生重绘,回流的成本比重绘高
性能问题:1.改变window大小 2.改变字体 3.添加或删除样式 4.文字改变 5.定位或浮动 6.盒模型
注意事项:
parentNode.insertBefore(newNode, refNode)
parentNode表示父节点,newNode表示要添加的节点,refNode表示参照节点parent.replaceChild(newChild,oldChild)
element.setAttribute(name, value)
ele.style.color = 'red'
ele.style.setProperty('font-size', '16px')
ele.style.removeProperty('color')
复制代码
var style = document.createElement('style');
style.innerHTML='body{color:red;} #top{color:white;}';
document.head.appendChild(style);
复制代码
attribute是dom元素在文档中做为HTML标签拥有的属性
prototype是dom元素在JS中做为对象拥有的属性
dom.style.width/height
dom.currentStyle.width/height
window.getCompontedStyle(dom).width/height
dom.getBoundingClientRect().width/height
dom.offsetWidth/offsetHeight
element.onclick=function(){}
element.addEventListener('click',function(){},false)
element.addEventListener('keyup',function(){},false)
DOM0级事件就是将一个函数赋值给一个事件处理属性,缺点在于一个处理程序没法同时绑定多个处理函数。
DOM2级事件运行给一个程序添加多个处理函数,定义了addEventListener和removeEventListener两个方法,分别用于绑定和解绑事件,方法包含三个参数分别是绑定的事件处理的属性名称,处理函数,是否在捕获时执行事件
IE8如下使用attachEvent和detachEvent实现,不须要传入第三个参数,由于IE8如下只支持冒泡型事件
btn.attachEvent('onclick', showFn);
btn.detachEvent('onclick', showFn);
复制代码
DOM3级事件是在DOM2级事件的基础上添加不少事件类型如load,scroll,blur,focus,dbclick,mouseup,mousewheel,textInput,keydown,keypress,同时也容许使用者自定义一些事件。
<div onclick="clicked()"></div>
复制代码
优缺点:简单,但与HTML代码紧密耦合,更改不方便
document.onclick = function(){}; // 指定事件
docuemtn.onclick = null; // 删除事件
复制代码
优缺点:简单且跨浏览器
addEventListener('click', function(){},布尔值) // 指定事件
removeListener('click', function(){}, 布尔值) // 移除事件
复制代码
优缺点:能够添加多个监听函数,若是指定处理函数是匿名函数,则没法删除
attachEvent('onclick', function(){}) // 指定事件
detachEvent('click', function(){}) // 移除事件
复制代码
优缺点:能够添加多个监听函数,若是指定处理函数是匿名函数,则没法删除
attachEvent()第一个参数比addEventListener()的事件名多一个“on”;且没有第三个参数,由于IE事件模型只支持冒泡事件流
IE中事件处理程序处于全局做用域,其内的this会指向window,而DOM事件模型是做用于元素,其内的this执行所属元素
阻止冒泡
IE:cancelBubble=true
DOM: stopPropagation()
阻止元素默认事件
IE:returnValue=false
DOM:preventDefault()
事件目标
IE: srcElement DOM: target
var ev = ev || window.event;
document.docuemntElement.clientWidth || document.body.clientWidth
var target = ev.srcElement || ev.target
复制代码
addEventListener第三个参数为false,事件在冒泡时候执行,事件目标target一级一级往上冒泡
如何阻止事件冒泡
child.addEventListener('click', function(e){
console.log('目标事件')
e.stopPropagation();
}, false)
复制代码
事件捕获是自上而下执行的,将addEventListener第三个参数为true
DOM2级事件规定的事件流包括三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段。首先发送的是事件捕获,为截获事件提供了机会,而后是实际的目标接收到事件,最后一个阶段是冒泡阶段,能够在这个阶段对事件作出响应
window->docuemnt->html->body->...
一开始接收事件的window,window接收完之后给到document,第三个才是html标签,再就是body,而后在一级一级往下传。与之至关的就是冒泡,从当前元素到window的过程
var event = new Event('custome');
ev.addEventListener('custome', function(){
console.log('custome');
});
ev.dispatchEvent(event);
复制代码
mouseover:当鼠标移入元素或其子元素都会触发事件,因此有一个重复触发,冒泡的过程。对应的移除事件是mouseout
mouseenter: 当鼠标移入元素自己(不包含子元素)会触发事件,不会冒泡,对应的移除事件是mouseleave
事件代理(事件委托)把本来须要绑定的事件委托给父元素,让父元素担当事件监听的职务。原理是DOM元素的事件冒泡。
好处:能够提升性能,大量节省内存占用,减小事件注册,能够实现新增子对象时无需再次对其绑定
document.onload是在样式结构加载完才执行,window.onload()不只要样式结构加载完还要执行完全部样式图片资源文件所有加载完后才会触发
document.ready原生中无此方法,jQuery中有$().ready(),ready事件不要求页面全加载完,只须要加载完DOM结构便可触发。
JSON是JS的一个内置对象,也是一种轻量级的数据交换格式。 经常使用两个方法:
// 建立XMLHTTPRequest对象
var xhr = new XMLHttpRequest();
// 建立一个新的http请求
xhr.open("get", url, true)
// 设置响应HTTP请求状态变化的函数
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
// 获取异步调用返回的数据
alert(xhr.responseText)
}
}
}
// 发送HTTP请求
xhr.send(null);
复制代码
状态码readyState说明:0:未初始化,未调用send();1:已调用send(),正在发生请求;2:send()方法执行完毕,已经接收到所有响应内容;3:正在解析响应内容;4:解析完成,能够在客户端调用了
优势:1.经过异步模式,提高用户体验;2.优化了浏览器和服务器之间的传输,减小没必要要的数据往返,减小了带宽占用;3.Ajax在客户端运行,承担了一部分原本由服务器承担的工做,减小了大用户量下的服务器负载;4.Ajax能够实现局部刷新
缺点:1.Ajax暴露了与服务器交互的的细节;2.对搜索引擎的支持较弱;3.不容易调试
误区:咱们常认为GET请求参数的大小存在限制,而POST无限制
实际上HTTP协议没有限制GET/POST的请求长度限制,GET的最大长度限制是由于浏览器和WEB服务器限制了URL的长度。
GET和POST方法没有实质区别,只是报文格式不一样。
能够跨域的三个标签:<img><link><script>
跨域指经过JS在不一样的域之间进行数据传入或通讯。 协议,域名,端口有一个不一样就是不一样域
同源策略是为了防止CSRF攻击,它是利用用户的登陆态发起恶意请求。若是没有同源策略,网站能够被任意来源的Ajax访问到内容。
<script>
标签没有跨域限制的漏洞function jsonp(url, callback, success){
let script = docuemnt.createElement('scipt');
script.src = url;
script.async = true;
script.type = "text/javascript";
window[callback] = function(data){
success && success(data)
}
document.body.appendChild(script)
}
jsonp('http://xxx.com', 'callback', function(value){
console.log(value);
})
复制代码
JSONP使用简单,兼容性不错但仅限GET请求
a.test.com
和b.test.com
。在页面添加document.domain = 'test.com'
表示二级域名相同便可跨域// 发送消息
window.parent.postMessage('message', 'http://www.test.com')
// 接收消息
let mc=new MessageChannel()
mc.addEventListener('message', event => {
let origin = event.origin || event.originalEvent.origin;
if(origin === 'http://www.test.com'){
console.log('验证经过')
}
})
复制代码
window.name
答:
cookie,sessionStorage,localStorage,indexDB。
indexDB不限存储大小,不与服务器端通讯,除非主动删除不然一直存在。
Service Worker是运行在浏览器背后的独立线程,通常能够用来实现缓存功能,传输协议必须为https
箭头函数与普通函数的区别:
let nodeList = document.querySelectorAll('div')
let arr=[...nodeList]
复制代码
let arr1=[1,2,3]
let arr2=[4,5,6]
let arr3=[...arr1, ...arr2]
复制代码
利用了遍历对象内部的iterator接口,将for...of循环分解为最原始的for循环
Generator能够控制函数的执行
function *foo(x){
let y=2*(yield(x+1))
let z=yield(y/3)
return (x+y+z)
}
let it=foo(5)
it.next() // {value:6,done:false}
it.next(12)
it.next(13)
复制代码
Generator函数调用会返回一个迭代器,第一次next,函数停在yield(x+1)因此value=5+1=6; 第二次next,传入参数至关于上一个yield的值,即let y=2*12=24; let z=24/3=8;第三次next,传入参数至关于上一个yield的值,即let z=13,y=24,x=5,相加返回42
async就是将函数返回值使用Promise.resolve()包裹一下,和then中处理返回值同样,而且async只能搭配await使用 await其实就是generator加上Promise的语法糖,且内部实现了自动执行generator
setTimeout延后执行,setInterval每隔一段时间执行一次回调函数,以上两种都不能保证在预期时间执行任务 requestAnimationFrame自带函数节流功能,且延时效果是精确的
const PENDGIN='pending'
const RESOLVED='resolved'
const REJECTED='rejected'
function myPromise(fn){
const that=this
that.state=PENDING
that.value=null
that.resolvedCallbacks=[]
that.rejectedCallbacks=[]
function resolve(value){
if(value instanceof myPromise){
return value.then(resolve, reject)
}
setTimeout(()=>{
if(that.state===PENDING){
that.state=RESOLVED;
that.value=value;
that.resolvedCallbacks.map(cb => cb(that.value))
}
},0)
}
function reject(error){
setTimeout(()=>{
if(that.state===PENDING){
that.state=REJECTED
that.value=value
that.rejectedCallbacks.map(cb => cb(that.value))
}
},0)
}
try{
fn(resolve, reject)
}catch(e){
reject(e)
}
}
myPromise.prototype.then=function(onFulfilled, onRejected){
const that=this
onFulfilled=typeof onFulfilled==='function'?onFulfilled: v=>v
onRejected=typeof onRejected==='function'?onRejected: r=>{throw r}
if(that.state===PENDING){
that.resolvedCallbacks.push(onFulfilled)
that.rejectedCallbacks.push(onRejected)
}
if(that.state===RESOLVED){
onFulfilled(that.value)
}
if(that.state===REJECTED){
onRejected(that.value)
}
}
new myPromise((resolve, reject) => {
setTimeout(()=>{
resolve(1)
},0)
}).then(value=>{
console.log(value)
})
复制代码
进程描述了CPU在运行指令及加载和保存上下文所需的事件,线程是更小的单位,秒速了执行一段指令所需的时间
由于js能够修改DOM,若是JS执行的过程UI线程还在工做会致使不能不能安全的渲染UI。 JS单线程运行,能够达到节省内存,节约上下文切换时间,没有锁的问题
执行栈存放函数调用的栈结构,遵循先进后出的原则。 从底部开始放进去执行栈,而后从栈顶取出执行
不一样的任务源会被分配到不一样task队列中,任务源能够分为微任务(microtask)和宏任务(macrotask) 微任务包括process.nextTick, promise, MutationObserver 宏任务包括script,setTimeout,setInterval,setImmediate,I/O,UI rendering
1.首先执行同步代码,这属于宏任务 2.当执行完全部同步代码后,执行栈为空,查询是否有异步代码须要执行 3.执行全部微任务 4.当执行完全部微任务后,若有必要会渲染页面 5.而后开始下一轮EventLoop,执行宏任务中的异步代码,也就是setTimeout中的回调函数
Vue3.0其中一个核心功能就是使用Proxy替代Object.defineProperty Proxy能够在目标对象前架设一个拦截器,通常Reflect搭配,前者拦截对象,后者返回拦截的结果
1.没法探测到对象根属性的添加和删除 2.没法探测到对数组基于下标的修改 3.没法探测到.length修改的监测
JavaScript高级程序设计(第3版)