深拷贝与浅拷贝
数据类型:
js中共有六种基本数据类型,undefined,null,boolean,bumber,string,symbol(es6新增)
基本数据类型的值是不可变的
var str = "123hello321";
str.toUpperCase();
console.log(str);
改变后的值需要一个新的变量进行接收.
引用类型
引用类型的值是可变的,引用类型的比较是引用的比较.
var obj1 = {}; // 新建一个空对象 obj1
var obj2 = {}; // 新建一个空对象 obj2
console.log(obj1 == obj2); // false
console.log(obj1 === obj2); // false
因为对象1和对象2分别开辟了一个内存空间,每个内存空间的内存地址都是不同的,对象1的值和对象2的值自然也不相同
如何区分深拷贝与浅拷贝?
简单来说,假设b复制了a,当我们改变a时,看b是否会跟着发生变化,如果b也跟着变化,那么此时就是浅拷贝,如果b没有发生变化,此时就是深拷贝.
为什么会出现深拷贝与浅拷贝?
深拷贝:
基础数据类型在被创建后会开辟出一个内存空间,名称为变量名,默认值为undefined,赋值后为所赋值.假设a,b.当a对b的赋值操作时,就是将a内存空间中的值传给了b,也即是将a的值传给了b,此时所传的值分别存储在a与b的内存空间中,这时改变a的值但b的值处于b自身的内存空间中,即使a发生了改变但b仍不受影响
浅拷贝:
复合数据类型会另外开辟出一处内存空间来存放自己的值,变量本身的内存空间所存储的是存放值的内存空间的内存地址,这时将a的值传给b,其实就是将a的内存地址传给了b.这样一来两者共用了一个内存地址,当其中任意一方改变了该内存地址的值,两者便都会发生改变
怎样解决浅拷贝?
一,循环遍历
var arr1 = [1, 2, 3];
var arr2 = [];
arr1.forEach((item) => {
arr2.push(item);//将arr1中的值通过循环推进arr2中,arr1与arr2的内存地址不同,其中一方发生改变时另一方自然不会跟着改变
});
二,展开运算符
var arr1 = [1, 2, 3];
var arr2 = [...arr1];//与循环大同小异,只是将拿到了值,并没有将内存地址一同拿来
arr1[0] = 5;
console.log(arr1, arr2);
三,json
var arr1 = { name: "张三", age: 18, jy: "地地地怒掏大王" };
var arr2 = JSON.stringify(arr1);
arr1.name = "李四";
console.log(arr1, arr2);
前两种方式都只适用于一维数组,当出现多维数组时不可使用
什么是递归函数?
一个函数在自身内部调用了自身,并且具有满足条件的出口(不是死递归),即是一个递归函数(有进有出,先进后出)
什么是this?
它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。
随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象
在普通函数中,this指向的是window
在箭头函数中,谁定义了箭头函数,this指向就是谁(箭头函数本身没有this指向)
定时器的this指向永远都是window,除非人为更改this指向
方法
call(),apply(),bind()
call()
语法格式:fun.call(this,obj1,obj2);
function fun(){
console.log(this);
}
box1.onclick = function(){
fun.call(this); // 使用call,修改this指向
}
形参接收时,第一个永远都是this,后面才是传递的参数
apply()
call和apply相似,不同指出在于传递的方式不同,call的参数需要逐个列举,apply的参数需要通过数组的形式传递,apply虽然传递的是数组,但是接收的时候还是一个个接收的
语法格式:fun.apply(this,[obj1,obj2]);
特殊:
Math.max(min).apply(null, arr),因为apply传递的是数组,并且一个个接收,也就是将数组中的值一个个展开,与展开运算符相同(不想改变this指向时传递空值)
bind()
bind()方法不会调用函数,需要手动添加调用方式(以新变量进行接收),但是能改变函数内部this指向
语法格式:Fun.bind(this,arg1,arg2);
function fun2(a, b) {
console.log(a + b);
console.log(this);
}
box1.onclick = function () {
// bind传參的格式和call是一样的,直接用逗号隔开
var aa = fun2.bind(this,10,20)
aa();
}
面试题call,apply,bind有什么区别:
call 和 apply 特性一样
都是用来调用函数,而且是立即调用
但是可以在调用函数的同时,通过第一个参数指定函数内部 this 的指向
call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可
apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递
如果第一个参数指定了 null 或者 undefined 则内部 this 指向 window
bind可以用来指定内部 this 的指向,然后生成一个改变了 this 指向的新的函数
它和 call、apply 最大的区别是:bind 不会调用