专业编程教程与实战项目分享平台

网站首页 > 技术文章 正文

前端一轮面试题(js篇) 持续更新 前端面试题简书

ins518 2024-10-05 20:31:34 技术文章 15 ℃ 0 评论



JS数据类型

JS基本有5种简单数据类型:String,Number,Boolean,Null,Undefined。引用数据类型:Object,Array,Function。

判断数据类型的方法

在写业务逻辑的时候,经常要用到JS数据类型的判断,面试常见的案例深浅拷贝也要用到数据类型的判断。

typeof

Bash
console.log(typeof 2);               // number
console.log(typeof true);            // boolean
console.log(typeof 'str');           // string
console.log(typeof undefined);       // undefined
console.log(typeof []);              // object 
console.log(typeof {});              // object
console.log(typeof function(){});    // function
console.log(typeof null);            // object
复制代码

优点:能够快速区分基本数据类型 缺点:不能将Object、Array和Null区分,都返回object

instanceof

Bash
console.log(2 instanceof Number);                    // false
console.log(true instanceof Boolean);                // false 
console.log('str' instanceof String);                // false  
console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);                   // true
复制代码

优点:能够区分Array、Object和Function,适合用于判断自定义的类实例对象 缺点:Number,Boolean,String基本数据类型不能判断

Object.prototype.toString.call()

Bash
var toString = Object.prototype.toString;
 
console.log(toString.call(2));                      //[object Number]
console.log(toString.call(true));                   //[object Boolean]
console.log(toString.call('str'));                  //[object String]
console.log(toString.call([]));                     //[object Array]
console.log(toString.call(function(){}));           //[object Function]
console.log(toString.call({}));                     //[object Object]
console.log(toString.call(undefined));              //[object Undefined]
console.log(toString.call(null));                   //[object Null]
复制代码

优点:精准判断数据类型 缺点:写法繁琐不容易记,推荐进行封装后使用

var,let,const的区别

let 为 ES6 新添加申明变量的命令,它类似于 var,但是有以下不同:

  • var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象
  • let 声明的变量,其作用域为该语句所在的代码块内,不存在变量提升
  • const声明的变量不允许修改

null和undefined区别

Undefined类型只有一个值,即undefined。当声明的变量还未被初始化时,变量的默认值为undefined。用法:

  • 变量被声明了,但没有赋值时,就等于undefined。
  • 调用函数时,应该提供的参数没有提供,该参数等于undefined。
  • 对象没有赋值的属性,该属性的值为undefined。
  • 函数没有返回值时,默认返回undefined。

Null类型也只有一个值,即null。null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。用法

  • 作为函数的参数,表示该函数的参数不是对象。
  • 作为对象原型链的终点。

定义函数的方法

  1. 函数声明
Bash
//ES5
function getSum(){}
function (){}//匿名函数
//ES6
()=>{}
复制代码
  1. 函数表达式
Bash
//ES5
var getSum=function(){}
//ES6
let getSum=()=>{}
复制代码
  1. 构造函数
Bash
const getSum = new Function('a', 'b' , 'return a + b')
复制代码

JS作用域的理解

JS中的作用域分为两种:全局作用域和函数作用域。函数作用域中定义的变量,只能在函数中调用,外界无法访问。没有块级作用域导致了if或for这样的逻辑语句中定义的变量可以被外界访问,因此ES6中新增了let和const命令来进行块级作用域的声明。

更多作用域的了解可以看JS作用域

闭包的理解

简单来说闭包就是在函数里面声明函数,本质上说就是在函数内部和函数外部搭建起一座桥梁,使得子函数可以访问父函数中所有的局部变量,但是反之不可以,这只是闭包的作用之一,另一个作用,则是保护变量不受外界污染,使其一直存在内存中,在工作中我们还是少使用闭包的好,因为闭包太消耗内存,不到万不得已的时候尽量不使用。

更多闭包的内容可以看JS闭包

数组去重

Bash
let arr = [1,'1',2,'2',1,2,'x','y','f','x','y','f'];
function unique1(arr){
	let result = [arr[0]];
	for (let i = 1; i < arr.length; i++) {
		let item = arr[i];
		if(result.indexOf(item) == -1){
			result.push(item);
		}
	}
	return result;
}
console.log(unique1(arr));
复制代码

更多JS去重的方法JS数组去重

call,apply和bind区别

三个函数的作用都是将函数绑定到上下文中,用来改变函数中this的指向;三者的不同点在于语法的不同。

Bash
fun.call(thisArg[, arg1[, arg2[, ...]]])
fun.apply(thisArg, [argsArray])
复制代码

所以apply和call的区别是call方法接受的是若干个参数列表,而apply接收的是一个包含多个参数的数组。

而bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

Bash
var bindFn = fun.bind(thisArg[, arg1[, arg2[, ...]]])
bindFn()
复制代码

Demos:

Bash
var name = 'window';
var sayName = function (param) {
    console.log('my name is:' + this.name + ',my param is ' + param)
};
//my name is:window,my param is window param
sayName('window param')

var callObj = {
    name: 'call'
};
//my name is:call,my param is call param
sayName.call(callObj, 'call param');


var applyObj = {
    name: 'apply'
};
//my name is:apply,my param is apply param
sayName.apply(applyObj, ['apply param']);

var bindObj = {
    name: 'bind'
}
var bindFn = sayName.bind(bindObj, 'bind param')
//my name is:bind,my param is bind param
bindFn();
复制代码

==和===区别

  • ==, 两边值类型不同的时候,要先进行类型转换,再比较
  • ===,不做类型转换,类型不同的一定不等。

==类型转换过程:

  1. 如果类型不同,进行类型转换
  2. 判断比较的是否是 null 或者是 undefined, 如果是, 返回 true .
  3. 判断两者类型是否为 string 和 number, 如果是, 将字符串转换成 number
  4. 判断其中一方是否为 boolean, 如果是, 将 boolean 转为 number 再进行判断
  5. 判断其中一方是否为 object 且另一方为 string、number 或者 symbol , 如果是, 将 object 转为原始类型再进行判断

深拷贝和浅拷贝

浅拷贝

Bash
function simpleClone(obj) {
    var result = {};
    for (var i in obj) {
        result[i] = obj[i];
    }
    return result;
}
复制代码

深拷贝,遍历对象中的每一个属性

Bash
function deepClone(obj) {
    let result;
    if (typeof obj == 'object') {
        result = isArray(obj) ? [] : {}
        for (let i in obj) {
            //isObject(obj[i]) ? deepClone(obj[i]) : obj[i]
            //多谢"朝歌在掘金"指出,多维数组会有问题
            result[i] = isObject(obj[i])||isArray(obj[i])?deepClone(obj[i]):obj[i]
        }
    } else {
        result = obj
    }
    return result
}
function isObject(obj) {
    return Object.prototype.toString.call(obj) == "[object Object]"
}
function isArray(obj) {
    return Object.prototype.toString.call(obj) == "[object Array]"
}
复制代码

防抖和节流

防抖

Bash
function debounce(fn, delay) {
  let timer = null;
  return function () {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, delay);
  }
}
复制代码

节流

Bash
function throttle(fn, cycle) {
  let start = Date.now();
  let now;
  let timer;
  return function () {
    now = Date.now();
    clearTimeout(timer);
    if (now - start >= cycle) {
      fn.apply(this, arguments);
      start = now;
    } else {
      timer = setTimeout(() => {
        fn.apply(this, arguments);
      }, cycle);
    }
  }
}

复制代码

cookie,sessionStorage和localStorage

  • cookie用来保存登录信息,大小限制为4KB左右
  • localStorage是Html5新增的,用于本地数据存储,保存的数据没有过期时间,一般浏览器大小限制在5MB
  • sessionStorage接口方法和localStorage类似,但保存的数据的只会在当前会话中保存下来,页面关闭后会被清空。

名称生命期大小限制与服务器通信cookie一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效4KB每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题localStorage除非被清除,否则永久保存5MB仅在浏览器中保存,不与服务器通信sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除5MB仅在浏览器中保存,不与服务器通信

0.1+0.2!=0.3怎么处理

把需要计算的数字升级(乘以10的n次幂)成计算机能够精确识别的整数,等计算完成后再进行降级(除以10的n次幂),即:

Bash
(0.1*10 + 0.2*10)/10 == 0.3 //true
复制代码

更多关于浮点数精度处理请看JS中浮点数精度问题

JS实现继承

首先创建一个父类

Bash
// 定义一个动物类
function Animal(name, color) {
    // 属性
    this.name = name || 'Animal';
    this.color = color || ['black'];
    // 实例方法
    this.sleep = function () {
        console.log(this.name + '正在睡觉!');
    }
}
// 原型方法
Animal.prototype.eat = function (food) {
    console.log(this.name + '正在吃:' + food);
};
复制代码

原型链继承

new了一个空对象,这个空对象指向Animal并且Cat.prototype指向了这个空对象,这种就是基于原型链的继承。

Bash
function Cat(name) {
    this.name = name || 'tom'
}
Cat.prototype = new Animal()

var cat = new Cat()
cat.color.push('red')
cat.sleep() //tom正在睡觉!
cat.eat('fish') //tom正在吃:fish
console.log(cat.color) //["black", "red"]
console.log(cat instanceof Animal) //true
console.log(cat instanceof Cat) //true
var new_cat = new Cat()
console.log(new_cat.color) //["black", "red"]
复制代码
  • 特点:基于原型链,既是父类的实例,也是子类的实例。
  • 缺点:1.无法实现多继承;2.所有新实例都会共享父类实例的属性。

构造继承

Bash
function Dog(name) {
    Animal.call(this)
    this.name = name || 'mica'
}
var dog = new Dog()
dog.color.push('blue')
dog.sleep() // mica正在睡觉!
dog.eat('bone') //Uncaught TypeError: dog.eat is not a function
console.log(dog.color) //["black", "blue"]
console.log(dog instanceof Animal) //false
console.log(dog instanceof Dog) //true
var new_dog = new Dog()
console.log(new_dog.color) //["black"]
复制代码
  • 特点:可以实现多继承(call多个),解决了所有实例共享父类实例属性的问题。
  • 缺点:1.只能继承父类实例的属性和方法;2.不能继承原型上的属性和方法。

组合继承

Bash
function Mouse(name){
    Animal.call(this)
    this.name = name || 'jerry'
}
Mouse.prototype = new Animal()
Mouse.prototype.constructor = Mouse

var mouse = new Mouse()
mouse.color.push('yellow)
mouse.sleep() //jerry正在睡觉!
mouse.eat('carrot') //jerry正在吃:carrot
console.log(mouse instanceof Animal)//true
console.log(mouse instanceof Mouse)//true
var new_mouse = new Mouse()
console.log(new_mouse.color) //["black"]
复制代码
  • 特点:可以继承实例属性/方法,也可以继承原型属性/方法
  • 缺点:调用了两次父类构造函数,生成了两份实例



链接来源:https://juejin.im/post/5df1e312f265da33d039d06d

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表