前端JS面试题-基础-变量类型和计算

写在前面:本文内容主要根据慕课网双越老师的付费课程“一天时间迅速准备前端面试 快速构建初级前端知识体系 ”进行编写,主要是为了自己在面试前总结学习,欢迎留言指教。

本系列包括如下内容:

每一部分包括题目知识点两部分。

变量类型和计算

题目:

  1. typeof能判断哪些类型
  2. 何时使用 === 何时使用 ==
  3. 值类型和引用类型的区别
  4. 手写深拷贝

1. typeof能判断哪些类型

  • 识别所有值类型
  • 识别函数
  • 判断是否是引用类型,但无法进一步判断具体引用类型

2. 何时使用 ===, 何时使用 ==

除了 判断 == null 之外,其他都一律用 ===
因为 == 在尽量地对要比较的变量进行类型转换,很多不相等的变量通过类型转换会相等,这不是我们预期的结果,因此我们要尽量使用 === 进行比较

3. 值类型和引用类型的区别

  • 首先,什么是值类型,什么是引用类型
    在JS中值类型的变量直接存储数据,而引用类型的变量持有的是数据的引用,数据存储在数据堆中。
    值类型变量声明后,不管是否已经赋值,编译器为其分配内存;当声明一个引用类型变量时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间,当使用该变量时,才会分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。
  • 其次,常见的值类型变量和引用类型变量
    常见的值类型变量:String,Number,Boolean,undefined,Symbol
    常见的引用类型变量:Array, Object, null, function

4. 手写深拷贝

参考知识点3中给出的代码。
注意:

  • 注意判断值类型和引用类型,指对引用类型进行深拷贝
  • 主语判断是数组还是对象,影响返回结果的初始化
  • 递归

知识点:

1. 值类型 引用类型

首先给出常见值类型和常见引用类型的举例:

  • 常见值类型
let a //undefined 未定义
const s = 'abc' //String 字符串
const n = 100 //Number 数值
const b = true //Boolean 布尔值
const s = Symbol('s)
  • 常见引用类型
const obj = {x: 100} //Object 对象
const arr = {'a', 'b', 'c'} //Array 数组
const n = null //特殊引用类型,指针指向为空地址
function fn(){} //特殊引用类型,但不用于存储数据,所有没有“拷贝、赋值函数”一说

接下来给出两个关于值类型和引用类型的赋值的代码,分析其原理:

// 值类型
let a = 100
let b = a
a = 200
console.log(b)  // 100

// 引用类型
let a = { age: 20}
let b = a
b.age = 21
console.log(a.age) // 21

对于值类型的数据,其存储情况如下:
image
考虑到性能问题,值类型数据的存储和复制都比较快速,不耗性能,因此它被存储到栈里,key下的value直接存储值。

对于上面给出的代码,新建a,并赋值,其存储结果如第一个框所示;新建b,并将a赋值给b,其存储结果如第二个框所示;所以再a变化时,b不受影响,如第三个框所示。

对于引用类型的数据,其存储情况如下:
image
在栈中,value内只存储key所在的内存地址,通过内存地址到堆里进行查看具体值。
因此,当新建一个引用类型a,再新建一个引用类型b,并将a赋值给b,那b下存储的只是a的内存地址。当b对age进行修改时,堆内的值被修改,也就是a的age也被修改,因为a、b指向同一个内存地址。

2. typeof运算符

  • 识别所有值类型
    image
  • 识别函数
  • 判断是否是引用类型,不能识别到具体的引用类型
    image

3. 深拷贝

知识点1中展示并讲解了值类型数据和引用类型数据的拷贝问题。值类型数据可以利用浅拷贝来完成数据的拷贝,但引用类型数据无法利用浅拷贝来完成数据的拷贝,因此我们需要写一个深拷贝的方法来解决上述问题。

接下来给出手写深拷贝的代码:

/**
 * @param {type}  要拷贝的对象
 */
function deepClone(obj = {}) {
	//针对的是对象和数组
	if(typeof obj != 'object' || obj == null) {
		return obj
	}

	//初始化返回结果
	let result
	if (obj instanceof Array) {
		result = []
	} else {
		result = {}
	}

	for (let key in obj) {
		if (obj.hasOwnProperty(key)) {
			//保证key不是原型的属性
			//递归
			result[key] = deepClone(obj[key])
		}
	}

	//返回结果
	return result
}

给出如下的代码来演示浅拷贝和深拷贝的区别,和深拷贝的作用:

const obj1 = {
	age: 20,
	name: 'xxx',
	address: {
		city: 'beijing'
	},
	arr: ['a', 'b', 'c']
}

const obj2 = obj1

obj2.address.city = 'shanghai'
console.log(obj1.address.city)

const obj3 = deepClone(obj1)
obj3.address.city = 'shenzhen'
console.log(obj1.address.city)

运行,可以在控制器内看到如下结果:

image

我们创建了一个obj1,其中city的值为beijing,将obj1浅拷贝给obj2,并obj2.address.city = 'shanghai',打印obj1.address.city,发现beijing被修改为shanghai;将obj1深拷贝给obj3,并obj3.address.city = 'shenzhen',打印obj1.address.city,发现没有被修改。这样我们就完成了深拷贝操作。

4. 类型转换

有3种情况会发生隐式类型转换,分别为:

  • 字符串拼接
    image
  • ==
    image

== 会尽量地通过类型转换使其相等,所以我们应该尽可能地使用 ===

image

  • if语句和逻辑判断
    在这里要介绍两种变量,分别为:
    • truely变量: !!a === true 的变量
    • falsely变量: !!a === false 的变量
      image

在进行if语句和逻辑判断时,会将变量转换为truely变量和falsely变量。

posted @ 2021-06-28 19:30  Dreamup_lu  阅读(146)  评论(0编辑  收藏  举报