代码输入后果
setTimeout(function () { console.log(1);}, 100);new Promise(function (resolve) { console.log(2); resolve(); console.log(3);}).then(function () { console.log(4); new Promise((resove, reject) => { console.log(5); setTimeout(() => { console.log(6); }, 10); })});console.log(7);console.log(8);
输入后果为:
23784561
代码执行过程如下:
- 首先遇到定时器,将其退出到宏工作队列;
- 遇到Promise,首先执行外面的同步代码,打印出2,遇到resolve,将其退出到微工作队列,执行前面同步代码,打印出3;
- 继续执行script中的代码,打印出7和8,至此第一轮代码执行实现;
- 执行微工作队列中的代码,首先打印出4,如遇到Promise,执行其中的同步代码,打印出5,遇到定时器,将其退出到宏工作队列中,此时宏工作队列中有两个定时器;
- 执行宏工作队列中的代码,这里咱们须要留神是的第一个定时器的工夫为100ms,第二个定时器的工夫为10ms,所以先执行第二个定时器,打印出6;
- 此时微工作队列为空,继续执行宏工作队列,打印出1。
做完这道题目,咱们就须要分外留神,每个定时器的工夫,并不是所有定时器的工夫都为0哦。
代码输入后果
function a() { console.log(this);}a.call(null);
打印后果:window对象
依据ECMAScript262标准规定:如果第一个参数传入的对象调用者是null或者undefined,call办法将把全局对象(浏览器上是window对象)作为this的值。所以,不论传入null 还是 undefined,其this都是全局对象window。所以,在浏览器上答案是输入 window 对象。
要留神的是,在严格模式中,null 就是 null,undefined 就是 undefined:
'use strict';function a() { console.log(this);}a.call(null); // nulla.call(undefined); // undefined
手写题:数组扁平化
function flatten(arr) { let result = []; for (let i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { result = result.concat(flatten(arr[i])); } else { result = result.concat(arr[i]); } } return result;}const a = [1, [2, [3, 4]]];console.log(flatten(a));
什么是 JavaScript 中的包装类型?
在 JavaScript 中,根本类型是没有属性和办法的,然而为了便于操作根本类型的值,在调用根本类型的属性或办法时 JavaScript 会在后盾隐式地将根本类型的值转换为对象,如:
const a = "abc";a.length; // 3a.toUpperCase(); // "ABC"
在拜访'abc'.length
时,JavaScript 将'abc'
在后盾转换成String('abc')
,而后再拜访其length
属性。
JavaScript也能够应用Object
函数显式地将根本类型转换为包装类型:
var a = 'abc'Object(a) // String {"abc"}
也能够应用valueOf
办法将包装类型倒转成根本类型:
var a = 'abc'var b = Object(a)var c = b.valueOf() // 'abc'
看看如下代码会打印出什么:
var a = new Boolean( false );if (!a) { console.log( "Oops" ); // never runs}
答案是什么都不会打印,因为尽管包裹的根本类型是false
,然而false
被包裹成包装类型后就成了对象,所以其非值为false
,所以循环体中的内容不会运行。
晓得 ES6 的 Class 嘛?Static 关键字有理解嘛
为这个类的函数对象间接增加办法,而不是加在这个函数对象的原型对象上
为什么函数的 arguments 参数是类数组而不是数组?如何遍历类数组?
arguments
是一个对象,它的属性是从 0 开始顺次递增的数字,还有callee
和length
等属性,与数组类似;然而它却没有数组常见的办法属性,如forEach
, reduce
等,所以叫它们类数组。
要遍历类数组,有三个办法:
(1)将数组的办法利用到类数组上,这时候就能够应用call
和apply
办法,如:
function foo(){ Array.prototype.forEach.call(arguments, a => console.log(a))}
(2)应用Array.from办法将类数组转化成数组:
function foo(){ const arrArgs = Array.from(arguments) arrArgs.forEach(a => console.log(a))}
(3)应用开展运算符将类数组转化成数组
function foo(){ const arrArgs = [...arguments] arrArgs.forEach(a => console.log(a)) }
transition和animation的区别
- transition是适度属性,强调适度,它的实现须要触发一个事件(比方鼠标挪动下来,焦点,点击等)才执行动画。它相似于flash的补间动画,设置一个开始关键帧,一个完结关键帧。
- animation是动画属性,它的实现不须要触发事件,设定好工夫之后能够本人执行,且能够循环一个动画。它也相似于flash的补间动画,然而它能够设置多个关键帧(用@keyframe定义)实现动画。
大数相加
题目形容:实现一个add办法实现两个大数相加
let a = "9007199254740991";let b = "1234567899999999999";function add(a ,b){ //...}
实现代码如下:
function add(a ,b){ //取两个数字的最大长度 let maxLength = Math.max(a.length, b.length); //用0去补齐长度 a = a.padStart(maxLength , 0);//"0009007199254740991" b = b.padStart(maxLength , 0);//"1234567899999999999" //定义加法过程中须要用到的变量 let t = 0; let f = 0; //"进位" let sum = ""; for(let i=maxLength-1 ; i>=0 ; i--){ t = parseInt(a[i]) + parseInt(b[i]) + f; f = Math.floor(t/10); sum = t%10 + sum; } if(f!==0){ sum = '' + f + sum; } return sum;}
寄生组合继承
题目形容:实现一个你认为不错的 js 继承形式
实现代码如下:
function Parent(name) { this.name = name; this.say = () => { console.log(111); };}Parent.prototype.play = () => { console.log(222);};function Children(name) { Parent.call(this); this.name = name;}Children.prototype = Object.create(Parent.prototype);Children.prototype.constructor = Children;// let child = new Children("111");// // console.log(child.name);// // child.say();// // child.play();
数组有哪些原生办法?
- 数组和字符串的转换方法:toString()、toLocalString()、join() 其中 join() 办法能够指定转换为字符串时的分隔符。
- 数组尾部操作的办法 pop() 和 push(),push 办法能够传入多个参数。
- 数组首部操作的办法 shift() 和 unshift() 重排序的办法 reverse() 和 sort(),sort() 办法能够传入一个函数来进行比拟,传入前后两个值,如果返回值为负数,则替换两个参数的地位。
- 数组连贯的办法 concat() ,返回的是拼接好的数组,不影响原数组。
- 数组截取方法 slice(),用于截取数组中的一部分返回,不影响原数组。
- 数组插入方法 splice(),影响原数组查找特定项的索引的办法,indexOf() 和 lastIndexOf() 迭代办法 every()、some()、filter()、map() 和 forEach() 办法
- 数组归并办法 reduce() 和 reduceRight() 办法
说一下前端登录的流程?
首次登录的时候,前端调后调的登录接口,发送用户名和明码,后端收到申请,验证用户名和明码,验证胜利,就给前端返回一个token,和一个用户信息的值,前端拿到token,将token贮存到Vuex中,而后从Vuex中把token的值存入浏览器Cookies中。把用户信息存到Vuex而后再存储到LocalStroage中,而后跳转到下一个页面,依据后端接口的要求,只有不登录就不能拜访的页面须要在前端每次跳转页面师判断Cookies中是否有token,没有就跳转到登录页,有就跳转到相应的页面,咱们应该再每次发送post/get申请的时候应该退出token,罕用办法再我的项目utils/service.js中增加全局拦截器,将token的值放入申请头中 后端判断申请头中有无token,有token,就拿到token并验证token是否过期,在这里过期会返回有效的token而后有个跳回登录页面从新登录并且革除本地用户的信息
如何阻止事件冒泡
- 一般浏览器应用:event.stopPropagation()
- IE浏览器应用:event.cancelBubble = true;
PWA应用过吗?serviceWorker的应用原理是啥?
渐进式网络应用(PWA)
是谷歌在2015年底提出的概念。基本上算是web应用程序,但在外观和感觉上与原生app
相似。反对PWA
的网站能够提供脱机工作、推送告诉和设施硬件拜访等性能。
Service Worker
是浏览器在后盾独立于网页运行的脚本,它关上了通向不须要网页或用户交互的性能的大门。 当初,它们已包含如推送告诉和后盾同步等性能。 未来,Service Worker
将会反对如定期同步或天文围栏等其余性能。 本教程探讨的外围性能是拦挡和解决网络申请,包含通过程序来治理缓存中的响应。
函数防抖
触发高频事件 N 秒后只会执行一次,如果 N 秒内事件再次触发,则会从新计时。
简略版:函数外部反对应用 this 和 event 对象;
function debounce(func, wait) { var timeout; return function () { var context = this; var args = arguments; clearTimeout(timeout) timeout = setTimeout(function(){ func.apply(context, args) }, wait); }}
应用:
var node = document.getElementById('layout')function getUserAction(e) { console.log(this, e) // 别离打印:node 这个节点 和 MouseEvent node.innerHTML = count++;};node.onmousemove = debounce(getUserAction, 1000)
最终版:除了反对 this 和 event 外,还反对以下性能:
- 反对立刻执行;
- 函数可能有返回值;
- 反对勾销性能;
function debounce(func, wait, immediate) { var timeout, result; var debounced = function () { var context = this; var args = arguments; if (timeout) clearTimeout(timeout); if (immediate) { // 如果曾经执行过,不再执行 var callNow = !timeout; timeout = setTimeout(function(){ timeout = null; }, wait) if (callNow) result = func.apply(context, args) } else { timeout = setTimeout(function(){ func.apply(context, args) }, wait); } return result; }; debounced.cancel = function() { clearTimeout(timeout); timeout = null; }; return debounced;}
应用:
var setUseAction = debounce(getUserAction, 10000, true);// 应用防抖node.onmousemove = setUseAction// 勾销防抖setUseAction.cancel()
position的属性有哪些,区别是什么
position有以下属性值:
属性值 | 概述 |
---|---|
absolute | 生成相对定位的元素,绝对于static定位以外的一个父元素进行定位。元素的地位通过left、top、right、bottom属性进行规定。 |
relative | 生成绝对定位的元素,绝对于其原来的地位进行定位。元素的地位通过left、top、right、bottom属性进行规定。 |
fixed | 生成相对定位的元素,指定元素绝对于屏幕视⼝(viewport)的地位来指定元素地位。元素的地位在屏幕滚动时不会扭转,⽐如回到顶部的按钮⼀般都是⽤此定位⽅式。 |
static | 默认值,没有定位,元素呈现在失常的文档流中,会疏忽 top, bottom, left, right 或者 z-index 申明,块级元素从上往下纵向排布,⾏级元素从左向右排列。 |
inherit | 规定从父元素继承position属性的值 |
后面三者的定位形式如下:
- relative: 元素的定位永远是绝对于元素本身地位的,和其余元素没关系,也不会影响其余元素。
- fixed: 元素的定位是绝对于 window (或者 iframe)边界的,和其余元素没有关系。然而它具备破坏性,会导致其余元素地位的变动。
- absolute: 元素的定位绝对于前两者要简单许多。如果为 absolute 设置了 top、left,浏览器会依据什么去确定它的纵向和横向的偏移量呢?答案是浏览器会递归查找该元素的所有父元素,如果找到一个设置了
position:relative/absolute/fixed
的元素,就以该元素为基准定位,如果没找到,就以浏览器边界定位。如下两个图所示:
说一下怎么取出数组最多的一项?
// 我这里只是一个示例const d = {};let ary = ['赵', '钱', '孙', '孙', '李', '周', '李', '周', '周', '李'];ary.forEach(k => !d[k] ? d[k] = 1 : d[k]++);const result = Object.keys(d).sort((a, b) => d[b] - d[a]).filter((k, i, l) => d[k] === d[l[0]]);console.log(result)
分片思维解决大数据量渲染问题
题目形容:渲染百万条构造简略的大数据时 怎么应用分片思维优化渲染
实现代码如下:
let ul = document.getElementById("container");// 插入十万条数据let total = 100000;// 一次插入 20 条let once = 20;//总页数let page = total / once;//每条记录的索引let index = 0;//循环加载数据function loop(curTotal, curIndex) { if (curTotal <= 0) { return false; } //每页多少条 let pageCount = Math.min(curTotal, once); window.requestAnimationFrame(function () { for (let i = 0; i < pageCount; i++) { let li = document.createElement("li"); li.innerText = curIndex + i + " : " + ~~(Math.random() * total); ul.appendChild(li); } loop(curTotal - pageCount, curIndex + pageCount); });}loop(total, index);
扩大思考:对于大数据量的简略 dom 构造渲染能够用分片思维解决 如果是简单的 dom 构造渲染如何解决?
这时候就须要应用虚构列表了 大家自行百度哈 虚构列表和虚构表格在日常我的项目应用还是很频繁的
代码输入问题
function fun(n, o) { console.log(o) return { fun: function(m){ return fun(m, n); } };}var a = fun(0); a.fun(1); a.fun(2); a.fun(3);var b = fun(0).fun(1).fun(2).fun(3);var c = fun(0).fun(1); c.fun(2); c.fun(3);
输入后果:
undefined 0 0 0undefined 0 1 2undefined 0 1 1
这是一道对于闭包的题目,对于fun办法,调用之后返回的是一个对象。咱们晓得,当调用函数的时候传入的实参比函数申明时指定的形参个数要少,剩下的形参都将设置为undefined值。所以 console.log(o);
会输入undefined。而a就是是fun(0)返回的那个对象。也就是说,函数fun中参数 n 的值是0,而返回的那个对象中,须要一个参数n,而这个对象的作用域中没有n,它就持续沿着作用域向上一级的作用域中寻找n,最初在函数fun中找到了n,n的值是0。理解了这一点,其余运算就很简略了,以此类推。
数据类型判断
typeof 能够正确辨认:Undefined、Boolean、Number、String、Symbol、Function 等类型的数据,然而对于其余的都会认为是 object,比方 Null、Date 等,所以通过 typeof 来判断数据类型会不精确。然而能够应用 Object.prototype.toString 实现。
function typeOf(obj) {- let res = Object.prototype.toString.call(obj).split(' ')[1]- res = res.substring(0, res.length - 1).toLowerCase()- return res// 更好的写法+ return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()}typeOf([]) // 'array'typeOf({}) // 'object'typeOf(new Date) // 'date'
字符串模板
function render(template, data) { const reg = /\{\{(\w+)\}\}/; // 模板字符串正则 if (reg.test(template)) { // 判断模板里是否有模板字符串 const name = reg.exec(template)[1]; // 查找以后模板里第一个模板字符串的字段 template = template.replace(reg, data[name]); // 将第一个模板字符串渲染 return render(template, data); // 递归的渲染并返回渲染后的构造 } return template; // 如果模板没有模板字符串间接返回}
测试:
let template = '我是{{name}},年龄{{age}},性别{{sex}}';let person = { name: '布兰', age: 12}render(template, person); // 我是布兰,年龄12,性别undefined