javascript问题汇总

JS中的异步以及事件轮询机制

JS中的异步以及事件轮询机制 - heshan珊 - 博客园

宏任务和微任务

异步任务分为宏任务和微任务

每一个宏任务执行完之后,都会检查是否存在待执行的微任务
如果有,则执行完所有的微任务之后,再执行下一个宏任务。
宏任务和微任务交替执行。

  1. 宏任务(macrotask):类似主任务
    1. 异步Ajax请求
    2. setTimeout 、setInterval
    3. 文件操作
    4. 其他宏任务
  2. 微任务(microtask):类似事件队列
    1. Promise.then、Promise.catch和Promise.finally
    2. process.nextTick
    3. 其他微任务
  1. JS中的异步运行机制如下:  
    1. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
    2. 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
    3. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
    4. 主线程不断重复上面的第三步。
  2. JS种事件队列的优先级
    1. ES6 的任务队列(then中的回调)比事件循环中的任务(如settimeout的回调)队列优先级更高。

数据结构类型

链表

:堆就是用数组实现的二叉树,所以它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。

栈:

重载和重写的区别

一、定义上的区别:

1、重载是指不同的函数使用相同百的函数名,但是函数的参数个数或类型不同。调用的时候根据函数的参数来区别不同的函数。

2、覆盖度(也叫重写)是指在派生类中重新对基类中的虚函数(注意是虚函数)重新实现。即函数名和参数都一样,只是函数的实现体不一样。

js继承的6种方式

js继承的6种方式 - ranyonsue - 博客园

面向对象和面向过程

什么是面向对象(OOP) - 简书

面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。

面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。

JavaScript接口定义

JavaScript接口 - 简书

defer和async的区别

  1. <script async src="script.js"></script>

    有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。只要它加载完了就会立刻执行

  2. <script defer src="myscript.js"></script>

    有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。它是按照加载顺序执行脚本的,会等前面的文件加载完再加在自己,这一点要善加利用

理解javascript中的事件模型

理解javascript中的事件模型 - 泛舟青烟 - 博客园

先捕(大到小)获后冒泡(小到大);

a++和++a的区别

a++是先执行表达式后再自增,执行表达式时使用的是a的原值。
++a是先自增再执行表达示,执行表达式时使用的是自增后的a。

1.什么是上下文环境?

JavaScript 代码运行时,会产生一个全局的上下文环境(context,又称运行环境),包含了当前所有的变量和对象。然后,执行函数(或块级代码)的时候,又会在当前上下文环境的上层,产生一个函数运行的上下文,变成当前(active)的上下文,由此形成一个上下文环境的堆栈(context stack)。

这个堆栈是“后进先出”的数据结构,最后产生的上下文环境首先执行完成,退出堆栈,然后再执行完成它下层的上下文,直至所有代码执行完成,堆栈清空。

JavaScript的内存机制

JavaScript的内存机制也一样分为了堆和栈,但它和Java还是存在区别的。

  1. JavaScript中的栈只会存放一些原始类型的小数据,例如 Undefined、Null、Boolean、Number 和 String、Symbol等等,
  2. 在JavaScript中的堆中,则是用来存放引用类型,例如Object, Array, Function等
  3. 其数据存储在堆空间中,只在栈空间内存储了相对应的引用地址。

为什么要分栈和堆?

JavaScript引擎需要用栈来维护程序执行期间的上下文状态(环境),如果栈过大,所有数据都放在栈里面,栈里面的数据取用特别不方便,会影响上下文的切换效率

堆栈与闭包之间的关系

闭包闭包让你可以在一个内层函数中访问到其外层函数的作用域(当前上下文中创造出新的上下文且可以访问上级上下文变量)

被闭包引用的变量会去到堆里的一个叫做closure的闭包对象里面去,并且将数据存在里面,而在栈中只留下一个引用地址指向这个堆里的闭包对象。由于闭包的原因,这个foo的执行上下文不能被销毁,所以栈内的其他变量仍在栈中,但是我们并不能在外面调用到它了,但它确实是存在的。

2.setTimeout、setInterval被遗忘的第三个参数

参考网站

setTimeout、setInterval被遗忘的第三个参数 - leaf+ - 博客园

关于JS定时器(setTimeout / setInterval)定时不准问题及解决方案

关于JS定时器(setTimeout / setInterval)定时不准问题及解决方案 - 简书

  1. 动态计算时差

    1. 在定时器开始前和运行时动态获取当前时间,在设置下一次定时时长时,在期望值基础上减去当前时延,以获得相对精准的定时运行效果。
    2. 此方法仅能消除setInterval()长时间运行造成的误差累计,但无法消除单个定时器执行延迟问题。
  2. Web Worker
    1. Web Worker 的作用,就是为 JavaScript 创造多线程环境,  
    2. webworker限制
      1. (1)同源限制

        分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。

        (2)DOM 限制

        Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用documentwindowparent这些对象。但是,Worker 线程可以navigator对象和location对象。

        (3)通信联系

        Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。(postmessage通信)

        (4)脚本限制

        Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。

        (5)文件限制

        Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

prototype和__proto__的理解

prototype、__proto__与constructor_juse__we的博客-CSDN博客

需要注意的问题

再给 Child 添加新的方法的时候,一定要在原型继承父元素后添加,这样可以防止自己定义的方法,会和继承来的方法名字相同,导致 Child 自己定的方法被覆盖

原型链继承的问题

JavaScript之原型链继承&注意点和缺点 - heyushuo - 博客园

1.实例共享引用类型

虽然原型链继承很强大, 但是存在一个问题, 最主要的问题是包含引用类型值的原型, 因为包含引用类型值的原型属性会被所有的实例共享, 而在通过原型来实现继承的时候, 原型实际变成了另外一个函数的实例(这里边就有可能存在引用类型)

通过一个例子看一下

function Parent() {
  this.newArr = ["heyushuo", "kebi"];
}

function Child() {
  this.name = "kebi";
}
Child.prototype = new Parent();
var Person1 = new Child();
Person1.newArr.push("kuli");
console.log(Person1.newArr); // ["heyushuo","kebi","kuli"]
var Person2 = new Child();
console.log(Person2.newArr); // ["heyushuo","kebi","kuli"]

2.在创建 Child 的子类的时候,无法像继承元素传递参数

foreach和map的相同点和区别

forEach使用

array.forEach(callback(currentValue, index, array){

    //do something

}, this)   // 回调函数callback(当前数组中元素,索引,当前数组)
           // this的指向。

map的使用

array.map(function(item,index,arr){},thisValue)

区别

 1、forEach()返回值是undefined,不可以链式调用。

 2、map()返回一个新数组,原数组不会改变。

相同点

  • 匿名函数中的this都是指向window
  • 只能遍历数组
  • 都不会改变原数组
  • foreach和map没有办法终止或者跳出循环,除非抛出异常,所以想执行一个数组是否满足什么条件,返回布尔值,可以用一般的for循环实现,或者用Array.every()或者Array.some();

5.array,字符串常用方法

字符串

stringObject.slice(start,end) 可提取字符串的某个部分,并以新的字符串返回被提取的部分
stringObject.split(separator(分隔符),howmany)方法用于把一个字符串分割成字符串数组。
stringObject.substring(start,stop)方法用于提取字符串中介于两个指定下标之间的字符。
stringObject.substr(start,length)方法可在字符串中抽取从 start 下标开始的指定数目的字符。

6.三种数组去重的方法

1es6 set数据结构

2循环单个对比去重

思路:

1.先将原数组进行排序

2.检查原数组中的第i个元素 与 结果数组中的最后一个元素是否相同,因为已经排序,所以重复元素会在相邻位置

3.如果不相同,则将该元素存入结果数组中

Array.prototype.unique2 = function(){
	this.sort();	//先排序
	var res = [this[0]];
	for(var i = 1; i < this.length; i++){
		if(this[i] !== res[res.length - 1]){
			res.push(this[i]);
		}
	}
	return res;
}
var arr = [1, 'a', 'a', 'b', 'd', 'e', 'e', 1, 0]
alert(arr.unique2());

第二种方法也会有一定的局限性,因为在去重前进行了排序,所以最后返回的去重结果也是排序后的。如果要求不改变数组的顺序去重,那这种方法便不可取了。

3讲数组变为新数组的下标(重复的会覆盖前面的),for in遍历

function unique3(arr){
    for (var i =0,hash=[];i<arr.length ;i++ ){
        if (hash[arr[i]]==undefined){
        hash[arr[i]]=1;
        } 
    }
    var j=0;
    var keys=[];
    for (keys[i++] in hash );
    return keys;
}
console.log( unique3(arr) );

7.三种排序的方法

三种基础的排序算法 - FightKelly - 博客园

sort 排序方法的实现原理 - 掘金

8.跨域的方法

各类前端实现跨域的方法_juse__we的博客-CSDN博客_前端跨域

jsonp安全问题

解决 jsonP 安全问题 - you1you - 博客园

cors简单请求,复杂请求,预请求

CORS跨域请求[简单请求与复杂请求] - 裙下的小香蕉 - 博客园

1、简单请求

HEAD,GET,POST之一,头信息较少。但是HTTP头当中要求总是包含一个域(Origin)的信息。该域包含协议名、地址以及一个可选的端口。不过这一项实际上由浏览器代为发送,并不是开发者代码可以触及到的。
2、复杂请求

复杂请求表面上看起来和简单请求使用上差不多,但实际上浏览器发送了不止一个请求。其中最先发送的是一种"预请求",此时作为服务端,也需要返回"预回应"作为响应。预请求实际上是对服务端的一种权限请求,只有当预请求成功返回,实际请求才开始执行。

预请求以OPTIONS形式发送,当中同样包含域,并且还包含了两项CORS特有的内容:

Access-Control-Request-Method – 该项内容是实际请求的种类,可以是GET、POST之类的简单请求,也可以是PUT、DELETE等等。
Access-Control-Request-Headers – 该项是一个以逗号分隔的列表,当中是复杂请求所使用的头部。

显而易见,这个预请求实际上就是在为之后的实际请求发送一个权限请求,在预回应返回的内容当中,服务端应当对这两项进行回复,以让浏览器确定请求是否能够成功完成。

复杂请求的部分响应头及解释如下:

Access-Control-Allow-Origin(必含) – 和简单请求一样的,必须包含一个域。
Access-Control-Allow-Methods(必含) – 这是对预请求当中Access-Control-Request-Method的回复,这一回复将是一个以逗号分隔的列表。尽管客户端或许只请求某一方法,但服务端仍然可以返回所有允许的方法,以便客户端将其缓存。
Access-Control-Allow-Headers(当预请求中包含Access-Control-Request-Headers时必须包含) – 这是对预请求当中Access-Control-Request-Headers的回复,和上面一样是以逗号分隔的列表,可以返回所有支持的头部。这里在实际使用中有遇到,所有支持的头部一时可能不能完全写出来,而又不想在这一层做过多的判断,没关系,事实上通过request的header可以直接取到Access-Control-Request-Headers,直接把对应的value设置到Access-Control-Allow-Headers即可。
Access-Control-Allow-Credentials(可选) – 和简单请求当中作用相同。
Access-Control-Max-Age(可选) – 以秒为单位的缓存时间。预请求的的发送并非免费午餐,允许时应当尽可能缓存。

一旦预回应如期而至,所请求的权限也都已满足,则实际请求开始发送。

9.javascript的设计模式

基础笔记(二):设计模式摘录 - 老真 - 博客园

10移动端区分ios和安卓

通过 navigator.userAgent获取代理者(Linux是ios,Android是安佐), navigator.appVersion获得版本号


$(function(){
    var u = navigator.userAgent, app = navigator.appVersion; 
    var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; 
    //android终端    或者uc浏览器 
    var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端 
    alert('是否是Android:'+isAndroid); 
    alert('是否是iOS:'+isiOS);
    if(isAndroid){
	    $ ("#choose").attr('capture','camera');
    }
})

11.函数节流,函数去抖

函数节流和函数去抖_juse__we的博客-CSDN博客

12
sessionStorage,localStorage ,cookie

sessionStorage,localStorage ,cookie_juse__we的博客-CSDN博客

13Promise原理、方法和问题集锦

Promise原理和问题集锦_juse__we的博客-CSDN博客

14迭代(iterate)和递归(recursion)的区别

参考:迭代是人,递归是神(迭代与递归的总结:比较)_kingkyrie的博客-CSDN博客_迭代是人,递归是神

从概念上讲,递归就是指程序调用自身的编程思想,即一个函数调用本身;

int fib(int n){  
     if(n>1) return fib(n-1) + fib(n-2);  
     else return n; // n = 0, 1时给出recursion终止条件  
}  

迭代是利用已知的变量值,根据递推公式不断演进得到变量新值得编程思想。

int fib(int n){  
    int i, temp0, temp1, temp2;        
    if(n<=1) return n;  
    temp1 = 0;  
    temp2 = 1;  
    for(i = 2; i <= n; i++){  
        temp0 = temp1 + temp2;  
        temp2 = temp1;  
        temp1 = temp0;  
    }  
    return temp0;  
}  

JS 中深拷贝的几种实现方法

JS 中深拷贝的几种实现方法_程序员小哥哥的博客-CSDN博客_js深拷贝

js设计模式之观察者模式及发布/订阅模式

js设计模式之【观察者模式】VS【发布/订阅模式模式】的区别? - leaf+ - 博客园

JS篇-遍历对象属性(for in、Object.keys、Object.getOwnProperty)

JS篇-遍历对象属性(for in、Object.keys、Object.getOwnProperty) - SegmentFault 思否

js检测数据类型四种办法

js检测数据类型四种办法 - zt123123 - 博客园

js中instanceof原理

js中instanceof原理_wyw223的博客-CSDN博客_instanceof原理

前端面试(算法篇) - 数组乱序

前端面试(算法篇) - 数组乱序 - Wise.Wrong - 博客园

js连等赋值

.运算符优先于=赋值运算

js连等赋值 - ooooevan - 博客园

JS 三个连等 - 简书

performance.now() VS Date.now()

performance.now() VS Date.now()_Kid thePhantom Thief的博客-CSDN博客_performance.now

获取元素距离浏览区域的距离

获取元素距离浏览区域的距离_juse__we的博客-CSDN博客

URL编码转换函数:escape()、encodeURI()、encodeURIComponent()

URL编码转换函数:escape()、encodeURI()、encodeURIComponent() - 鱼我所欲也 - 博客园

apply、call、bind 三者相比较,之间又有什么异同

var obj = {
    x: 81,
};
 
var foo = {
    getX: function(y) {
        return this.x+y;
    }
}
 
console.log(foo.getX.bind(obj)(2));  //81,注意传参方式
console.log(foo.getX.call(obj,2));    //81,注意传参方式
console.log(foo.getX.apply(obj,[2]));   //81,注意传参方式,使用数组对象

三个输出的都是81,但是注意看使用 bind() 方法的,他后面多了对括号。

也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind()方法。而 apply/call 则会立即执行函数。
总结一下:

applycallbind 三者都是用来改变函数的this对象的指向的;
applycallbind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
applycallbind 三者都可以传参但传参方式不一样;
bind 是返回对应函数,便于稍后调用;applycall 则是立即调用 。

eventLoop事件轮询

什么是 Event Loop? - 阮一峰的网络日志

简单说,就是在程序中设置两个线程:一个负责程序本身的运行,称为"主线程";另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为"Event Loop线程"(可以译为"消息线程")。

asynchronous mode

上图主线程的绿色部分,还是表示运行时间,而橙色部分表示空闲时间。每当遇到I/O的时候,主线程就让Event Loop线程去通知相应的I/O程序,然后接着往后运行,所以不存在红色的等待时间。等到I/O程序完成操作,Event Loop线程再把结果返回主线程。主线程就调用事先设定的回调函数,完成整个任务。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值