聊一聊写代码基础,但是容易出错的点

157 阅读5分钟

在我们学的越来越多,学的越来越杂的时候,如果一些基础却还没有到位,这样为我们后面的学习和写代码是留下了非常多的隐患的,对于后面的学习,导致学习的效率变慢,需要重新学习前面已经学习过的知识,对于写项目,写代码,也是有着极大的影响的,在不知不觉中就会在项目中留下大大小小的隐患,如果只是一个,两个bug还比较容易解决,如果很多的bug耦合在一起,到时候再来排除bug的时候,真的是痛不欲生。

一、++表达式

let a = 1

let b = a + ++a + a++

当我们在代码中遇到这么一段代码的时候,你能不运行代码,根据自己的开发知识得到a和b的值吗?

遇到这个问题,我们都知道++会将a自增一次,那么自增的时机是什么呢?

当++在变量之前时 ++a

1.先自增 2.返回结果

当++在变量之后时 a++

1.先返回结果 2.再自增

这个时候我们再来看代码

//当代码运行到++a时(a=2) 先自增,再返回
let b = 1 + (1+1) + a++
//当代码运行到a++时(a=3) 先返回,再自增
let b = 1 + (1+1) + 2
//b=5,a=3

二、对于引用类型数据的赋值

这里的引用类型主要针对对象和数组

//对象类型的直接赋值
let obj = {
name:"lihu",
age:"18"
};
let newObj = obj;
obj.age = 19;
//数组类型的直接赋值
let arr = [1,2,3,4];
let newArr = arr;
arr[1] = 100;

当我们想在写代码的时候,大家思考一下对应的newObjnewArr的值应该是多少

解析:当数据为引用类型的数据时,例如对象,对象中存放的是指向每一个属性的指针,而属性值另外存放在一个堆中,当我们直接赋值,两个对象中存放的指针都同时指向同一个属性值,当我们改变其中一个对象的属性时,另一个对象也会受到影响。

想要摆脱这种影响,需要对对象进行拷贝(浅拷贝or深拷贝)

浅拷贝:只拷贝一层

那么我们如何在代码中书写呢?这里以js为例子

let obj = { a:1 }
//将对象解构,将解构的结果用对象包裹起来,
//这样新得到的对象存储的地址就将是一个新的值,原本的对象的属性值改变也不会影响到新的对象
let newObj = {...obj}

let arr = [1]
//数组同理
let newArr = [...arr]

深拷贝:将对象所有属性完完全全拷贝

上面的浅拷贝只适用于一层的数据结构,当遇到多层结构时就不太适用了,例如:

//多层结构的对象
let obj = {
    studentName:"李四",
    studentCard:{
        cardId:"10001",
        ...
    }
    ...
}
//多层结构的数组
let arr = [[1,2],[1,2,3],[3]...]

当对象和数组呈现出多层结构时,只是简单的浅拷贝就不行了,原因:

例如上面的对象例子,当解构到studentCard属性的时候,由于它是一个对象,所以存放的还是同一个地址,数组同理,所以将这些数据进行简单的浅拷贝赋值给另外的对象或者数组时,修改原本的对象中的引用类型的数据时还是会影响新对象或新数组。

使用深拷贝,在js中提供一些方法,能帮助我们实现深拷贝

方法一:JSON字符串

//将对象转化为json字符串
let jsonString = JSON.stringify(obj)
//再将json字符串转化为对象
let newObj = JSON.parse(jsonString)

这种方法虽然简单,但是也有一些比较致命的缺点,就是不能处理一部分特殊的数据 例如:

let a = {
    name: 'Jack',
    age: 18,
    hobbit: ['sing', {type: 'sports', value: 'run'}],
    score: {
        math: 'A',
    },
    run: function() {},
    walk: undefined,
    fly: NaN,
    cy: null,
    date: new Date()
}
let b = JSON.parse(JSON.stringify(a))
console.log(b)
// {
//     age: 18,
//     cy: null,
//     date: "2022-05-15T08:04:06.808Z"
//     fly: null,
//     hobbit: (3) ["dance", "sing", {…}],
//     name: "Jack",
//     score: {math: "A"},
// }

方法二:递归函数实现深拷贝

在实现这个方法的时候,无非就是需要注意当前传入参数的类型

//深拷贝
const cloneDeep = (obj) =>{
	// 传入的对象的类型不是引用数据类型,
	// 返回
	if(typeof obj !=='object' || obj === null){
		return obj
	}
				
	//但是这里的obj可能有两种情况
	let resultObj 
				
	//判断是数组还是对象
	if(obj instanceof Array){
		resultObj = []
	}
	else{
		resultObj = {}
	}
				
	for (let key in obj) {
					
                resultObj[key] = cloneDeep(obj[key])
	}
				
	return resultObj
}

//测试数据
const obj = {
   name:"王五",
   age:18,
   class:undefined,
   children:[
       {
           id:1,
           children:[
               {
                   id:2
               }
           ]
       }
   ]
   
   
   
   
   
const obj2 = cloneDeep(obj)
obj2.name = '李四'
obj2.children[0].id = 1000
console.log("obj",obj);
console.log("obj2",obj2);

然后我们再来看一看最终的结果

image.png 修改克隆出来的数据并没有影响到原本的数据,也代表我们的这个方法是实现成功了的

方法三:使用别人的库

使用步骤如下 ` 1.下载依赖

npm i --save lodash

2.引入具体使用的页面

import _ from 'lodash'

3.使用方法进行深拷贝

import _ from 'lodash';

const data = {
    id:"1",
    parentId:"0"
    name:"码表一",
    children:[
    {
       id:"2",
       parentId:"1",
       name:"码值一"
    },
    ...
    ]
}

const copyData = _.cloneDeep(data)

上面这3个步骤就是使用lodash深拷贝的具体流程了