js基础面试题

本文最后更新于:2023年12月5日 晚上

基础部分

数据类型

五种简单数据类型: undefined, null, boolean, number, string

一种复杂数据类型: object

另外按照存储方式分为值类型和引用类型

有三大引用类型: object, array, function

typeof 返回哪些数据类型

array, object, null 都返回 object

function 返回 function

例举 3 种强制类型转换 和 2 种隐试类型转换

强制: parseInt(), parseFloat(), Number()

隐式: == 等等

split() 和 join() 的区别

前者是将字符串切割成数组的形式, 后者是将数组转换成字符串

pop() push() unshift() shift()

pop() 尾部删除, push() 尾部添加

shift() 头部删除, unshift() 头部添加

事件绑定 和 普通事件 有什么区别

普通添加事件, 最下面的事件会覆盖上面的, 而事件绑定(addEventListener)就不会

事件捕获 和 冒泡

事件的三个阶段: 捕获, 目标, 冒泡。

addEventListener 的第三个参数 默认 false 冒泡阶段触发, true 捕获阶段触发。

冒泡阶段触发就是先触发内部元素的事件。

捕获阶段触发就是先触发外部元素的事件。

call 和 apply 以及 bind() 的区别

call() 和 apply() 是在执行函数的时候调用,临时改变函数内部的 this 指向。两者的唯一区别就是 call 传入参数列表,apply 传入参数数组。

bind() 是创建新函数,在创建函数的时候调用。例如: f = fn.bind(xx) 把 fn 函数内部的 this 指向 xx 对象, 然后就生成可新函数 f, 以后无论怎么调用函数 f, 他里面的 this 都是指向 xx。

es6 class

严格模式

如果没有指定 this,则 this 值就将为 undefined。

构造函数

constructor 方法是一个特殊的方法, 这种方法用于创建和初始化一个由 class 创建的对象, 一个类只能有一个名为 “constructor” 的特殊方法。

原型方法

和 PHP 类一样, 只是没有 function 关键字。

静态方法

static 关键字用来定义一个类的静态方法。调用静态方法不需要实例化类,但不能通过实例化一个实例调用静方法。静态方法通常用于为一个应用程序创建工具函数。

extends

如果子类中存在构造函数,则需要在使用 this 之前需要先调用 super()。

super 关键字

super 这个关键字, 既可以当作函数调用, 也可以当做对象使用, 这两种情况下, 它的用法完全不同.

  1. super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。注意,super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B的实例,因此super()在这里相当于A.prototype.constructor.call(this)。作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错。
  2. super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

es5 和 es6 的继承

es5

  1. 借用构造函数, 缺点: 无法继承原型链上的属性和方法.

    //子构造函数
    function Sub() {
     Super.call(this)
    }
  2. 原型链继承:

    子构造函数.prototype = new 父构造函数() //实现继承
    子构造函数.prototype.constructor = 子构造函数 //添加 constructor

    缺点: 不能给父构造函数传参,

  3. 组合继承: 借用构造函数 + 原型链继承

    //子构造函数
    function Sub() {
     Super.call(this) //第一次调用
    }
    Sub.prototype = new Super() //第二次调用
    Sub.prototype.constructor = Sub

    缺点: 无论什么情况, 都会调用两次超类型构造函数, 一次是在创建子类型原型的时候, 一次是在子类型构造函数的内部

  4. 寄生式继承 : 创建一个仅仅用于封装过程的函数, 然后在内部以某种方式增强对象, 最后返回对象

    function object(o) {
     function F() {}
     F.prototype = o
     return new F()
    }
    function createSubObj(original) {
     var clone = object(original) //object() 是ES5前Object.create()的非规范化实现
     return clone
    }
  5. 寄生组合式继承

    //Object.create 创建一个新对象, 使用现有的对象来提供创建的对象的 __proto__
    function inheritPrototype(Super, Sub) {
     var superProtoClone = Object.create(Super.prototype) //创建一个空的新对象, 指定其 __proto__
     Sub.prototype = superProtoClone //修改子构造函数的prototype
     Sub.prototype.constructor = Sub //修改子构造函数的prototype.constructor
    }
    function Super() {
     this.property = "Super Property"
     this.xx = "xxx"
    }
    function Sub() {
     Super.call(this)
     this.property = "Sub Property"
    }
    inheritPrototype(Super, Sub)
    var sub = new Sub()
    console.dir(sub)

es6

es6 的继承主要是 class 的继承

基本用法: class 通过 extends 关键字实现继承, 这比 es5 的通过修改原型链实现继承, 要清晰和方便的多

有哪些内置的构造函数

  1. Object()
  2. Function()
  3. Array()
  4. RegExp()
  5. Number()
  6. String()
  7. Boolean()
  8. Date()
  9. Error()

常用的内置对象有哪些, 并列举该对象的常用方法

DOM 节点的增删改查

手写一个闭包

希望访问在不同作用域中的变量, 就需要使用闭包。

闭包的作用, 就是保存自己私有的变量, 通过提供的接口(方法)给外部使用, 但外部不能直接访问该变量

//希望在另一个作用域访问, 访问fn中的name这个局部变量
function fn() {
 var name = "zs"
 return () => {
  return name
 }
}
var f = fn()
var n = f()
console.log(n)

变量提升

仅提升, 不初始化

代码实现数组排序并去重

简单方法 :

function fn(arr) {
 arr.sort((a, b) => a - b)
 return [...new Set(arr)]
}
var arr = [1, 1, 2, 9, 9, 6, 5, 3]
fn(arr)

冒泡 + 双重遍历去重 :

function fn(arr) {
 let length = arr.length,
  i,
  j,
  k,
  l
 //冒泡排序
 for (i = 0; i < length - 1; i++) {
  for (j = 0; j < length - 1; j++) {
   if (arr[j] < arr[j + 1]) {
    ;[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
   }
  }
 }
 //双重遍历去重, 外循环从 0 到 length, 内循环从 k+1 到 length, 将重复的值去掉
 for (k = 0; k < arr.length; k++) {
  let c = arr[k]
  for (l = k + 1; l < arr.length; l++) {
   if (arr[l] == c) {
    arr.splice(l, 1)
    l-- // splice后, 数组长度减一, 所以要 l--
   }
  }
 }
 return arr
}

var arr = [1, 1, 2, 9, 9, 6, 5, 3]
fn(arr)

合并两个有序数组并排序

要求不能直接合并排序,要通过循环插入的方式合并排序

var a1 = [2, 3, 4, 6, 7, 1000]
var a2 = [1, 2, 3, 2000]

var i = a1.length
while (i--) {
 var j = a2.length - 1
 if (j === -1) {
  break
 }
 var a2v = a2[j]
 a2v >= a1[i] && a1.splice(i + 1, 0, a2.pop()) && i++
}
a1 = a2.concat(a1)
console.log(a1)

实际工作部分

出一套适应不同分辨率, 不同终端的前端方案实现方案是什么

  1. 流式布局, 就是百分比布局.
  2. 响应式布局
  3. rem 布局, rem 只相对 html 根元素的 font-size , 所以将 html 的 font-size 设置为 100px

如何实现跨域

  1. JSONP 已淘汰

  2. CORS

  3. 服务器跨域

  4. postmessage html5 中新增的方法

对象和类

在 js 中没有类, 所以在 js 中所谓的 类 就是构造函数, 对象是由构造函数创建

JS 的垃圾回收机制

如果一个对象不再被引用就会被 GC 回收, 如果两个对象互相引用, 而不再被第三者引用, 那么这两个互相引用的对象也会被回收

正则表达式

捕获异常

H5 有哪些新特性

  1. 拖拽释放
  2. 语义化更好的内容标签
  3. 音频视频
  4. 画布
  5. 地理
  6. 本地离线缓存
  7. sessionStorage
  8. 表单控件
  9. 新的技术

如何实现浏览器多个标签之间的通信

调用 localstorage, cookies 等本地存储方式


js基础面试题
http://blog.lujinkai.cn/前端/JavaScript/js基础面试题/
作者
像方便面一样的男子
发布于
2020年12月6日
更新于
2023年12月5日
许可协议