前端面试基础知识点总结

1,997 阅读4分钟

1.JavaScript有几种类型的值?以及内置对象

  • 栈:原始数据类型(Undefined,Null,Boolean,Number、String、symbol)

  • 堆:引用数据类型(object、array、function) 两种类型的区别是:存储位置不同; 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储; 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体

  • Object 是 JavaScript 中所有对象的父对象 数据封装类对象:Object、Array、Boolean、Number 和 String 其他对象:Function、Arguments、Math、Date、RegExp、Error

2.如何判断数据类型?

推荐使用Object.prototype.toString方法进行数据类型判断,因为typeOf不能准确的判断出复杂数据类型,instanceOf只能判断复杂数据类型,constructor属性容易被篡改。

使用该方法我们可以封装一个isType方法来对类型进行判断

const type = (o) => {
    let s = Object.prototype.toString.call(o);
    return s.match(/\[object (.*?)\]/)[1].toLowerCase();
};
[
    'Undefined',
    'Null',
    'String',
    'Number',
    'Boolean',
    'Object',
    'Array',
    'Function',
    'RegExp'
].forEach((t) => {
    type['is' + t] = (o) => {
        return type(o) === t.toLowerCase();
    };
});
type.isObject({});
type.isArray([]);

3.一道闭包和运算符优先级的面试题?

var a=0,b=0;
function A(a){
    A = function(b){
        alert(a+b++);
    }
    alert(a++);
}
A(1); //1
A(2); //4
  • A(1)变量A被赋值的funtion的内部有调用变量a,形成闭包alert(1)后,内容中的a存在并变成了2,所以A(2)结果为4。

4.设计一个异步任务类 Task?当任务函数执行 next 的时候,会跳转到下一个任务函数执行

class Task {
    constructor() {
        this.taskIndex = 0
        this.taskList = []
        this.stopRun = false
    }
    add(fn,context, ...args) {
        const next = () => {
            this.taskIndex++
            if (!this.stopRun && this.taskList[this.taskIndex]) {
                this.run()
            }
        }
        this.taskList.push(fn.bind(context, next, ...args))
        return this
    }
    run() {
        this.taskList[this.taskIndex]()
    }
    stop() {
        this.stopRun = true
    }
}

function task1(next) {
    setTimeout(() => {
        console.log(1)
        next()
    },1000)
}

function task2(next,b) {
    setTimeout(() => {
        console.log(b)
        next()
    },1000)
}

let task = new Task()
task.add(task1).add(task2,null,3)
task.run()

5.ES6箭头函数this问题?

var name = 'window';
var obj1 = {
    name: 'obj1',
    fun1() {
        console.log(this.name);
    },
    fun2: () => {
        console.log(this.name);
    },
    fun3() {
      return () => {
          console.log(this.name);
      }  
    },
    fun4: () => {
        return () => {
            console.log(this.name);
        }
    }
};
obj1.fun1(); //obj1
obj1.fun2(); // window
obj1.fun3()(); //obj1
obj1.fun4()(); //window

非箭头函数和箭头函数的this指向区别:非箭头函数this的指向不是函数被创建时绑定,而是被怎么样的方式调用时绑定的。而箭头函数刚好相反,箭头函数的this指向是函数被创建时绑定的,它的指向就是当前词法作用域中的this,并且不会因为被怎么样的方式调用改变绑定。所以箭头函数的this指向关键是判断其定义时的词法作用域环境是哪个对象。

6.Array()和Array.of()区别?

    Array(); //[]
    Array(3); //[ , , ]并不是[3]
    Array(1, 2, 3); //[1, 2, 3]
  • Array方法没有参数、一个参数、三个参数时,返回结果都不一样。只有当参数个数不少于 2 个时,Array()才会返回由参数组成的新数组。参数个数只有一个时,实际上是指定数组的长度。
    Array.of(); //[]
    Array.of(3); //[3]
    Array.of(1, 2, 3); //[1, 2, 3]
  • 相对于Array方法,Array.of()在没有参数、一个参数、三个参数时,返回的都是数组,完全可以替代Array方法。

7.js获取宽高位置的常见方式区别?clientWidth,offsetWidth,scrollWidth

下面是css盒子模型图,css样式如下:

div {
    width: 100px;
    height: 100px;
    padding: 10px;
    border: 10px solid #ccc;
    margin: 10px;
    box-sizing: content-box;
}

以此div为例,我们说下几种获取宽高方式的区别:

  • clientWidth(120) = width + 左右padding;
  • clientHeight(120) = height + 上下padding;
  • clientLeft(10) = border-left(左边框厚度);
  • clientTop(10) = border-top(上边框厚度);
  • offsetWidth(140) = width + 左右padding + 左右boder;
  • offsetHeith(140) = height + 上下padding + 上下boder;
  • offsetTop:当前元素上边框外边缘到第一个已定位父级(offsetParent)上边框 内边缘的距离。一直往上找,如果父级都没有定位,则分别是到body顶部的距离。offsetLeft类似;
  • scrollWidth:获取指定标签内容层的真实宽度(可视区域宽度+被隐藏区域宽度)当前元素的scrollWidth可以理解为横向滚动条宽度;scrollHeight类似。
  • scrollTop :内容层顶部 到 可视区域顶部的距离;
  • scrollLeft:内容层左端 到 可视区域左端的距离;