- var、let、const的区别;
- var 会变量提升
- let 声明的变量只在它所在的代码块有效
- const声明后不能再修改其指向的目标,假如const指向的是一个对象/数组,那么虽然不能更改指向目标,但是可以更改对象和数组内部的值;
- class声明一个类时,存在变量提升么?为什么?
- 不存在。因为要方便类的继承,先声明子类再声明父类;
- const 声明一个对象,如何让对象内部的属性的值也无法改变?
- 使用Object.freeze()锁死(es5新增特性);对数组等引用类型的值,还是能修改的;
- javascript有哪几种数据类型?如何判断?
- 六种基本数据类型:
- undefined
- null
- string
- Boolean
- Symbol
- 一种引用类型
- object(function/Date/RegExp/Number/String/boolean)
- 如何判断?
- typeof(1) //number无法区分引用类型都返回‘object’
- instanceof //[] instanceof Array; //true 但是无法对原始类型进行判断。一般都是判断为object后再使用instanceof具体判断。
var obj = {}; obj instanceof Object; //true var arr = []; arr instanceof Array; //true var now = new Date(); now instanceof Date; //true var func = function(){}; func instanceof Function; //true var str = "string"; str instanceof String; //false 复制代码
- Objectl.prototype.toString.call()通用的来判断原始数据类型和引用数据类型。
var num1 = 1; var num2 = new Number(1); Object.prototype.toString.call(num1) == "[object Number]"; //true Object.prototype.toString.call(num2) == "[object Number]"; //true var arr = []; Object.prototype.toString.call(arr) == "[object Array]"; //true var func = function(){}; Object.prototype.toString.call(func) == "[object Function]"; //true function A(){}; var a = new A(); Object.prototype.toString.call(a) == "[object Object]"; //true 复制代码
- constructor
console.log([].constructor == Array); console.log({}.constructor == Object); console.log("string".constructor == String); console.log((123).constructor == Number); console.log(true.constructor == Boolean); 复制代码
- Symbol(es6)特点如下:
- 表示独一无二的值
- 声明时不能使用new Symbol(),而是 Symbol()
- 声明时可以加参数,用于描述
- 作为key时不能被遍历
- 如何声明两个相等的Symbol变量?
let a = Symbol.for('a'); let b = Symbol.for('a'); a === b; // true 复制代码
- 检查一个对象是否存在的方法:
- this指向问题
if(!obj){ // 控制台会报错obj is not defined obj = {}; } if(!this.obj){ alert('1') this.obj = {}; } if(!this.hasOwnProperty('obj')){ alert('2') this.obj = {}; } if(!window.obj){ alert('3') window.obj = {}; } 复制代码
- Promise是什么?
- 含义: 是异步编程的一种解决方案, 简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
- 使用场景:异步请求,比如ajax
- 哪些状态:pending,resolved,rejected.
- 如果内部抛错,但是没有被捕获,这个没被捕获的错误接下来会发生什么事情?冒泡。
- 如何捕获错误:最后catch;then的第二个参数。
- 不可以用try catch 捕获,因为是异步编程。
- 写一个简易的promise
//todo 复制代码
- async、await 的使用场景是什么?
- 连续的异步请求,下一步的异步请求依赖于前一步的异步请求结果;
- 假如有A、B、C三个异步请求,异步请求C依赖于异步请求A和B的结果(即A和B完成后再发起C),那么你会如何实现它?
- Promise.all();
- 设置状态分别标记A和B,A、B完成后会去修改自己的完成标记,然后检查所有的状态标记,假如都是完成状态,然后去执行异步请求C。
- 检测一个变量是否为对象?
typeof xx === 'object' // error null也是对象。
(xx !== null) && (typeof xx === "object") // ok
复制代码
- 判断var是的是否是全局变量。
var x = 0;
function text() {
return this.x;
}
let o = {};
o.x = 1;
o.m = text;
// o.m.apply(); // console.log('x',x) 0 this指向全局
o.m.apply(o); // console.log('x',x) 1 this指向var,var的this还是全局。
复制代码
- this指向问题1
function f1() {
var n = 1;
aAdd = function () { // 没有用var直接将值赋值给了window。
console.log('n', n); // 也可以获取n=1
n += 1;
}
function f2() {
return n;
}
return f2;
}
var result = f1();
aAdd();// 回调用此函数,并且加1.
result();
console.log('result', result()); // 999
console.log('aAdd', aAdd);
复制代码
- this指向问题2
var x = {
name: 'bw2',
getName1: function() {
console.log(this) // {name: "bw2", getName1: ƒ}
},
getName2: function() {
setTimeout(() => {
console.log(this) // {name: "bw2", getName1: ƒ}
},0)
},
getName31: () => {
console.log(this) //Window
},
getName32: function() {
return function() {
console.log(this) // Window
}
}
}
x.getName1() // {name: "bw2", getName1: ƒ}
x.getName2() // {name: "bw2", getName1: ƒ}
x.getName31() // Window {stop: ƒ, open: ƒ, alert: ƒ, confirm: ƒ, prompt: ƒ, …}
x.getName32()() // Window {stop: ƒ, open: ƒ, alert: ƒ, confirm: ƒ, prompt: ƒ, …}
复制代码
- 法则一:对象方法中的this指向对象本身(箭头函数形式的除外)
var x = {
name: 'bw2',
getName1: function() {
console.log(this)
}
}
x.getName1() // {name: "bw2", getName1: ƒ}
复制代码
- 多层嵌套函数中的this指向等同于包含该this的最近一个function的this
- 箭头函数没有独立的this作用域,所以继续往外层走,走到了getName: function(){}。那么就是他了,this指向等同于这个function内部的this指向。根据法则一,this指向对象本身。
var x = {
name: 'bw2',
getName2: function() {
console.log(this) // 等同于此处的this
setTimeout(() => {
console.log(this) // 箭头函数没有this,继续往上找,原始的this位置
},0)
}
}
x.getName2() // {name: 'bw2', getName1: ƒ}
复制代码
- 法则三:箭头函数以及非指向对象方法中的function的情况下this指向window
var x = {
name: 'bw2',
getName31: () => {
console.log(this) // window
},
getName32: function() {
return function() {
console.log(this) //window
}
}
}
x.getName31() // Window {stop: ƒ, open: ƒ, alert: ƒ, confirm: ƒ, prompt: ƒ, …}
x.getName32()() // Window {stop: ƒ, open: ƒ, alert: ƒ, confirm: ƒ, prompt: ƒ, …}
复制代码
- 写个函数‘get-element-by-id’ 返回‘getElementById’
function get(str) {
var strArray = str.split('-');
for(let i = 0 ;i < strArray.length; i++){
if(i > 0){
strArray[i] = strArray[i].slice(0, 1).toUpperCase() + strArray[i].slice(1)
}else {
strArray[i] = strArray[i];
}
}
return strArray.join('');
}
let b = get('get-element-by-id');
复制代码
- 请描述一下 cookies,sessionStorage 和 localStorage 的区别?
- 是否传递给服务器。cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。 cookie数据始终在同源的http请求中携带(即使不需要),记会在浏览器和服务器间来回传递。sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
- 大小。cookie数据大小不能超过4k。 sessionStorage和localStorage,虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
- 时间。localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据; sessionStorage数据在当前浏览器窗口关闭后自动删除。 cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
- 说几条写JavaScript的基本规范
1.不要在同一行声明多个变量。 2.请使用 ===/!==来比较true/false或者数值 3.使用对象字面量替代new Array这种形式 4.不要使用全局函数。 5.Switch语句必须带有default分支 6.函数不应该有时候有返回值,有时候没有返回值。 7.For循环必须使用大括号 8.If语句必须使用大括号 9.for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。 复制代码
- null和undefined的区别?
- null: Null类型,代表“空值”,代表一个空对象指针,使用typeof运算得到 “object”,所以你可以认为它是一个特殊的对象值。
- Undefined:Undefined类型,当一个声明了一个变量未初始化时,得到的就是undefined。
- console.log(null==undefined)//true。console.log(null===undefined)//false
- null 用法:
- 作为函数的参数,表示该函数的参数不是对象。
- 原型链的终点。
- undefined表示"缺少值"
- 变量被声明了,但没有赋值时,就等于undefined。
- 调用函数时,应该提供的参数没有提供,该参数等于undefined。
- 对象没有赋值的属性,该属性的值为undefined。
- 函数没有返回值时,默认返回undefined。
- 什么是深拷贝和浅拷贝,如何做深拷贝?
- 深拷贝含义:它不但拷贝目标对象的第一层属性,而且还递归拷贝目标对象的所有属性
- 浅拷贝含义:浅拷贝只会将对象的各个属性进行依次复制,并不会进行递归复制,也就是说只会进行赋值目标对象的第一层属性。
//浅拷贝1、ES6:object.assign()
var a = { name : “hello” };
var b = Object.assign( { },a );
b.name = “hi”;
console.log(a);
复制代码
// 浅拷贝2、展开运算符……
扩展运算符用三个点号表示,功能是把数组或类数组对象展开成一系列用逗号隔开的值
var a = { name : “hello” };
var b = { …a};
b.name = “hi”;
console.log(a);
复制代码
//浅拷贝3、自己封装函数实现for in
var a = { name : “hello” };
var b = copy(a);
b.name = ‘hi’;
console.log(a);
function copy(obj){
var result = { };
for(var attr in obj ){
result [attr] = obj[attr];
}
return result;
}
复制代码
```
//深拷贝1
var dest = JSON.parse(JSON.stringify(target));
//深拷贝2
var deepCopy= function(source) {
var result={};
for (var key in source) {
result[key] = typeof source[key]===’object’? deepCoyp(source[key]): source[key];
}
return result;
}
// 深拷贝3 reduce
function deepClone(a) {
const keys = Object.keys(a)
return keys.reduce((memo, current) => {
const value = a[current]
if (typeof value === 'object') {
return {
...memo,
[current]: deepClone(value),
}
}
return {
...memo,
[current]: value,
}
}, {})
}
var a = {
val: 1,
desc: {text: 'a'},
}
var b = deepClone(a)
//深拷贝4 第三方类库
Lodash merge函数
immutable
```
复制代码
- call、apply和bind方法的用法以及区别?
- call 方法第一个参数是要绑定的this,后边传入是参数列表,当第一个参数是null、undefined的时候,默认指向window。
- 比如fn.call(obj,...arguments)
var obj = { message: 'My name is: ' } function getName(firstName, lastName) { console.log(this.message + firstName + ' ' + lastName) } getName.call(obj, 'Dot', 'Dolby') 复制代码
- apply接收两个参数,第一个是要绑定的this,第二是参数数组。当第一个是null、undefined的时候默认指向window。
- 比如:fn(obj,[...])
var obj = { message: 'My name is: ' } function getName(firstName, lastName) { console.log(this.message + firstName + ' ' + lastName) } getName.apply(obj, ['Dot', 'Dolby'])// My name is: Dot Dolby 复制代码
- bind第一个参数是this,从第二参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用。
var obj = {
name: 'Dot'
}
function printName() {
console.log(this.name)
}
var dot = printName.bind(obj)
console.log(dot) // function () { … }
dot() // Dot
复制代码
//同样bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的。
var a = {
user:"追梦子",
fn:function(e,d,f){
console.log(this.user); //追梦子
console.log(e,d,f); //10 1 2
}
}
var b = a.fn;
var c = b.bind(a,10);
c(1,2);
复制代码
- call、apply和bind函数存在的区别:
- 返回值不同:bind返回对应函数, 便于稍后调用。apply, call则是立即调用。
- 在 ES6 的箭头函数下, call 和 apply 将失效。
- call和apply的第二个参数不同。call第二个参数是单个系列。bind可以多个参数,依次是行参。apply第二参数是[...]。
- js里面,变量声明方式一共几种?
- var let const function class import
- 浏览器基础对象有哪几个?
- window、navigator、screen、history、location。
- 页面刷新有哪几种方式?
- location.reloading;locatoin.href = href。location.replace。
- Navigator如何区分是Android还是iOS(如果做过移动端开发);如果区分是否在微信中?(如果有做过移动端微信开发)
- 基础考点:至少要能答出通过UA区分,答不出扣分。
- 一阶考点:考察对UA有实际使用经验
- 二阶考点:能讲出Android的一些奇葩浏览器UA(如Adr、QQ浏览器等),说明经验丰富
- websocket 是什么怎么用?如何兼容低浏览器?
Adobe Flash Socket 、 ActiveX HTMLFile (IE) 、 基于 multipart 编码发送 XHR 、 基于长轮询的 XHR 复制代码
// websocket怎么用? 复制代码
- offsetWidth/offsetHeight,clientWidth/clientHeight与scrollWidth/scrollHeight的区别?
- offsetWidth/offsetHeight返回值包含content + padding + border,效果与e.getBoundingClientRect()相同
- clientWidth/clientHeight返回值只包含content + padding,如果有滚动条,也不包含滚动条
- scrollWidth/scrollHeight返回值包含content + padding + 溢出内容的尺寸
- XMLHttpRequest通用属性和方法?
- readyState:表示请求状态的整数,取值
- UNSENT(0):对象已创建
- OPENED(1):open()成功调用,在这个状态下,可以为xhr设置请求头,或者使用send()发送请求
- HEADERS_RECEIVED(2):所有重定向已经自动完成访问,并且最终响应的HTTP头已经收到
- LOADING(3):响应体正在接收
- DONE(4):数据传输完成或者传输产生错误
- onreadystatechange:readyState改变时调用的函数
- status:服务器返回的HTTP状态码(如,200, 404)
- statusText:服务器返回的HTTP状态信息(如,OK,No Content)
- responseText:作为字符串形式的来自服务器的完整响应
- responseXML: Document对象,表示服务器的响应解析成的XML文档
- abort():取消异步HTTP请求
- getAllResponseHeaders(): 返回一个字符串,包含响应中服务器发送的全部HTTP报头。每个报头都是一个用冒号分隔开的名/值对,并且使用一个回车/换行来分隔报头行
- getResponseHeader(headerName):返回headName对应的报头值
- open(method, url, asynchronous [, user, password]):初始化准备发送到服务器上的请求。method是HTTP方法,不区分大小写;url是请求发送的相对或绝对URL;asynchronous表示请求是否异步;user和password提供身份验证
- setRequestHeader(name, value):设置HTTP报头
- send(body):对服务器请求进行初始化。参数body包含请求的主体部分,对于POST请求为键值对字符串;对于GET请求,为null
- readyState:表示请求状态的整数,取值
- 列举数据相关的常用方法
- push/pop,shift/unshift,slice/splice/concat,sort/recerse,map/reduce,forEach,filter。
- 列举字符串常用的方法
- indexOf/lastIndexOf/charAt, split/match/test, slice/substring/substr, toLowerCase/toUpperCase
- js里的作用域是什么样子的?
- js里边叫函数作用域,就是一个变量在全函数里有效.比如有个变量p1在函数最后一行定义,第一行也有效,但是值是undefined.
var globalVar = 'global var'; function test() { alert(globalVar); // undefined, 因为globalVar在本函数内被重定义了,导致全局失效,这里使用函数内的变量值,可是此时还没定义 var globalVar = 'overrided var'; // globalVar在本函数内被重定义 alert(globalVar); // overrided var } alert(globalVar); // global var,使用全局变量 复制代码
- 如何实现浏览器内多个标签页之间的通信?
- webSocket、loaclStorage、cookie、
- 如何提高cookie的安全性?
- httpOnly、cookie-secure的值改为true、超时设置。
- 如何统计一个页面加载时间?如何统计一个页面首屏的加载时间?
- 怎么看koa跟express?
- Koa更像架子,插件扩展;express是framework;Handler处理方式差异,一个是回调、一个是生成器函数
- for ... in 和 for ... of 的区别?
- for...in语句以原始插入顺序迭代对象的可枚举属性。不完善,
- for...of 可迭代对象定义要迭代的数据。 解决历史问题。
- setTimeout和Promise在异步实现上,有什么区别?
dd? 复制代码
- 如何判断一个变量是空对象?
- Object.keys(ES6),for in循环
- hasOwnProperty person.hasOwnProperty("name")
- 箭头函数=>的this是指向哪里?
- 箭头函数不会创建自己的this,而是默认绑定函数的宿主对象(或者函数所绑定的对象等同类意思)
- 如果有对象嵌套的情况,则this绑定到最近的一层对象上。
- 冒泡和捕获,有什么区别?有哪些事件是不会冒泡的?
- focus、blur、load、unload等事件,不会冒泡。
- 事件代理 or 委托(delegate)原理和作用是什么?
- 利用事件冒泡机制实现,作用是通过委托代理到父节点,解决子节点过多或者动态加载时的重复绑定问题
- 实现原理:event.target监听实际触发元素;避免是期望元素的子节点,需追加parentNode循环判断。
- 知道哪些模块化规范,你使用过哪些?
- cmd:先下好,依赖就近,需要执行的时候再解析(seajs)
- CommonJS: node使用的CommonJS
- amd:(依赖前置,下载后立即解析) seajs 很少用了
- es6 import Module :(编译时加载,静态加载,可以实现静态分析,优化加载);es6的模块化;
- export 导出时,有几种写法?他们之间区别是什么?
- export default和 export {a, b, c}
- 前者 import 引入时,不需要关心导出的变量名,但是后者需要知道。
- 浏览器的事件机制,包含了哪些阶段?
- 事件的三个阶段(捕获,目标源,冒泡)
- 浏览器中的事件轮回模型(Event Loop),什么是微任务,什么是宏任务?
- 微任务包括 process.nextTick ,promise ,MutationObserver。
- 宏任务包括 script , setTimeout ,setInterval ,setImmediate ,I/O ,UI rendering。
- Event Loop 执行顺序如下所示:
- 首先执行同步代码,这属于宏任务
- 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
- 执行所有微任务
- 当执行完所有微任务后,如有必要会渲染页面
- 然后开始下一轮 Event Loop,执行宏任务中的异步代码,也就是 setTimeout 中的回调函数
- 浏览器有哪些缓存机制?
- 缓存位置:Service Worker;Memory Cache(内存中的缓存);Disk Cache(硬盘中的缓存)
- 缓存策略
- 强缓存(通过设置两种 HTTP Header 实现:Expires 和 Cache-Control 。强缓存表示在缓存期间不需要请求,state code 为 200)
- 协商缓存(缓存过期了,就需要发起请求验证资源是否有更新。协商缓存可以通过设置两种 HTTP Header 实现:Last-Modified 和 ETag )
- 浏览器渲染一个网页的过程?
- 1.浏览器接收到 HTML 文件并转换为 DOM 树
- 2.将 CSS 文件转换为 CSSOM 树
- 3.生成渲染树
- 注意点: 碰到script标签会阻塞渲染,所以一般会把script放到页脚。如果想要避免script阻塞页面渲染,可以给script标签加 async或defer 属性
- 如何进行前端错误监控?
- window.onerror方法可以很好做前端错误监控
window.onerror = function(message, url, line) { if (!url) return; var msg = {}; //记录客户端环境 msg.ua = window.navigator.userAgent; //只记录message里的message属性就好了, //错误信息可能会比较晦涩,有些信息完全无用,应酌情过滤 msg.message = message.message; msg.url = url; msg.line = line; msg.page = window.location.href; var s = []; //将错误信息转换成字符串 for(var key in msg){ s.push(key + '=' + msg[key]); } s = s.join('&'); //这里是用增加标签的方法调用日志收集接口,优点是比较简洁。 new Image().src = '/ajax-jserror.php?' + encodeURIComponent(s) + '&t=' + Math.random(); }; 复制代码
- try&catch
- 使用箭头函数(arrow functions)的优点是什么?
- 作用域安全:在箭头函数之前,每一个新创建的函数都有定义自身的 this 值(在构造函数中是新对象;在严格模式下,函数调用中的 this 是未定义的;如果函数被称为“对象方法”,则为基础对象等),但箭头函数不会,它会使用封闭执行上下文的 this 值
- 简单:箭头函数易于阅读和书写
- 清晰:当一切都是一个箭头函数,任何常规函数都可以立即用于定义作用域。开发者总是可以查找 next-higher 函数语句,以查看 this 的值
- 变量赋值
(() => {
var a = b = 3;
})()
console.log(a) // a is not defined
console.log(b) // 3
// 等价于 b=3 && var a=b
// 所以console时,a不存在,b为3
复制代码
- 数组去重的方法有哪些?
- 参考 。
- 防抖动和节流?
- 防抖动就是:防抖动 Debouncing把触发非常频繁的事件(比如按键,滚动)合并成一次执行。基本思路是规定时间内仅仅触发最后一次,依次类推,如果连接起来可能很长时间不会执行。先定义一个定时器,触发一次判断是否定时器是否已经赋值了,如果赋值了,清空定时器,重新赋值。
- 其它解释:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行
function debounce(func, delay) { let timeOut = null; // 定义一个定时器函数; return function () { if(timeOut !== null){ // 如果已经赋值了,就清空定时器重新计算。 clearTimeout(timeOut); } timeOut = setTimeout(func,delay); //每次触发就赋值,执行最后一次赋值的函数 } } function handle() { console.log('抖动') } window.addEventListener('scroll',debounce(handle,500)) 复制代码
- 节流就是:固定时间内仅仅执行一次,如果重新赋值,重新计算。函数执行完,立即将定时器赋值为空对象。用了apply改变this指向。
- 其它解释: 指定时间间隔内只会执行一次任务;
// 应用场景:页面resize 页面scroll, input输入效验,搜索 var throttle = function (func, delay) { let time = null; return function () { let _this = this; if(!time) { // 如果已经赋值就不要执行(赋值)了, time = setTimeout(function () { // 通过赋值 func.apply(_this, arguments); // func 参数 time = null; // 约定时间执行完后 赋值为null 新的生命周期开始 }, delay) } } }; function doSomfun(){ console.log('节流',Math.random()); }; window.addEventListener('scroll',throttle(doSomfun, 1000)) 复制代码
- js实现千分位?
function commafy(num) { return num && num .toString() .replace(/(\d)(?=(\d{3})+\.)/g, function($0, $1) { return $1 + ","; }); } console.log(commafy(1234567.90)); //1,234,567.90 复制代码
- 怎么让 a == 1 && a == 2 && a == 3 的返回值为 true ?
let a = {};
let b = 1;
a.valueOf = function () {
console.log(b);
return b++;
}
console.log(a == 1 && a == 2 && a == 3);
复制代码
- 能不能实现 a === 1 && a === 2 && a === 3 ?
let b = 1;
Object.defineProperty(window, 'a', {
get() {
console.log(b)
return b++;
}
})
console.log(a === 1 && a === 2 && a === 3);
复制代码
- 请问在js中,输入表达式 0.1 + 0.2 的结果是什么?
- 0.30000000000000004(能回答出来不是0.3,而是0.3后有若干个0和一个数字即可)
- 原因是浮点数和整数,在存储时的方法是不同的,因此相加的规则也是不同的;
- 浮点数是怎么存储的?
- 几进制
- 浮点数计算精度丢失问题?
- // todo
- 前端实现动画的方式有哪些?
- js:定时器改变 html 元素位置;
- CSS3:transition 和 animation,区别有哪些?
- 前者是针对属性的,当属性更改时,就会触发动画。使用起来更简单
- 后者是帧动画,通过 keyframes 来设置帧状态,从一帧过渡到另外一帧,使用起来更强大。
- canvas、SVG、WebGL
- gif
- flash
- 参考
- 当对动画进行性能优化时,有哪些可以使用的方案?
- 尽量减少DOM操作;
- 对于复杂的流程展示型动画,可以考虑使用canvas;
- 对于不方便使用js、css实现的动画,使用gif替代;
- 如果要进行错误捕获,有哪些办法?
- try、catch;
- window.onerror
- promise的catch
- 如何获取选中的单选框的值?
document.querySelectorAll("input[type='radio']").forEach(item => console.log(item.checked)); // 可以拿取选中的那个。 复制代码
- 写一个函数实现从从路径字符串中截取文件名的功能?
/** * 从零字符串中读取文件名. * @param {String}filePath * @return {String} * @example * getFileName('/user/document/abc.doc') //=> abc.doc; */ function getFileName(filePath) { // 最笨实现 // 可继续追问的点: // 1. 是否可以省去这个临时数组? let pathList = filePath.split('/')[0]; return pathList[ pathList.length - 1] || ''; // 正则实现 // 可继续追问的点: // 1. 用正则如何判断最后一级路径? let match = /\/([^/]*)$/.match(filePath); return match && match[1] ? match[1] : ''; // 最佳实现 let posi = filePath.lastIndexOf('/'); return posi > -1 ? filePath.slice(posi + 1) : ''; } 复制代码
- 找出数组中出现次数超过一半的数字JavaScript
/* --------- 找出最接近的值 ----------- */
/* 尽量不使用 JS 特有的语法糖,尽量不使用如 Array.sort 等语言特有的方法。*/
const arr2 = [1, 5, 9, 15, 28, 33, 55, 78, 99];
/**
* 返回最接近输入值的数字,如果有多个,返回最大的那个
* @param {number} n
* @return {number}
*/
function findMoreThanHalf(arr) {
// todo
}
// 测试用例
console.log(findMoreThanHalf([0])) // 0
console.log(findMoreThanHalf([0,1])) // -1
console.log(findMoreThanHalf([0,1,2,2])) // -1
console.log(findMoreThanHalf([0,1,2,2,2])) // 2
console.log(findMoreThanHalf([0,1,2,3,3,3])) // -1
console.log(findMoreThanHalf([0,1,2,3,3,3,3])) // 3
复制代码
- 数组洗牌
/* --------- 数组洗牌 ----------- */
/* 尽量不使用 JS 特有的语法糖,尽量不使用如 Array.sort 等语言特有的方法。*/
const arr = [3, 1, 22, 13, 5, 37, 42, 15, 5, 79, 38, 8, 28, 9];
/**
* 不创建新的数组,返回原有数组,打乱里面的数字顺序,考虑性能,时间复杂度越低越好
* @param {number[]} arr
* @return {number[]}
*/
function shuffle(arr) {
// todo
}
复制代码
- 如何拆解URL参数中queryString
const url = 'http://sample.com/?a=1&b=2&c=xx&d#hash';
/**
* 返回 URL 参数中的 QueryString
* @param url {string}
* @return {Object}
* @example
* parseQueryString('http://sample.com/?a=1&b=2&c=xx&d&&==#hash')
* -> { a: '1', b: '2', c: 'xx', d: '' };
*/
function parseQueryString(url) {
// todo
}
复制代码
- 用 DFS or BFS 来实现遍历DOM树
/**
* 从页面根节点开始,遍历页面上所有 DOM 元素,并且返回每个DOM标签的名称和出现次数
* 分别用「深度优先」和「广度优先」的策略来实现
* @param {HTMLElement} 页面根节点
* @return {Object} - 包含页面上所有标签名-该标签出现次数的对象,eg: { div: 10, p: 20, h1: 3 }
*/
function collectAllElements(e) {
// your code here...
}
复制代码
- 实现一个函数,可以将数组转化为树状数据结构
// 入参格式参考:
const arr = [
{ id: 1, name: 'i1' },
{ id: 2, name: 'i2', parentId: 1 },
{ id: 4, name: 'i4', parentId: 3 },
{ id: 3, name: 'i3', parentId: 2 },
{ id: 8, name: 'i8', parentId: 7 }
];
/* 可以将数组转化为树状数据结构,要求程序具有侦测错误输入的能力*/
function buildTree(arr) {
/**
* 此处写代码逻辑
*/
}
复制代码
- 从 document 开始遍历收集页面中 DOM 树上的所有元素,存放到数组中
/**
分别用「深度优先」和「广度优先」的策略来实现
@param {HTMLElement} - e
@return {HTMLElement[]}
*/
function collectAllElements(e) {
// your code here...
}
复制代码
- 实现下面的find方法
var data = [
{ userId: 8, title: 'title1'},
{ userId: 11, title: 'other'},
{ userId: 15, title: null},
{ userId: 19, title: 'title2'}
];
var find = function(origin) {
// your code here...
}
//查找data中,符合条件的数据,并进行排序
var result = find(data).where({
"title": /\d$/
}).orderBy('userId', 'desc');
console.log(result); // [{ userId: 19, title: 'title2'}, { userId: 8, title: 'title1' }];
复制代码
- 实现一个简单的模板引擎
var tpl = template('hey there {{ name }}
');
var div = document.createElement('div');
div.innerHTML = tpl({ name: 'Neo' });
document.body.appendChild(div);
复制代码
- 实现一个AST解析方法,解析下列输入,输出对应树形结构(区分标签、属性、内容等)
const htmlStr = `
"widget-body" data-spm-anchor-id="a1z4o.xxss.i3.14803e15bAFF41">
"ctr-val g-csscut-more" style="display: inline-block;vertical-align: top;width:200px;”>" href="positionDetail.htm?id=44106" title="欢迎应聘蚂蚁金服支付宝前端工程师-杭州、上海、北京、成都">欢迎应聘蚂蚁金服支付宝前端工程师-杭州、上海、北京、成都
`
function astParser(){
// todo
}
复制代码
- 用原生js实现拖拽效果
"container" style="border:1px solid red; position: absolute; width:100px; height: 100px">something
复制代码
- 实现自定义事件
// 2. 具备 off 方法解绑事件
function EventEmitter () {
// TODO
}
var emitter = EventEmitter();
emitter.on('foo', function(e){
console.log('listening foo event 1', e);
});
emitter.on('foo', function(e){
console.log('listening foo event 2', e);
});
emitter.on('bar', function(e){
console.log('listening bar event', e);
});
// 监听全部事件
emitter.on('*', function(e){
console.log('listening all events');
});
emitter.trigger('foo', {name : 'John'});
emitter.trigger('bar', {name : 'Sun'});
emitter.trigger('*', {name : 'Sun'});
emitter.off('foo');
复制代码
- 实现JS继承
var Class = {};
Class.create = function(props){
// TODO
};
var Animal = Class.create({
sleep : function(){
console.log("zzzzzz~");
}
});
var Person = Animal.extend({
constructor : function(){
this.type = "Person";
},
speak : function(){
console.log("hello world!");
}
});
var qitao = new Person("Qitao");
qitao instanceof Person
qitao instanceof Animal
复制代码
- 如何阻止事件冒泡?
- ?
- 常见测试题
var x = 1;
function ScopeTest(){
alert( x ); // undefined
var x = 'hello world';
alert( x ); //hello world
}
ScopeTest();
复制代码
// JS在执行每一段JS代码之前, 都会首先处理var关键字和function定义式(函数定义式和函数表达式)
function test(xxx){
alert(xxx); // function
var xxx = 123;
function xxx(){}
alert(xxx); //123
}
test(444); //先弹出function然后123.
复制代码
console.log(1);
setTimeout(function() {
console.log(2);
}, 0);
console.log(3);
// 132
复制代码
var x = 1;
function ScopeTest(){
alert( x ); // 1
}
复制代码
var name = 'laruence';
function echo()
{
alert(name);
}
function env()
{
var name = 'eve';
echo();
}
env(); // laruence
复制代码
-
如果你想要实现支持setter和getter特性的拷贝,该怎么实现?
- Object.defineproperties (定义属性) 和 Object.getOwnPropertyDescriptors(es2017,获取对象的多个属性)、Object.getOwnPropertyDescriptor(老一点,获取对象的单个属性的属性),但babel可以解决
-
如果遍历一个Object对象? for…in…, for…of… 的区别是什么? forEach、map、filter、some、every函数的区别?
- //TODO
-
body中添加li标签
在一个body中插入十个- 第i项
,考虑效率和性能
var str=''
',$body;
for(var i = 1;i<=10;i++){
str+='第'+i+'项 '
}
str+=''
$body=typeof document.querySelectorAll=='function'?document.querySelectorAll('body')[0]:document.getElementsByTagName('body')[0];
$body.innerHtml+=str;
复制代码
- 如何理解JavaScript原型链?、
- JavaScript中的每个对象都有一个prototype属性,我们称之为原型,而原型的值也是一个对象,因此它也有自己的原型,这样就串联起来了一条原型链,原型链的链头是object,它的prototype比较特殊,值为null。
- 原型链的作用是用于对象继承,函数A的原型属性(prototype property)是一个对象,当这个函数被用作构造函数来创建实例时,该函数的原型属性将被作为原型赋值给所有对象实例,比如我们新建一个数组,数组的方法便从数组的原型上继承而来。、
- 当访问对象的一个属性时, 首先查找对象本身, 找到则返回; 若未找到, 则继续查找其原型对象的属性(如果还找不到实际上还会沿着原型链向上查找, 直至到根). 只要没有被覆盖的话, 对象原型的属性就能在所有的实例中找到,若整个原型链未找到则返回undefined
- JavaScript的作用域和作用域链?
- JavaScript的作用域指的是变量的作用范围,内部作用域由函数的形参,实参,局部变量,函数构成,内部作用域和外部的作用域一层层的链接起来形成作用域链,当在在函数内部要访问一个变量的时候,首先查找自己的内部作用域有没有这个变量,如果没有就到这个对象的原型对象中去查找,还是没有的话,就到该作用域所在的作用域中找,直到到window所在的作用域,每个函数在声明的时候就默认有一个外部作用域的存在了
- 比如:bar找t变量的过程就是,先到自己的内部作用域中找,发现没有找到,然后到bar所在的最近的外部变量中找,也就是foo的内部作用域,还是没有找到,再到window的作用域中找,结果找到了
var t=4; function foo(){ var tem=12; funciton bar(){ var temo=34; console.log(t+" "+tem+" "+temo); } } 复制代码
- setTimeout和Promise在异步实现上,有什么区别?
- todo?
- 异步编程的实现方式?
- 回调函数
- 优点:简单、容易理解
- 不利于维护,代码耦合高
- 事件监听(采用时间驱动模式,取决于某个事件是否发生):
- 优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数
- 缺点:事件驱动型,流程不够清晰
- 发布/订阅(观察者模式)
- 类似于事件监听,但是可以通过‘消息中心’,了解现在有多少发布者,多少订阅者
- Promise对象
- 优点:可以利用then方法,进行链式写法;可以书写错误时的回调函数;
- 缺点:编写和理解,相对比较难
- Generator函数
- 优点:函数体内外的数据交换、错误处理机制
- 缺点:流程管理不方便
- async函数
- 优点:内置执行器、更好的语义、更广的适用性、返回的是Promise、结构清晰。
- 缺点:错误处理机制
- 回调函数
- 解释一下什么是eventloop(事件循环)?
- // todo
- 如果要渲染一个10000行的table, 什么办法能够优化渲染?
- 因为javascript是单线程,渲染10000行的数据会造成页面主线程被hang住,导致页面无响应,如果要渲染10000的数据可以通过setTimeout将10000条数据分片渲染,防止主线程被hang住
- new操作符具体可以干什么呢?
- 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
- 属性和方法被加入到 this 引用的对象中。
- 新创建的对象由 this 所引用,并且最后隐式的返回 this 。
- 如何清除字符串前后空格?
- // todo
- 工作中是如何设计后端 API 的?
- http, 状态码,错误码,json,restful,graphql