前端面试基础Javascript 篇

217 阅读5分钟

写本文的目的是巩固一下前端的一些基础,互相交流一下,做一个综合的归纳

前端面试基础HTML篇

前端面试基础CSS篇

前端面试基础Javascript 篇

Javascript

面试Javascript方面的一些问题,或者介绍,持续更新

1.JS的数据类型

String
Number
Boolean
Undefined
BigInt
Symbol
null
Object
Function

2.作用域

JavaScript 的静态作用域链与“动态”闭包链

ECMAScript 变量可以包含两种不同类型的数据:原始值和引用值。

原始值(primitive value)就是最简单的数据

引用值(reference value)则是由多个值构成的对象。在把一个值赋给变量时,JavaScript 引擎必须确定这个值是原始值还是引用值。引用值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存位置,因此也就不能直接操作对象所在的内存空间。在操作对象时,实际上操作的是对该对象的引用(reference)而非 实际的对象本身。为此,保存引用值的变量是按引用(by reference)访问的。

JavaScript采用的是词法作用域,函数的作用域基于函数创建的位置。

3.原型、原型链

JavaScript深入之从原型到原型链

关于原型链,我就不重复了,有很多总结的文章

Function.prototype.xxx 
创建的function通过原型链,就能获取到原型上的方法

Object.prototype.xxx 
创建的object通过原型链,就能获取到原型上的方法

xxx.__proto__ == Xxx.prototype
xxx.prototype.__proto__ == Object.prototype.xxx

4.变量声明和函数声明

JavaScript深入之执行上下文栈

浅谈JS变量提升

函数提升优先级高于变量提升,当函数声明与变量名相同时,在变量赋值前,函数声明依旧是函数声明,不会被覆盖;当变量赋值后,函数声明被同变量覆盖。

1.第一个示例

console.log(typeof a);
a();
var a = 3;
function a() {
 console.log(typeof a);
}
console.log(typeof a);
a = 6;
a();

答案

"function"

"function"

"number"

"a is not a function"

2.第二个示例

console.log(a);

console.log(typeof f);

var flag = true;

if (!flag) {
    var a = 1;
};

if (flag) {
    function f(a) {
        f = a;
        console.log("1");
    };
}
console.log(typeof f);
"undefined"

"undefined"

"function"

在非严格模式下,代码块中,只有使用 var 声明的变量和函数声明是可以提升的,但是函数声明只能将函数的名字提升出去

3.第三个示例

function f() {
    console.log(typeof f); //function
    // var f = 3;
    f = 3;
   console.log(typeof f); //number
};

f();

var s = function s() {
    console.log(typeof s); //function
    // var s = 3;
    s = 3;
    console.log(typeof s); //function 
};

s();

上述代码中,函数f是具名函数,函数s是函数表达式。具名函数中,可以在函数内部改变函数名,而函数表达式,如果有函数名,则它的函数名只能作用在其自身作用域中,且不可改变改变函数名。

以上的代码是copy自浅谈JS变量提升

5.Promise实现

9k字 | Promise/async/Generator实现原理解析

6.js - 设计模式

JavaScript设计模式es6(23种

js - 观察者模式与订阅发布模式

7.虚拟DOM

从了解到深入虚拟DOM和实现diff算法

8.手写 call、apply、bind 原理基础版

1.call

Function.prototype.myCall = function (ctx, ...arg) {
  ctx.fn = this
  const result = ctx.fn(...arg)
  delete ctx.fn
  return result
}
var obj = {
  a: 5,
  b: 1
}
function abc(c, d) {
  console.log(this.a - this.b - c - d)
  return this.a - this.b - c - d
}
console.log('abc.myCall(obj, 1, 5)', abc.myCall(obj, 1, 5)) // - 2

2.apply

apply和call类似的,只不过传参不一样, apply这里自己初学js时留过一个坑,自己没看清api介绍,以为被apply后的函数,接受也必须是一个数组,后来意识到自己当时有多粗心

apply第二个参数可以为arguments

Function.prototype.myApply = function (ctx, arg) {
  ctx.fn = this
  const result = ctx.fn(...arg)
  delete ctx.fn
  return result
}
var obj = {
  a: 5,
  b: 1
}
function abc(c, d) {
  console.log(this.a - this.b - c - d)
  return this.a - this.b - c - d
}
console.log('abc.myApply(obj, 1, 5)', abc.myApply(obj, [1, 5])) // - 2

3.bind

bind和call接受参数是一样的,只不过会返回一个函数,通过返回函数执行call或者apply

Function.prototype.myBind = function (ctx, ...arg) {
  const that = this
  return function () {
    // 结合上面的apply方法
    return that.myApply(ctx, arg)
  }
}
console.log('abc.myBind(obj, 1, 5)', abc.myBind(obj, 1, 5)()) // - 2

9. 手写简版 new

function myNew() {
  var obj = new Object()
  var Fn = [].shift.call(arguments);
  obj._proto_ = Fn.prototype
  var res = Fn.call(obj, arguments)
  return typeof res === 'object' ? res : obj;//确保构造器总是返回一个对象
}

10.节流和防抖

1.防抖

function debounce(fb, wait) {
  var timeout
  return function () {
    var that = this;
    var args = arguments;
    clearTimeout(timeout)
    setTimeout(function () {
      fb.apply(that, args)
    }, wait)
  }
}

2.节流

function throttle(fn) {
  var timeout
  return function () {
    var that = this;
    var args = arguments;
    if (timeout) return
    setTimeout(function () {
      fn.apply(that, args)
      timeout = null
    }, wait)
  }
}

function throttle(fn, wait) {
  var previous = 0;
  return function () {
    var that = this;
    var args = arguments;
    var now = +new Date();
    if (now - previous > wait) {
      fn.apply(that, args)
      previous = now
    }
  }
}

11.浅拷贝和深拷贝

浅拷贝和深拷贝主要是对引用的考察

1.浅拷贝

  • Object.assign()
  • Array.prototype.concat()
  • ...展开弗

2.深拷贝

JSON.parse(JSON.stringify()); 
这个是最简单的,但是弊端
拷贝其他引用类型、拷贝函数、循环引用等一些缺陷
function deepClone(obj) {
  if (typeof obj !== 'object') return;
  var newObj = obj instanceof Array ? [] : {};
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
    }
  }
  return newObj;
}

JavaScript专题之深浅拷贝

12.实现JSON.parse

function parse(jsonStr){
 return eval("(" + jsonStr + ")");
}

13.数组排序、去重

1.排序

十大经典排序算法总结

2.去重

1. [...new Set(arr)]
2. 类似indexof判断是否有,无就添加

14.数组扁平化

递归的方法

function flat(arr) {
  var newArr = [];
  for (var i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      newArr = newArr.concat(flat(arr[i]))
    }
    else {
      newArr.push(arr[i])
    }
  }
  return newArr;
}

toString

toString().split(',')

es6

flat(Infinity)

15.instanceof的实现

function instance_of(L, R) {
  let O = L.__proto__
  const P = R.prototype
  while (O) {
    if (O === P) return true
    O = O.__proto__
  }
  return false
}

16.JsonP的原理

JavaScript跨域请求jsonp原理

17.事件机制/Event Loop

从event loop规范探究javaScript异步及浏览器更新渲染时机

这一次,彻底弄懂 JavaScript 执行机制

后续再慢慢补充下