js base

  • 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
  • 列举数据相关的常用方法
    • 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

转载于:https://juejin.im/post/5c9a047b5188251e592be053

你可能感兴趣的:(js base)