前端面试题(第三弹)——js对象的基本方法和深浅拷贝
一、 js对象(object)
1.创建对象的两种方式
第一种
let person = new Object();
person.name = "dabing";
person.age = 23;
person.sayName = function () {
console.log(this.name)
}
第二种
let person = {
name:"xiaowang",
age:22,
sayName () {
console.log(this.name)
}
}
2. 对象属性的类型
1.configurable:属性是否可以通过delete删除,默认值为true。
2.enumberable:属性是否可以通过for in 进行循环返回,默认值为true。
3.writable:属性是否可被修改,默认值为true。
4.value:属性实际的值,默认为undefined。
//要修改属性的默认特性,就必须使用Object.defineProperty()方法
let person = {}
Object.defineProperty(person, "name", {
writable: false, //设置person的name属性不可修改
value:"xiaowang"
})
// defineProperty() 方法接受三个参数 第一个是要修改的对象,第二个是对象的属性,
// 最后一个参数是一个对象里面包含了
// 四个属性configurable、enumberable、writable、value
console.log(person.name); //"xiaowang"
person.name = "dabing"
console.log(person.name) //"xiaowang"
3. 访问器属性
访问器属性有四个属性类型,也是使用Object.defineProperty() 进行定义修改,
1.configurable:属性是否可以通过delete删除,默认值为true。
2.enumberable:属性是否可以通过for in 进行循环返回,默认值为true。
3.get(){}; 读取属性,默认undefined。
4.set(){}; 设置属性,默认undefined。
访问器属性对于没有接触过的人来说有点难理解,怎么区分数据属性与访问器属性呢?
如下例子,我们一般在设置访问器属性的时候,会给属性在前面或者后面加上下划线(属于是约定俗成),以表示私有变量,在js中这是伪私有。
设置完伪私有变量之后,一般情况下我们是不希望直接访问这个属性的,所以我们给book再定义一个“year”,我们会直接访问这个year ,这个year就是访问器属性,而不是去访问_year,
在通过Object.defineProperty()方法中,设置get、set也不是必要的。可以根据实际场景进行调整。
let book = {
_year:2017,
edition: 1
}
Object.defineProperty(book, "year", {
get() {
return this._year;
},
set(newValue) {
if(newValue > 2017) {
this._year = newValue;
this.eidtion += newValue - 2017;
}
}
})
book.year = 2018
console.log(book.edition) //2
//另外有定义多个属性的方法Object.defineProperties({
year_:{
value:2017
},
edition:{
value:1
},
year:{
get() {
return this.year_;
},
set(newValue) {
if(newValue > 2017) {
this._year = newValue;
this.eidtion += newValue - 2017;
}
}
})
//读取属性的特性的方法Object.getOwnPropertyDescriptor(对象,属性)
//访问对象所有属性特性的方法Object.getOwnPropertyDescriptors(对象)
二、基本类型和引用类型
基本类型的数据包括number、string、boolean、null、undefined ———基本数据类型是值传递
引用数据类型 Object {} 、[] 、function(){} 、Date 、RegExp ———引用数据类型是地址传递
var number = 23
var a = number
a = 20
console.log(number+a) //43 栈内存 会开辟新地址
var obj ={
name:"xiaowang",
age:23
}
var b = obj;
b.name = "dabing"
console.log(obj) //{name: 'dabing', age: 23} 堆内存 b会指向obj的内存地址 修改的是同一个对象
三、 深浅拷贝
1. 深浅拷贝定义解释
深浅拷贝就像上面举的例子一样,浅拷贝就是指Object的直接复制,修改一个值另一个也跟着变化,两个指向同一个内存地址,深拷贝指的是我们对于Object的拷贝,可以实现两个对象互不影响,像基本数据类型那样。
2. 实现深拷贝的方法
> JSON.parse(JSON.stringify(obj))
obj = {name:"aa"}
var b = JSON.parse(JSON.stringify(obj))
b.name = "bb"
console.log(obj) // {name: 'aa'}
console.log(b) // {name: 'bb'}
!!!注意:
JSON.parse(JSON.stringify(obj)) 是最简单的实现方式,但是有一些缺陷:
对象的属性值是函数时,无法拷贝。
原型链上的属性无法拷贝
不能正确的处理 Date 类型的数据
不能处理 RegExp
会忽略 symbol
会忽略 undefined
> 实现一个 deepClone 函数 (深拷贝,递归)
function deepClone (obj) {
if(typeof obj != 'object') {
return obj
}
let newObj = obj.constructor === Array ? [] : {}
for (let i in obj ) {
if(obj[i] instanceof Object) {
newObj[i] = deepClone(obj[i])
}else{
newObj[i] = obj[i];
}
}
return newObj;
}
var obj = {name:"wang ",age:22}
var obj2= deepClone(obj)
obj2.name = "bing"
console.log(obj2) // {name: 'bing', age: 22}