您的位置:首页 > 职场人生

熬夜吐血整理最全web前端面试题合辑(三)

2018-10-22 17:46 218 查看
版权声明:转载请注明出处 德拉 https://blog.csdn.net/Della0930/article/details/83274484

JavaScript篇

Javascript很多考题都出自红宝书(JavaScript高级程序设计)

  • JS 有哪些数据类型?

    基本数据类型:
    String Boolean Number Undefined Null
    (本质上null就是一个占位用的对象)ES6新增了
    Symbol
    (创建后独一无二且不可变的数据类型)
  • 引用数据类型:
    Object
    狭义的对象
    Array
    ,
    Function
  • 是否可以使用

    typeof bar === 'object'
    来检测
    bar
    是不是
    object
    类型,有何风险?

      有风险。
      typeof
      只能检测出
      String,Number,Boolean,Undefined,Object,Function
      这六种类型.
    1. typeof null
      返回的也是
      Object
      ,因为
      null
      本质上就是一个占位的对象.另一方面,数组
      Array
      也不能用
      typeof
      检测数据类型,因为同样会返回
      Object
      .
  • 认清

    Array
    的方法:

      console.log( bar instanceof Array) // 如果数组,返回true
    1. console.log( Array.isArray(bar)) //ES5方法
    2. console.log( Object.prototype.toString.call(bar) === '[object Array]')
    3. 终极判断数据类型的方法:
      //可以判断的类型有 Number, String, Boolean, Undefined, Null,Object,Function,Array
      console.log( Object.prototype.toString.call(arr).slice(8, -1));
      console.log( Object.prototype.toString.call(arr).slice(8, -1) === 'Array'])
  • 什么是

    window
    对象? 什么是
    document
    对象?

      window
      对象是指浏览器打开的窗口。
    • document
      对象是
      Documentd
      对象(
      HTML
      文档对象)的一个只读引用,
      window
      对象的一个属性。
  • undefined
    null
    的区别

      undefined
      代表定义未赋值
    • null
      表示定义并且赋值了,只是值为null
  • 介绍js有哪些内置对象?

      数据封装类对象:
      Object、Array、Boolean、Number
      String
    • 其他对象:
      Function、Arguments、Math、Date、RegExp、Error
  • 内存溢出与内存泄露

      内存溢出
        一种程序运行出现的错误
      • 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
    1. 内存泄露
        占用的内存没有及时释放
      • 内存泄露积累多了就容易导致内存溢出
      • 常见的内存泄露: 意外的全局变量
      • 没有及时清理的计时器或回调函数
      • 闭包
  • new操作符具体干了什么呢?
    1. 创建一个空对象,并且

    this
    变量引用该对象,同时还继承了该函数的原型。
    2. 属性和方法被加入到
    this
    引用的对象中。
    3. 新创建的对象由
    this
    所引用,并且最后隐式的返回 this 。

    var obj = {};
    obj.__proto__ = Base.prototype;
    Base.call(obj);
  • 对象的创建模式?

      Object
      构造函数模式
      /*
      一个人: name:"Tom", age: 12
      */
      var p = new Object()  //先创建空Object对象
      p = {} //此时内部数据是不确定的
      p.name = 'Tom'// 再动态添加属性/方法
      p.age = 12
      p.setName = function (name) {
      this.name = name
      }
      //测试
      console.log(p.name, p.age)//Tom 12
      p.setName('Bob')
      console.log(p.name, p.age)//Bob 12
      对象字面量模式
    var p = {
    name: 'Tom',
    age: 12,
    setName: function (name) {
    this.name = name
    }
    }
    //测试
    console.log(p.name, p.age)
    p.setName('JACK')
    console.log(p.name, p.age)
  • 工厂函数:通过工厂函数动态创建对象并返回(内置对象)
    function createPerson(name, age) { //返回一个对象的函数===>工厂函数
    var obj = {
    name: name,
    age: age,
    setName: function (name) {
    this.name = name
    }
    }
    return obj
    }
    
    // 创建2个人
    var p1 = createPerson('Tom', 12)
    var p2 = createPerson('Bob', 13)
  • 构造函数模式
    function Person(name, age) {
    this.name = name;
    this.age = age;
    this.setName = function(name){this.name=name;};
    }
    new Person('tom', 12);
  • 构造函数+原型的组合模式
    function Person(name, age) {
    this.name = name;
    this.age = age;
    }
    Person.prototype.setName = function(name){this.name=name;};
    new Person('tom', 12);
  • JavaScript原型,原型链 ? 有什么特点?

      函数的
      prototype
      属性(显示原型属性): 在定义函数时自动添加的, 默认值是一个空
      Object
      实例对象(独独Object不满足)
    • 所有函数都是Function的实例对象(包含Function)
      console.log(Function.__proto__===Function.prototype)//true
    • Object的原型对象是原型链尽头
      console.log(Object.prototype.__proto__) // null
    • 所有实例对象都有一个特别的属性:
      __proto__
      (隐式原型属性)在创建实例对象时被自动添加, 并赋值为构造函数的prototype值
    • 原型链: 访问一个对象的属性时,
    • 先在自身属性中查找,找到返回
    • 如果没有, 再沿着
      __proto__
      这条链向上查找, 找到返回
    • 如果最终没找到, 返回
      undefined
    • 别名: 隐式原型链
    • 作用: 查找对象的属性(方法)
    • 这样通过
      __proto__
      属性就形成了一个链的结构---->原型链
    • 当查找对象内部的属性/方法时,
      js
      引擎自动沿着这个原型链查找
  • Javascript如何实现继承?

      1 构造继承 2 原型继承 3 实例继承 4 拷贝继承
    //原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式。
    function Parent(){
    this.name = 'wang';
    }
    function Child(){
    this.age = 28;
    }
    Child.prototype = new Parent();//继承了Parent,通过原型
    
    var demo = new Child();
    alert(demo.age);
    alert(demo.name);//得到被继承的属性
  • 上下文作用域

  • 全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。
    当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找,
    直至全局函数,这种组织形式就是

    作用域链

    • 谈谈

      This(上下文)
      对象的理解。

      我们每次调用函数时,解析器都会将一个上下文对象作为隐含的参数传递进函数。使用
      this
      来引用上下文对象,根据函数的调用形式不同,
      this
      的值也不同。
    • this
      的不同的情况:
        以函数的形式调用时,
        this
        window
      1. 以方法的形式调用时,
        this
        就是调用方法的对象
      2. 以构造函数的形式调用时,
        this
        就是新创建的对象
      3. 使用
        call
        apply
        调用时,
        this
        时指定的那个对象
      4. 在事件中,
        this
        指向触发这个事件的对象,特殊的是,
        IE
        中的
        attachEvent
        中的
        this
        总是指向全局对象
        Window
  • call
    apply
    的区别?

      这两个方法都是函数对象的方法需要通过函数对象来调用
    • 通过两个方法可以直接调用函数,并且可以通过第一个实参来指定函数中
      this
    • 不同的是
      call
      是直接传递函数的实参而
      apply
      需要将实参封装到一个数组中传递
  • Javascript
    中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是?

      hasOwnProperty
  • 什么是立即执行函数?使用立即执行函数的目的是什么?

      概念:1. 声明一个匿名函数 2. 马上调用这个匿名函数
    • 为什么要用括号把函数包起来:为了兼容
      JS
      的语法
    • 作用: 隐藏内部实现 不污染外部命名空间(创建一个独立的作用域,这个作用域里面的变量,外面访问不到(即避免「变量污染」))
    • 以这个面试题为例,用立即执行函数给每个 li 创造一个独立作用域即可
    var liList = ul.getElementsByTagName('li')
    for(var i=0; i<6; i++){
    function(j){
    liList[j].onclick = function(){
    alert(j) // 0、1、2、3、4、5
    }
    }(i)
    }
    //在立即执行函数执行的时候,i 的值被赋值给 j,此后 j 的值一直不变。
    //i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的j「分别」
    //是 0、1、2、3、4、5。以上,就是立即执行函数的基本概念。
  • JSON
    的了解?

  • JSON
    (JavaScript Object Notation) 是一种轻量级的数据交换格式。 它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小.如:
    {"age":"12", "name":"back"}

    JSON字符串转换为JSON对象:
    var obj =eval('('+ str +')');
    var obj = str.parseJSON();
    var obj = JSON.parse(str);
    
    JSON对象转换为JSON字符串:
    var last=obj.toJSONString();
    var last=JSON.stringify(obj);
    • NaN是什么?它是什么类型?如何检测一个变量是不是NaN? 答案:
      NaN(not a Number)
      ,但是实际上它是
      Number
      类型,
      typeof NaN
      会返回
      number
      .这个东西比较厉害,因为
    • NaN === NaN //false
    • 你会发现它自己都不等于它自己,因此判断变量是否是它,不能使用
      ===
      ,可以使用
      isNaN()
      方法
    //检查变量是否是NaN
    isNaN(bar);
    Object.is(bar,NaN); //ES6方法,这个方法会修正JS中的一些小bug
    /* Object.is()方法,要求严格相等,且Object.is(NaN,NaN)会返回true */
    这两个方法结合起来用的作用在于判断变量 bar 是一个 NaN非数值,但不是NaN本身这个数
    /*补充一个*/
    var a = b = 3;
    //实际上等同于
    var a=b;
    b=3;
    • 数组的filter,以下输出结果是什么(2018拼多多前端原题)
    var arr = [1,2,3];
    arr[10] = 9;
    arr.filter((item)=> {
    return item === undefined?
    })
    
    //答案
    []

    解析: 是的,答案的确是[],不是[undefined x 7]。 首先,看下前两句执行后,arr是什么

    console.log(arr)
    //[1,2,3, emptyx7, 9]
    console.log(arr[5])
    //undefined

    undefined
    和数组保留的
    empty
    插槽并不是等同的,即使我们打印出相应的数据会显示
    undefined
    ,但是与js的
    undefined
    是不同的,除了
    arr.filter
    ,包括
    arr.map()
    函数都是会保留
    empty
    插槽的。

    • JS小数计算不准确的bug
    console.log(0.1 + 0.2);
    console.log(0.1 + 0.2 == 0.3);
    
    //答案: 0.30000000000000004
    false

    解析: 详细的解析见连接,这里说一下解决办法 0.1+0.2 != 0.3

    //解决办法
    parseFloat((0.1+0.2).toFixed(10));
    • 讨论实现判断变量是否是整数的函数isInter(x)的实现
      答案: 在ES6中,是有现成的方法Number.isInteger可以使用的。如果自己实现,思路是什么呢
    //1 异或运算
    function isInter(x) {
    return x ^ 0 === x
    }
    //2 取整
    return Math.round(x) === x  //同样可以用floor ceil
    //取余
    return (typeof x === 'number')&&(x % 1 === 0)
    • 写一个sum方法,可以实现以下两种调用方式
    console.log(sum(2,3)) //5
    console.log(sum(2)(3)) //5

    答案:

    //方法1
    var sum = function(x,y) {
    if(y === undefined) {
    return function(y) {
    return x + y;
    }
    }else {
    return x + y;
    }
    }
    
    //方法2
    var sum = function(x){
    if( arguments.length === 1) {
    return function (y) {
    return x + y;
    }
    } else {
    console.log('here');
    return arguments[0] + arguments[1];
    }
    }
    • 递归设计。 实现一个函数,给该函数一个DOM节点,函数访问其所有子元素(所有子元素,不仅仅是直接子元素),每次访问子元素的时候,并为其传一个callback。
      访问一个DOM tree,是一个经典的深度优先搜索的算法
    function Traverse(DOM,callback) {
    callback(DOM);
    var list = DOM.children;
    Array.prototype.forEach.apply(list,(item)=>{
    Traverse(item,callback); //递归
    })
    }
    • Array数组的flat方法实现(2018网易雷火&伏羲前端秋招笔试)
      Array的方法flat很多浏览器还未能实现,请写一个
      flat
      方法,实现
      扁平化嵌套数组
      ,如:
    Array
    var arr1 = [1, 2, [3, 4]];
    arr1.flat();
    // [1, 2, 3, 4]

    这个问题的实现思路和Deep Clone非常相似,这里实现如下:

    Array.prototype.flat = function() {
    var arr = [];
    this.forEach((item,idx) => {
    if(Array.isArray(item)) {
    arr = arr.concat(item.flat()); //递归去处理数组元素
    } else {
    arr.push(item)   //非数组直接push进去
    }
    })
    return arr;   //递归出口
    }

    神秘力量的新解法

    arr.prototype.flat = function() {
    this.toString().split(',').map(item=> +item )
    }
    1. toString方法,连接数组并返回一个字符串 '2,2,3,2,3,4'
    2. split方法分割字符串,变成数组['2','2','3','2','3','4']
    3. map方法,将string映射成为number类型2,2,3,2,3,4
    • 乱序的新定义
      以前面试的时候遇到要写打乱数组的题目,直接就是一句代码搞定
    arr.sort(() => Math.random() - 0.5);

    后面意识到这种方法并不能真正意义上去实现打乱
    这是参考别人实现的方法:sort()方法无用?

    function shuffle(arr) {
    /*
    即将它改造为一个对象,
    原来的值存储在键v中,同时给它增加一个键r,
    值为一个随机数,然后排序时比较这个随机数:
    */
    let new_arr = arr.map(i => ({v: i, r: Math.random()}));
    new_arr.sort((a, b) => a.r - b.r);
    arr.splice(0, arr.length, ...new_arr.map(i => i.v));
    
    return arr
    }
    /*这是测试代码*/
    let a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
    console.log(shuffle(a));
    • js
      延迟加载的方式有哪些?

      defer
      (只支持
      IE
      )和
      async
      、创建
      script
      ,插入到
      DOM
      中,加载完毕后
      callBack
      (用得最多)、按需异步载入
      js
  • 如何将浮点数点左边的数每三位添加一个逗号,如

    12000000.11
    转化为
    『12,000,000.11』
    ?

      (386485473.88).toLocaleString('en-US') // "386,485,473.88"
    //方法2:
    var separator=(num)=>{
    if(!num){
    return '0.00';
    };
    let str = parseFloat(num).toFixed(2);
    return str && str
    .toString()
    .replace(/(\d)(?=(\d{3})+\.)/g, function($0, $1) {
    return $1 + ",";
    });
    }
    
    separator(386485473.88) //"386,485,473.88"
  • 列举ES6新特性

      函数默认值、解构赋值 、模板字符串、
      let/const
      、新增函数库(
      Number String Array Obiect Math
      )、箭头函数
  • let
    const
    var
    的区别?

      let
      : 无变量提升、有块级作用域、不能重复声明
  • const
    :
      无变量提升、有块级作用域、禁止重复声明
    • 禁止重复赋值、必须赋初始值
  • var
    存在变量提升,可以重复声明,赋值
  • 箭头函数

    this
    的指向

      在箭头函数中,函数体内部没有自己的 this,默认在其内部调用 this 的时候,会自动查找其父级上下文的 this 对象(如果父级同样是箭头函数,则会按照作用域链继续向上查找)
  • 手写

    es6
    继承

  • promise的状态,链式调用,同步异步流程,唯一性

  • js
    for
    for in
    循环它们之间的区别?

      遍历数组时的异同:
      for
      循环 数组下标的
      typeof
      类型:
      number
      ,
      -
      for in
      循环数组下标的
      typeof
      类型:
      string
  • 遍历对象时的异同:
      for
      循环 无法用于循环对象,获取不到
      obj.length
      ;
    • for in
      循环遍历对象的属性时,原型链上的所有属性都将被访问,
    • 解决方案:使用
      hasOwnProperty
      方法过滤或
      Object.keys
      会返回自身可枚举属性组成的数组
  • js
    对数组去重,列出你的思路(两种以上)

    //第一种:原生方法去重,借助一个空数组实现去重,便于理解底层原理(unique函数带有参数)
    function unique(arr) {
    let a = [];
    //Array.prototype.forEach(function(item, index){}) : 遍历数组
    arr.forEach((item,index)=>{
    a.indexOf(item)===-1?a.push(item):'';
    })
    return a;
    };
    console.log(unique([1,3,3,5,7,1,1,3])); //[1,3,5,7];
    
    //第二种:
    /*第二种同上(unique函数,但是不带参数)
    拓展:需要注意的一点就是此函数可以传多个数组,但是要看arguments[index]
    决定执行哪个数组,默认是执行第一个*/
    function unique2() {
    let a = [];
    //Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
    Array.from(arguments[1]).forEach((item,index)=>{
    a.indexOf(item)===-1?a.push(item):'';
    })
    return a;
    }
    console.log(unique2([1,2,2,5,1,3,4,3],[1,1,5,55,4]);//[ 1, 5, 55, 4 ]
    
    //原理
    function unique2() {
    let a = [];
    //Array.prototype 可以换成[]
    Array.prototype.forEach.call(arguments[0],(item,index)=>{
    a.indexOf(item)===-1?a.push(item):'';
    })
    return a;
    }
    console.log(unique2([1,2,2,5,1,3,4,3],[1,1,5,55,4]);//[[ 1, 2, 5, 3, 4 ]]
    
    //第三种方法:  Array.from方法可以将Set结构转为数组
    //new Set + Array.from
    function unique3(arr) {
    return Array.from(new Set(arr));
    }
    console.log(unique3([1,2,2,5,1,3,4,3]));
    
    //第四种方法:最简单
    let arr = [1,2,5,5,1,3,4,3,7,9,7];
    let uniq = [...new Set(arr)];
    console.log(uniq);
    
    //第五种方法: 基于数组原型链的去重方法
    Array.prototype.uniq = function () {
    let a = [];
    this.forEach((item,index)=>{
    a.indexOf(item)===-1?a.push(item):'';
    })
    return a;
    }
    console.log([3,1,4,1,1,3].uniq());
  • 什么是闭包?手写一个闭包

      包含被引用变量(函数)的对象(通过
      Chrome
      工具查看)
  • 请将下列b函数进行修改,保证每次调用a都能+1(考闭包):

    function b(){
    var a=1;
    };
    function b(){
    var a=1;
    return ()=>{
    a++;
    return a;
    }
    };
    let c = b();
    c(); //2
    c(); //3
    c(); //4
  • 删除数组最后一个元素,改变原数组的方法?

      myArr.pop()
    • myArr.slice(myArr.length-1)
    • myArr.splice(myArr.length,1)
  • 列举常用的5个字符串操作方法

      string.slice()
      可以从一个字符串中截取指定的内容,并将截取到内容返回,不会影响原变量
  • string.substring()
      和slice()基本一致,不同的是它不能接受负值作为参数,如果设置一个负值,则会自动修正为0,
      substring()中如果第二个参数小于第一个,自动调整位置
  • string.substr()
      和slice()基本一致,不同的是它第二个参数不是索引,而是截取的数量
  • string.trim()
    去除前后空格
  • string.toUpperCase()
    将字符串转换为大写并返回
  • string.toLowerCase()
    将字符串转换为小写并返回
  • 列举常用的5个数组操作方法

      push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
  • 事件冒泡以及事件捕获。

  • 如何实现数组的随机排序?

  • /*第一种方法*/
    var arr = [1,2,3,4,5,6,7,8,9,10];
    function randSort1(arr){
    for(var i = 0,len = arr.length;i < len; i++ ){
    var rand = parseInt(Math.random()*len);
    var temp = arr[rand];
    arr[rand] = arr[i];
    arr[i] = temp;
    }
    return arr;
    }
    console.log(randSort1(arr));
    
    /*第二种方法*/
    var arr = [1,2,3,4,5,6,7,8,9,10];
    arr.sort(function(){
    return Math.random() - 0.5;
    })
    console.log(arr);
    
    /*第三种方法*/
    var arr = [1,2,3,4,5,6,7,8,9,10];
    function randSort2(arr){
    var mixedArray = [];
    while(arr.length > 0){
    var randomIndex = parseInt(Math.random()*arr.length);
    mixedArray.push(arr[randomIndex]);
    arr.splice(randomIndex, 1);
    }
    return mixedArray;
    }
    console.log(randSort2(arr));
    • 排序方法
      /*冒泡排序*/
      function bubbleSort (myArr) {
      var len = myArr.length;
      var i,j,stop;
      for (i = 0; i < len; i++) {
      for (j = 0; stop = len-i, j < stop; j++) {
      if (myArr[j] > myArr[j+1]) {
      [myArr[j],myArr[j+1]] = [myArr[j+1],myArr[j]];//交换元素
      }
      }
      
      }
      return myArr;
      }
      var res = bubbleSort([3,2,4,5,1]);
      console.log(res);//[1,2,3,4,5]
      
      /*选择排序*/
      function selectSort (myArr) {
      var len = myArr.length,
      min;
      var i,j;
      for (i = 0; i < len; i++) {
      min = i;
      for (j=i+1; j < len;j++) {
      if (myArr[j]<myArr[min]) {
      min = j;
      }
      }
      //如果i不是最小的,则互换
      if (i!= min) {
      [myArr[i],myArr[min]] = [myArr[min],myArr[i]];
      }
      }
      return myArr;
      }
      var res = selectSort([3,2,4,5,1]);
      console.log(res);//[1,2,3,4,5]
      
      /*插入排序*/
      function insertionSort(arr) {
      for(let i = 1; i < arr.length; i++) {
      for(let j = 0; j < i; j++) {
      if(arr[i] < arr[j]) {
      //在j位置新增一个元素arr[i]
      arr.splice(j, 0, arr[i]);
      //再把原来arr[i]所在的删除
      arr.splice(i+1, 1);
      break
      }
      console.log(arr); // 至今不明白为什么控制台输出是[2,3,4,5,1]
      
      }
      }
      }
      var arr = [3,2,4,5,1];
      insertionSort(arr);
      console.log(arr); //[1,2,3,4,5]
      
      /*归并排序*/
      function mergeSort(arr) {
      var merge = function(leftArr, rightArr) {
      var resultArr = []
      while(leftArr.length && rightArr.length) {
      resultArr.push(leftArr[0] <= rightArr[0] ? leftArr.shift() : rightArr.shift());
      }
      return resultArr.concat(leftArr).concat(rightArr)
      }
      if(arr.length < 2) return arr;
      let mid = parseInt(arr.length/2)  //取数组的中位下标,也可以用 arr.length >> 1
      return merge(mergeSort(arr.slice(0, mid)), mergeSort(arr.slice(mid)));
      }
      var res = mergeSort([3,2,4,5,1]);
      console.log(res);//[1,2,3,4,5]
      
      /*快速排序*/
      function quickSort(arr) {
      if (arr.length <= 1) {
      return arr //递归的出口
      }
      
      var left = [],
      right = [],
      current = arr.splice(0,1); //此时数组少了一个数(第一个)
      for (let i =0; i<arr.length; i++) {
      if (arr[i] < current) {
      left.push(arr[i]); // 放左边
      }else {
      right.push(arr[i]); //放右边
      }
      }
      return quickSort(left).concat(current,quickSort(right));
      }
      /*测试*/
      let res = quickSort([4,7,21,6,9,3,1]);
      console.log(res);//[1,3,4,6,7,9,21]
    • DOM操作——怎样添加、移除、移动、复制、创建和查找节点?
      这个面试的时候问了怎么用js动态控制插入节点
      (1)创建新节点
      createDocumentFragment() //创建一个DOM片段

      createElement() //创建一个具体的元素

      createTextNode() //创建一个文本节点

      (2)添加、移除、替换、插入
      appendChild()

      removeChild()

      replaceChild()

      insertBefore() //在已有的子节点前插入一个新的子节点

      (3)查找
      getElementsByTagName() //通过标签名称

      getElementsByName() //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)

      getElementById() //通过元素Id,唯一性
    • Promise
      怎么使用?

      -
      ES6
      Promise
      是一个构造函数,用来生成
      promise
      实例。 作用: 解决回调地狱(回调函数的层层嵌套, 编码是不断向右扩展, 阅读性很差)
    • 能以同步编码的方式实现异步调用
  • 使用
    Promise
    :
      创建
      promise
      对象
      let promise = new Promise((resolve, reject) => {
      //初始化promise状态为 pending
      //执行异步操作
      if(异步操作成功) {
      resolve(value);//修改promise的状态为fullfilled
      } else {
      reject(errMsg);//修改promise的状态为rejected
      }
      })
    1. 调用
      promise
      then()
      promise.then(function(
      result => console.log(result),
      errorMsg => alert(errorMsg)
      ));
      ---- --- --- ----- -------------------------
      promise.then(()=>{},()=>{}).then()...
      //使用promise封装处理ajax请求
      let request = new XMLHttpRequest();
      request.onreadystatechange = function () {
      
      }
      request.responseType = 'json';
      request.open("GET", url);
      request.send();
  • async/await
    语法了解吗?目的是什么
  • 概念:真正意义上去解决异步回调的问题,同步流程表达异步操作(本质是

    Generator
    的语法糖)

    * 不需要像Generator去调用next方法,遇到await等待,当前的异步操作完成就往下执行
    * 返回的总是Promise对象,可以用then方法进行下一步操作
    * async取代Generator函数的星号*,await取代Generator的yield
    * 语意上更为明确,使用简单,经临床验证,暂时没有任何副作用
    • 如何用正则实现 string.trim() //去除字符串前后的空格
      function trim(string){ return string.replace(/^\s+|\s+$/g, '')}
  • 写一个通用的事件侦听器函数。
  • // event(事件)工具集,来源:github.com/markyun
    markyun.Event = {
    // 页面加载完成后
    readyEvent : function(fn) {
    if (fn==null) {
    fn=document;
    }
    var oldonload = window.onload;
    if (typeof window.onload != 'function') {
    window.onload = fn;
    } else {
    window.onload = function() {
    oldonload();
    fn();
    };
    }
    },
    // 视能力分别使用dom0||dom2||IE方式 来绑定事件
    // 参数: 操作的元素,事件名称 ,事件处理程序
    addEvent : function(element, type, handler) {
    if (element.addEventListener) {
    //事件类型、需要执行的函数、是否捕捉
    element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
    element.attachEvent('on' + type, function() {
    handler.call(element);
    });
    } else {
    element['on' + type] = handler;
    }
    },
    // 移除事件
    removeEvent : function(element, type, handler) {
    if (element.removeEventListener) {
    element.removeEventListener(type, handler, false);
    } else if (element.datachEvent) {
    element.detachEvent('on' + type, handler);
    } else {
    element['on' + type] = null;
    }
    },
    // 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
    stopPropagation : function(ev) {
    if (ev.stopPropagation) {
    ev.stopPropagation();
    } else {
    ev.cancelBubble = true;
    }
    },
    // 取消事件的默认行为
    preventDefault : function(event) {
    if (event.preventDefault) {
    event.preventDefault();
    } else {
    event.returnValue = false;
    }
    },
    // 获取事件目标
    getTarget : function(event) {
    return event.target || event.srcElement;
    },
    // 获取event对象的引用,取到事件的所有信息,确保随时能使用event;
    getEvent : function(e) {
    var ev = e || window.event;
    if (!ev) {
    var c = this.getEvent.caller;
    while (c) {
    ev = c.arguments[0];
    if (ev && Event == ev.constructor) {
    break;
    }
    c = c.caller;
    }
    }
    return ev;
    }
    };
    • 刁钻代码题
    • a.x = a = {}
      问 a.x 是多少?
      undefined
    var a = {n:1};
    var b = a;
    a.x = a = {n:2};
    • (a ==1 && a== 2 && a==3)
      可能为
      true
      吗?

      a = {
      value: 0,
      toString(){
      a.value += 1
      return a.value
      }
      }
    • ["1", "2", "3"].map(parseInt)
      答案是多少?详细解析

      parseInt()
      函数能解析一个字符串,并返回一个整数,需要两个参数 (
      val
      ,
      radix
      ),其中
      radix
      表示要解析的数字的基数。【该值介于
      2
      ~
      36
      之间,并且字符串中的数字不能大于
      radix
      才能正确返回数字结果值】;
    • 但此处
      map
      传了
      3
      个 (
      element
      ,
      index
      ,
      array
      ),我们重写
      parseInt
      函数测试一下是否符合上面的规则。
      function parseInt(str, radix) {
      return str+'-'+radix;
      };
      var a=["1", "2", "3"];
      a.map(parseInt);  // ["1-0", "2-1", "3-2"] 不能大于radix
      /* 因为二进制里面,没有数字3,导致出现超范围的radix赋值和不合法的进制解析,
      才会返回NaN所以["1", "2", "3"].map(parseInt) 答案也就是:[1, NaN, NaN]*/
  • 以下两个函数是否等价

  • function foo1()
    {
    return {
    bar: "hello"
    };
    }
    
    function foo2()
    {
    return
    {
    bar: "hello"
    };
    }
    console.log(foo1()); // {bar : "hellp"}
    console.log(foo2()); // undefined
    答案:不等价!!
    注意return 后面大括号的位置,第二个函数js会默认return 后面返回的东西(是空),等价于
    return undefined
    {xxx}   //后面当然,当然是写了也白写
    • 事件是?IE与火狐的事件机制有什么区别? 如何阻止冒泡?
      1. 我们在网页中的某个操作(有的操作对应多个事件)。例如:当我们点击一个按钮就会产生一个事件。是可以被

      JavaScript
      侦测到的行为。
      2. 事件处理机制:
      IE
      是事件冒泡、
      Firefox
      同时支持两种事件模型,也就是:捕获型事件和冒泡型事件;
      3.
      ev.stopPropagation();
      (旧
      ie
      的方法
      ev.cancelBubble = true;

    • 如何实现深拷贝?

      理想方案:(但不能处理函数数据)
      function clone(object){ let _obj=JSON.parse(JSON.stringify(obj))}
  • 保险做法
    function clone(obj){
    if(!obj&& typeof obj!== 'object'){
    return;
    }
    var newObj=obj.constructor===Object?{}:[];
    for(var key in obj){
    newObj[key] =(obj[key]&&typeof obj[key]==='object')?clone(obj[key]):obj[key];
    }
    return newObj;
    }
  • 你对重绘、重排的理解?

      首先网页数次渲染生成时,这个可称为重排;
    • 修改
      DOM
      、样式表、用户事件或行为(鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等)这些都会导致页面重新渲染,那么重新渲染,就需要重新生成布局和重新绘制节点,前者叫做"重排",后者"重绘";
    • 减少或集中对页面的操作,即多次操作集中在一起执行;
    • 总之可以简单总结为:重绘不一定会重排,但重排必然为会重绘。
    • 更详细的可以看阮老师分析
  • 项目上线前,能做哪些优化?

      图片预加载,
      css
      样式表放在顶部且link链式引入,
      javascript
      放在底部
      body
      结束标签前;
    • 使用
      dns-prefetch
      对项目中用到的域名进行
      DNS
      预解析,减少
      DNS
      查询,如:
      <link rel="dns-prefetch" href="//github.com"/>
      ;
    • 减少http请求次数:图片静态资源使用
      CDN
      托管;
      API
      接口数据设置缓存,
      CSS Sprites/SVG Sprites
      ,
      JS
      CSS
      源码压缩、图片大小控制合适,使用
      iconfont
      (字体图标)或
      SVG
      ,它们比图片更小更清晰,网页
      Gzip
      压缩;
    • 减少
      DOM
      操作次数,优化
      javascrip
      t性能;
    • 减少
      DOM
      元素数量,合理利用
      :after、:before
      等伪类;
    • 避免重定向、图片懒加载;
    • 前后端分离开发,资源按需加载,最好能做到首屏直出(即服务端渲染);
    • 避免使用
      CSS Expression
      css
      表达式)又称
      Dynamic properties
      (动态属性)
    • 多域名分发划分内容到不同域名,解决浏览器域名请求并发数问题,同时也解决了请求默认携带的
      cookie
      问题;
    • 尽量减少
      iframe
      使用,它会阻塞主页面的渲染;
    • 对所有资源压缩
      JavaScript
      CSS
      字体
      图片
      等,甚至
      html
      ;
  • DOM 清空子元素的方法

  • <!--调用函数 删除-->
    <input type="button" onclick="deleteChildren('#bbb');" value="删除所有子元素" />
    function deleteChildren (a) {
    //获取父元素
    var parentNode = document.querySelector(a);
    //判断是否包含子元素
    if (parentNode.hasChildNodes()) {
    var len = parentNode.childNodes.length;//子元素的个数
    for (var i = 0; i < len; i++) {
    parentNode.removeChild(parentNode.childNodes[0]);//从第一个元素开始删除
    }
    }
    }

    参考文章在这

    阅读更多
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: