【面试题】JavaScript面试题详细总结(一)
创始人
2024-02-06 11:12:41
0

js基础部分


01 值类型与引用类型


1.1 问法
  • js判断数据类型?
  • js值类型与引用类型有哪些?
  • 值类型与引用类型的区别?
1.2 介绍

JavaScript存储数据两个区域:栈和堆

栈:通常空间是固定的(占据空间小、大小固定)

堆:通常空间是动态的分配(占据空间大,大小不固定)

ES5值类型:Boolean(布尔值)、String(字符串)、Number(数字)、Undefined(未定义)、Null(空(特殊))

ES5引用类型:Object(对象)、Array(数组)、Function(函数)

ES6值类型:Symbol(符号)

ES6引用类型:Map(图)、Set(集合)、Promise(承诺)

1.3 code分析
  • 值类型
var a = 15;  //值类型
var b = a;   //把a的值赋值给b
b = 50;
console.log(a);  //15
console.log(b); //50

可以这样理解:

keyvalue
a15
b50
  • 引用类型
var d = {age:18};//d 是引用类型 key存储在栈中 真正的值存储在堆中 
var e = d; //把d 的引用地址赋值给e,(e与d都指向同一块存储地址)
e.age = 35;
console.log(d.age);//35

可以这样理解:

key地址
d{age:18}{age:18}
e{age:18}
当e.age = 35;执行之后
d{age:35}{age:35}
e{age:35}
1.4 回答
  • 值类型与引用类型的区别?

答:

  1. 值类型 keyvalue 都存储在 js 内存栈中;

  2. 引用类型key存储在栈中,真正的值存储在堆中;

  3. 把引用类型赋值给一个变量,其实是把变量的引用类型的地址指向引用类型堆中地址。

  • 值类型与引用类型有哪些?

答:

  1. 值类型(或简单数据类型):String、Number、Boolean、Symbol、Undefined、Null
  2. 引用类型(复杂数据类型):Array、Object、Function、Set、Map

02 数据类型检测的方式

2.1 typeof

typeof 只能判断 是否为值类型或者引用类型,引用类型除函数都返回的是 object

  • code
console.log(typeof "abc");  //string
console.log(typeof 123);    //number
console.log(typeof true);    //boolean
console.log(typeof undefined);   //undefined
console.log(typeof null);    // Object(null 空指针)
console.log(typeof function(){});   //function
console.log(typeof {});   //object
console.log(typeof []);   //object
typeof new Map()      //'object'
typeof new Set()    //'object'
typeof Symbol      //'function'
typeof Symbol()   //'symbol'

其中数组、对象、null都会被判断为 object

2.2 instanceof

instanceof 含义:是不是某个对象的实例(是数组还是对象。

instanceof 只能正确判断引用数据类型,而不能判断基本数据类型。instanceof 运算符可以用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

  • code
var a = [1,2,3];
console.log(a instanceof Array); // true  a是数组的实例
console.log(a instanceof Object);//true  a是数组的实例,数组也是对象objectvar b = {age:18};
console.log(b instanceof Array); //false b不是数组的实例
console.log(b instanceof Object); //true   b是对象的实例
  • 控制台打印

在这里插入图片描述

2.3 constructor

constructor 有两个作用:

  1. 判断数据的类型
  2. 对象实例通过constructor对象访问它的构造函数。

需要注意的是:如果创造一个对象来改变它的原型,constructor就不能用来判断数据类型了;

  • code
console.log((2).constructor === Number); //true
console.log((true).constructor === Boolean); //true
console.log(("str").constructor === String); //true
console.log(([]).constructor === Array); //true
console.log((function(){}).constructor === Function); //true
console.log(({}).constructor === Object); //true
var a = [1,2,3];
console.log(a.constructor === Array); // true
console.log(a.constructor === Object);//falsevar b = {age:18};
console.log(b.constructor === Array); //false
console.log(b.constructor === Object); //
  • 控制台打印

在这里插入图片描述

数组专用 Array.isArray()

  1. Array.isArray()用于确定传递的值是否是一个Array
  • 语法
Array.isArray(value) 
  • 参数

    value 需要检测的值。

  • 返回值

    如果值是 Array,则为true;否则为false。

  • code

// 下面的函数调用都返回 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
Array.isArray(new Array('a', 'b', 'c', 'd'))
Array.isArray(new Array(3));
// 鲜为人知的事实:其实 Array.prototype 也是一个数组。
Array.isArray(Array.prototype);// 下面的函数调用都返回 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray(new Uint8Array(32))
Array.isArray({ __proto__: Array.prototype });
2.4 Object.prototype.toString.call()

Object.prototype.toString.call() 最准确判断数据类型方法。

Object.prototype.toString.call() 使用Object对象的原型方法toString 来判断数据类型。

  • code
var a = Object.prototype.toString;console.log(a.call(2)); //'[object Number]'
console.log(a.call("str")); //'[object String]'
console.log(a.call(true));//'[object Boolean]'
console.log(a.call([])); //'[object Array]'
console.log(a.call(function(){})); //'[object Function]'
console.log(a.call(undefined)); //'[object Undefined]'
console.log(a.call(null)); //'[object Null]'
console.log(a.call(/ /)); //'[object RegExp]'
console.log(a.call(document.body)); //'[object HTMLBodyElement]'
  • 控制台打印

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-poKtujDS-1669036289065)(C:\Users\khy\AppData\Roaming\Typora\typora-user-images\image-20221115224711639.png)]

  • 封装一个函数
 // Object.prototype.toString.call()
function getType(obj){return Object.prototype.toString.call(obj).sclice(8,-1);
}// Object对象 protype原型.toString转换为字符串  slice分割 从第8位到-1位

在这里插入图片描述

03 深拷贝与浅拷贝

3.1 浅拷贝

浅拷贝:只拷贝值类型,引用类型还是指向地址

var obj1 = {name:"liang",age:18,friend:["小红","小绿",{name:"小蓝",job:"teacher"}]
}
  • 01 ES6 扩展
var obj2 = {...obj1
}
//浅拷贝(如果属性值是引用类型,两个变量的属性都指向同一个内存地址)
  • 02 循环
var obj3 = {};
for(var k in obj1){obj3[k] = obj1[k];
}
  • 03 Object.assign 把参数的两个对象进行合并,属性相同后面覆盖前面
var obj4 = Object.assign(obj1,{})
  • 控制台操作

在这里插入图片描述

3.2深拷贝

深拷贝:目标对象与源对象相互之间切断联系

var obj1 = {name:"xiaoyuan",age:18,friend:["小红","小绿",{name:"小蓝",job:"teacher"}],say(){alert("你好我是" + this.name)}
}
  • JSON 转字符,字符串转对象
var obj2 = JSON.parse(JSON.stringify(obj1))
//JSON字符串的值只会保留 数组,对象,字符串,数字,null,undefined
//对象中的函数会被过滤掉( 一般数据也是不带函数的)
3.2.2先介绍一下递归的概念

递归:递归就是函数自己调用自己,要有结束条件

//需求:计算从1+2+..+5;
function add(n){if(n == 1){   //如果n是1,直接返回(递归函数的结束条件) return 1};return n + add(n - 1)
}
alert(add(5))  //15//分析
/* 
当n=1时,add(1) ==> 返回1
当n=2时,add(2) ==> 返回2+add(1) ==>2+1
当n=3时,add(3) ==> 返回3+add(2) ==> 3+2+1
当n=4时,add(4) ==> 返回4+add(3) ==> 4+3+2+1
当n=5时,add(5) ==> 返回5+add(4) ==> 5+4+3+2+1
*/
  • 斐波那契数列

求斐波那契 数为n的数列

  1. 下一个数等于前面两个数之和,第0位和第1位返回的是1
  2. 1,1,2,3,5,8,13,21,34,55,89,…
function fib(n){if(n == 0 || n == 1){ //如果是第0位返回1,如果是第1位返回1return 1}else{return fib(n - 1) + fib(n - 2) //如果其他位 返回 前面两个数的和}
}// alert(fib(41));此种方法计算有局限,最高计算到41位//分析
/*
n=0时,fib(0)==>  return 1
n=1时,fib(1)==>  return 1
n=2时,fib(2)==> return  fib(1)+fib(0)==>1+1=2
n=3时,fib(3)==> return  fib(2)+fib(1)==>2+1=3
n=4时,fib(4)==> return  fib(3)+fib(2)==>3+2=5*/
  • 升级
function getFib(n){//如果小于1 返回1if(n <= 1){return 1}else{//做数组arrvar arr = [1,1]//从第2位开始算for(var i = 2;i <= n;i++){arr.push(arr[i - 1] + arr[i - 2])//第n位数 是前面两个数的和}//console.log(arr)return arr.pop()  //返回最后一个(删除并返回最后一个)}
}alert(getFib(45))

  • 通过判断类型 递归深拷贝

深拷贝:目前对象与源对象相互之间切断联系

递归就是函数调用自己,一定要有结束条件

		var obj1 = {name: 'mumu',age: 18,friend: ["小红", "小绿", {name: '小蓝',job: 'teacher'}],say() {alert("你好我是" + this.name)}}//如果是数组需要递归,如果是对象需要递归,如果是值类型递归结束function deepCopy(obj) {//typeof 是object 不是nullif (typeof obj == "object" && obj != null) {//引用类型var temp = null;//如果是数组if (obj instanceof Array) {//要返回的结果应该是个数组temp = [];for (var i = 0; i < obj.length; i++) {temp = [];//递归拷贝数组for (var i = 0; i < obj.length; i++) {//temp[i]=obj[i] //**这样就是普通浅拷贝temp[i] = deepCopy(obj[i]); //递归拷贝//函数自己调用自己 返回的 拷贝 obj[i]的结果}} else {//返回的结果就是对象temp = {};//递归拷贝对象for (var k in obj) {temp[k] = deepCopy(obj[k]);}}//返回的结果return temp;} else {//非引用类型或者其他return obj}}var obj2 = deepCopy(obj1);// var obj1 = {// 	name: 'mumu',// 	age: 18,// 	friend: ["小红", "小绿", {// 		name: '小蓝',// 		job: 'teacher'// 	}],// 	say() {// 		alert("你好我是" + this.name)// 	}// }}//01 进入deepCody 函数// typeof obj1 结果就是object 并且不是null// 02 obj1 instanceof Array 结果是 false// temp ={}// for (var k in obj1){// 	temp[k] = deepCopy(obj1[k]);// }//03 return temp;//返回temp 对象(拷贝好的对象)// ====================================2.1// temp[name] = deepCopy(obj1["name"])  deepCopy("mumu")// typeof "mumu" 不是object 也不是null return "mumu"// temp[name] = "name"  // ===================================2.2// temp[age]=deepCopy(obj1["age"])  deepCopy(18)// typeof 18 不是object  也不是 null  return 18// temp[age] = 18// ==================================== 2.2// temp["friend"] =deepCopy(obj1["friend"])// ===========================================2.2.1// typeof ["小红","小绿",{name:"小蓝",job:"teacher"}] 结果是object 也是null// ["小红","小绿",{name:"小蓝",job:"teacher"}]  instanceof 结果为true// temp["friend"] = // for(var i = 0;i<["小红","小绿",{name:"小蓝",job:"teacher"}].length;i++ ){}//----------------------------只要是引用类型就递归拷贝下去,直到拷贝typeof 不会object

04 数据类型转换

4.1 隐式转换

数据类型转换:强制转换,隐式转换

强制转换

  1. Number()转换为数字,
  2. String() 转换为字符串
  3. Boolean() 转换为布尔值

隐式转符号

  1. +字符串连接符号(隐式转换为字符串)
  2. 数学运算:+ - * / (隐式转换为数字)
  3. >< >= <= || && ! 比较与逻辑(隐式转换为布尔值)
  • +字符串连接符号 会尝试把其他类型转换为 字符串
//字符串和任意数据 + 连接 都会转换为字符串
var a = "100";
var b = 10;
var c = a + b;
alert(c);//10010
  • 数学运算符号会尝试隐式 转换为数字

    如果数据没有转换数字成功,结果就是NaN

    true 转换为数字,默认转换为1;false默认会转换为0

//+ - * /  == 会尝试把其他类型转换为数字
//转换失败 NaN
//false 转换为 0
//true 转换 1
var a = "10";
var b = 2;
var c = a * b;
console.log(c);//20var a = "abc10";
var b = 2;
var c = a * b;
console.log(c);//NaNvar a = true;
var b = 2;
var c2 = a * b;
console.log(c2)  //2var a = false;
var b = 2;
var c3 = a * b;
console.log(c3)  //0
  • 逻辑与比较运算符号,会把变量转换为布尔值

​ 空字符串,0,null,undefined,NaN,false 才会被转换为false,其他都会被转换为true;

​ 把以上的变量值称为falsely变量值,其他的变量都称为truely变量值

//><>= <=  ! !=  ==  判断与逻辑返回会尝试把其他类型转换布尔值
//falsely变量转换为false
// "" null NaN undefined 0 转换为false
var a = "";
console.log(!!a); //false
console.log(!!-1); //true
console.log(!!NaN) //false
4.2 严格等于

== (等于) 判断隐式转换后值是否相等

=== (严格等于) 判断类型与值是否相对

  • ==
console.log(100 == "100");  //true(如果两边类似数字会优先隐式转换为数字)
console.log("" == false);  //true
console.log(1 == true);// true
console.log(null == undefined);// true 隐式转换后都为fasle
console.log(null == null);  // true  空指针都指向一个地方(空)
console.log(undefined == undefined);//
console.log(null == NaN);false(特殊) 数字不等于空
console.log([] == []);//false  //两块不同的内存地址
console.log({}== {});//false  //两块不同的内存地址

在这里插入图片描述

  • ===
// === 严格等于 判断类型 与值 是否相对
alert(0 === ""); //false
alert([] === []); //false
alert({} === {}); //false
alert(null === undefined); //false
alert(null === null); //true//应该都用=== 严格等于
//判断是为null 还是undefined 可以用===

在这里插入图片描述

  • 什么时候用=== 什么时候用==

答:应该在任何时候都使用=== (当判断是否为null或者为undefined可以为特例)

05 if与逻辑运算符

5.1 if
  1. if判断只要求()内 表达式结果是否为truely变量
  2. falsely变量:false “ ” 0 NaN false undefined null;对变量取两次反; !! 结果为false的变量,称为falsely变量
  3. 除了falsely变量外其他都是truely变量
var a = 10;
if(a){console.log("条件通过") //条件通过
}
//条件通过var b = "";
if(b){console.log("b通过")
}else{console.log("b不通过")  
}
// b不通过
5.2 逻辑 或

A||B 或

A为真(truely) 结果为A ,否则结果为B

  • 如果前面的变量为truely,最终的结果为第一个,如果为falsely,结果为第二个
var a = 15 || 0;
var b = false || 50;
var c = false || undefined;
var d = 0 || false;
console.log(a); //15   15 转换结果为true ,a的值就是15
console.log(b);  //50  false 转换的结果为false  b的值是50
console.log(c);  // undefined   
console.log(d);  //false
  • 举个例子
//例子  num 取不到,或者为0, 或者为null  ....最终结果为5
var re = localStorage.getItem("num") || 5;
5.3 逻辑 且

A&&B 逻辑且

A为假(falsely) 结果为A,否则结果为B

  • 如果前面的变量为falsely,直接返回 前面的值;如果前面的变量是truely,则返回后面的值

在这里插入图片描述

  • 判断对象

if(a&&a.b&&a.b.c){}

if(a?.b?.c){}

如果有a并且有a.b并且有a.b.c

06 原型与原型链

6.1 什么是类,什么是实例

什么是类,什么是实例?

  • 类:创造对象实例的模板(本质上都是函数) ;如:Array 、Object 、String…
    • 构造函数 用new 来执行的函数
    • class xxx{}
  • 实例:就是由类创建的对象(本质上讲就是对象);如[1,2,3]{name:“mumu”},“abc”
6.2 显示原型与隐式原型

显示原型

  • 类/构造函数都有一个显示原型prototype(本质就是对象)

隐式原型

  • 每个实例都有一个隐式原型 __ proto __

显示原型与隐式原型的关系

  • 类显示原型prototype等于其创建的实例的隐式原型 __ proto __

  • var  arr = [];
    arr.__proto__ === Array.prototype;
    

在这里插入图片描述

6.3 原型链

原型链

  • 查找对象实例的方法和属性时,先在自身找,找不到沿着__ proto __ 向上查找,__ proto __ 形成的链条关系,我们称为原型链 (实现了js继承)

原型与原型链的作用

  • 实现了js 的继承
  • 实现了实例的公用属性和方法
  • 创建2个类解释原型与原型链(People,Student)
		//01 创建people类function People(name, age) {this.name = name;this.age = age;}//02 给people 显示原型添加eat方法People.prototype.eat = function() {console.log(this.name + "正在吃饭");}//03 创建 学生类继承People 类function Student(name, age, no) {//执行people构造函数(执行people 函数并把当前的this传入函数,当做people的this)People.call(this, name, age);//定义学号this.no = no;}//04 让Student 显示原型链继承 People 的原型链Student.prototype = Object.create(People.prototype);//05 修正Student 显示原型链 上的构造函数Student.prototype.constructor = Student;//06 在Student 显示原型链添加方法Student.prototype.study = function() {console.log(this.name + "正在好好学习");}//07 构建 Student 的实例s1var s1 = new Student("菜菜", 18, 9527);

在这里插入图片描述

  • 图示

在这里插入图片描述

6.4 js实现继承
  • class 的extends方法
class Student extends People{constructor(name,age,no){//类中继承构造函数super(name,age)....}
}
  • 使用原型链
  1. Student构造函数中继承People
function Student(name,age,no){People.call(this,name,age)....
}
  1. 继承原型链
Student.prototype = Object.create(People.prototype)
  1. 修正Student构造函数
Stuent.prototype.constructor = Student
  1. 图示

在这里插入图片描述

6.5 实例公用方法(扩展)

怎么样让所有的数组求最大最小值?(通用方法)

  1. 数组Array 的实例都拥有最大最小值方法
  2. 把自定义方法挂载到类的原型上
  3. 💛 可以在所有的数字实例上访问max(min)方法
  • 求最大值
Array.prototype.max = function(){return Math.max(...this);//this就是当前数组,展开求最大值
}
  • 求最小值
Array.prototype.min = function(){return Math.min(...this);//this就是当前数组,展开求最小值
}

在这里插入图片描述
在这里插入图片描述

  • 怎么样让字符串有通用翻转(reverse)方法
String.prototype.reverse = function(){return this.split("").reverse().join("");
}

在这里插入图片描述

准则1:不要需要js默认对象原型上的方法

准则2:不要在js默认对象的原型上添加方法

vue2 数组的双向绑定劫持就是重写了数组的原型上的方法实现的


更多面试题后续更新…

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...