浅拷贝
- 只拷贝一层
- 如果拷贝的是简单数据类型, 它传递的是值, 有自己的内存空间
- 如果拷贝的是复杂数据类型, 它传递的是引用
- 实现浅拷贝方式
方式一 : 封装函数
function simpleClone(obj) {
let newObj = {}
for (let key in obj) {
newObj[key] = obj[key]
}
return newObj
}
let obj = { a: { b: 1 }, name: 'zs', say: `funtion(){alert('hello')}` }
let newObj = simpleClone(obj)
console.log(obj)
newObj.a.b = 33
newObj.name = 'ls'
newObj.say = function() {
alert('yell')
}
console.log(obj)
//{ a: { b: 1 }, name: 'zs', say: "funtion(){alert('hello')}" }
// { a: { b: 33 }, name: 'zs', say: "funtion(){alert('hello')}" }
方式二 : Object.assign()
Object.assign( target , … , source) 把源对象的属性复制给target目标对象
如果源对象嵌套的层级深 , 就是浅拷贝 ,只拷贝一层的引用
如果源对象就一层嵌套 , 就是深拷贝 ,拷贝的是值
//浅拷贝
let obj = { a: { b: 1 }, name: 'zs', say: `funtion(){alert('hello')}` }
let newObj = Object.assign({}, obj)
console.log(obj)
newObj.a.b = 33
newObj.name = 'ls'
newObj.say = function() {
alert('yell')
}
console.log(obj)
//{ a: { b: 1 }, name: 'zs', say: "funtion(){alert('hello')}" }
// { a: { b: 33 }, name: 'zs', say: "funtion(){alert('hello')}" }
深拷贝
- 拷贝多层-
- 实现深拷贝方式
方式一 : 手动复制
方式二 : 使用 Object.assign()
只适用于对象只有一层
let obj = { a: 1, b: { d: 4 }, c: 3 }
let newObj = Object.assign({}, obj)
console.log(obj)
newObj.a = 33
newObj.b.d = 22
console.log(obj)
//{ a: 1, b: { d: 4 }, c: 3 }
// { a: 1, b: { d: 22 }, c: 3 }
方法三 : 转成json格式再转会对象
缺点: 会丢失对象的constructor, 就是深拷贝出来的对象,无论之前构造函数是什么,拷贝后都会变成 object ; 复制的function会消失
只适用于 : 对象只有纯数据
var obj1 = { a: { b: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.a.b = 20;
console.log(obj1);
// { a: { b: 10 } } <-- 沒被改到
console.log(obj2);
// { a: { b: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
//false
方式四: 回调函数
function deepClone(initObj, finalObj) {
let obj = finalObj || {}
for (var key in initObj) {
var prop = initObj[key]
if (prop === obj) { //避免回调自己,形成死循环
continue
}
if (typeof prop === 'object') {
obj[key] = prop.constructor === 'Array' ? [] : {}
arguments.callee(prop, obj[key])
} else {
obj[key] = prop
}
}
return obj
}
let obj = { a: { b: 1 }, name: 'zs', say: `funtion(){alert('hello')}` }
let newObj = deepClone(obj)
console.log(obj)
newObj.a = [1, 2, 3]
newObj.name = 'lss'
console.log(obj)
//{ a: { b: 1 }, name: 'zs', say: "funtion(){alert('hello')}" }
// { a: { b: 1 }, name: 'zs', say: "funtion(){alert('hello')}" }
方式五 : 使用 Object.create()
function deepClone(initObj, finalObj) {
let obj = finalObj || {}
for (let key in initObj) {
let prop = initObj[key]
if (prop === obj) {
continue
}
if (typeof prop === 'object') {
obj[key] = (prop.constructor === 'Array') ? [] : Object.create(prop)
} else {
obj[key] = prop
}
}
}
let obj = { a: { b: 1 }, name: 'zs', say: `funtion(){alert('hello')}` }
let newObj = deepClone(obj)
console.log(obj)
newObj.a = [1, 2, 3]
newObj.name = 'lss'
console.log(obj)
//{ a: { b: 1 }, name: 'zs', say: "funtion(){alert('hello')}" }
// { a: { b: 1 }, name: 'zs', say: "funtion(){alert('hello')}" }
new和 Object.create的区别
new
//new 实例化构造函数/类
//做了四件事情
//1. 创建一个空对象
//2.this指向这个空对象
//3. 执行构造函数,给属性添加属性
//4. 返回该对象
Object.create(proto, [propertiesObject])
创建一个新对象,使用 现有的对象 来提供新创建的对象的proto
proto
是新创建对象的原型
propertiesObject
添加到新对象上作为可枚举的属性(自身身上的属性,不是原型链上的)
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function() {
console.log('say hello')
}
let a = new Person()
let b = Object.create(Person.prototype)
console.log(a) //Person { name: undefined, age: undefined }
console.log(b) //Person {} b的构造函数F()在Object.create()内部被隐藏起来了,所以b继承不到构造函数的属性
//但由于 新创建对象和现有对象的原型是一个,所以b实例有say方法
b.say() //say hello
//new 构造函数, 实例可以继承构造函数的属性和原型上的方法
//Object.create() 创建的实例 不能继承构造函数的属性,但因为原型是一个,所以有方法
配置可枚举属性
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function() {
console.log('say hello')
}
let a = new Person()
let b = Object.create(Person.prototype)
//配置新创建对象的可枚举属性
let c = Object.create(Person.prototype, {
name: {
value: 'zsy',
writable: true,
configurable: true,
enumerable: true
},
sex: {
enumerable: true,
get: function() {
return 'hello sex'
},
set: function(val) {
console.log('set value:' + val)
}
}
})
console.log(c) //Person { name: 'zsy', sex: [Getter/Setter] }
继承
- 原型链继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function() {
console.log(`hello,${this.age}的${this.name}`)
}
let p = new Person('zs', 10)
console.log(p) //Person { name: 'zs', age: 10 }
p.say() // hello,10的zs
- call/apply借用继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function() {
console.log('hello')
}
function Child(name, age, skill) {
Person.call(this, name, age)
this.skill = skill
}
let c = new Child('ls', 16, 'play game')
console.log(c) //Child { name: 'ls', age: 16, skill: 'play game' }
- 混合继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function() {
console.log('hello')
}
function Child(name, age, skill) {
Person.call(this, name, age)
this.skill = skill
}
//继承方法
//方式一
// Child.prototype = Person.prototype
//方式二
Child.prototype = Object.create(Person.prototype)
Child.prototype.constructor = Child
Child.prototype.eat = function() {
console.log('eat food')
}
let c = new Child('ls', 16, 'play game')
console.log(c) //Child { name: 'ls', age: 16, skill: 'play game' }
c.say() //hello
console.log(Child.prototype.constructor) //Child
- class继承
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
say() {
console.log('我是父级的函数')
}
}
class Child extends Person {
constructor(name, age, skill) {
super(name, age)
this.skill = skill
}
say() {
super.say()
console.log('我是继承父级的函数')
}
}
let c = new Child('zs', 13, 'play game')
console.log(c)
c.say()
//Child { name: 'zs', age: 13, skill: 'play game' }
// 我是父级的函数
// 我是继承父级的函数