一、js原型/原型链?
1.原型
概念:
js中每一个构造函数都有一个与之对象的js对象来表示,这个对象中都有prototype属性,这个属性就叫函数的原型。原型就是函数对象的prototype属性。
优点:构造函数的所有实例化对象都可以共享函数原型的属性和方法。
缺点:函数的原型delete方法删除不掉
2.原型链
实例化一个对象,我们要使用对象的属性或者方法,他会先从当前对象进行查找,如果找不到,就去函数的原型中去查找,如果原型中也不存在,就去函数的父对象查找,如果最终没找到,返回undefined。
二、(值类型)基本数据类型和引用数据类型的区别?
值类型
- 占用空间固定,保存在栈中(当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是仿制栈内存中的;栈内存储的基础变量以及一些对象的引用变量,基础变量的值是存储在栈中,而引用变量存储在栈中是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址的引用变量。)
- 保存与复制的是值本身
- 使用typeof检测数据的类型
- 基本类型数据是值类型
引用类型
- 占用空间不固定,保存在堆中(当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象
依然不会被销毁
,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。) - 保存与复制的是指向对象的一个指针
- 使用instanceof检测数据类型
- 使用new()方法构造出的对象的引用型
三、深拷贝和浅拷贝的区别?如何实现
浅拷贝值复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。浅拷贝只复制对象的第一层属性。
但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。对对象的属性进行递归复制。
实现方式
- 浅拷贝
-
使用Object.assign({},obj)第一个参数是一个空对象,第二个参数是你要复制的对象;通过这个方法我们知道浅拷贝不能修改基础的数据类型,可以修改引用的数据类型;
-
ES6中的…扩展运算符来进行浅拷贝的实现;
-
Object.assign()实现
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
var obj = { a: {a: "hello", b: 21} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = "changed";
console.log(obj.a.a); // "changed"
注意:当object只有一层的时候,是深拷贝,例如如下
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }
-
深拷贝
-
对象只有一层的话可以使用上面的:Object.assign()函数
-
转成 JSON 再转回来
-
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);
// { body: { a: 10 } } <-- 沒被改到
console.log(obj2);
// { body: { a: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
// false
用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。
-
使用Object.create()方法
直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
}