对象的使用
在对象中如果使用字面量定义对象{}只能通过点语法赋值,点语法只是字符串,表达式不能通过点语法赋值
var obj={
aa:‘true’,
bb:'ccc'
}
key值相同 后一个会把前一个覆盖
obj['b'+'b']='dsdsd'
console.log(obj) {aa:'true',bb:'dsdsd'}
## Es6 可以使用表达式作为key值 表达式可以为方法名
var obj={
['b'+'b']:true,
['a'](){return 1}
}
obj['b'+'b']='dsdsd'
console.log(obj) {bb:'dsdsd'}
obj={
a:'1',
b:2
}
obj={
a:'dasdsad',
b:'ssss'
}
通过字面量的方式 新定义一个对象下面会把上面覆盖
console.log(obj) {a:'dasdsad',b:'ssss'}
function Dian(){
obj={
a:'11111'
}
obj.a='aaaa'
obj['b']=2222
点语法 下面会把上面覆盖 只是对值的覆盖 用的还是同一堆内存空间
console.log(obj) {a:'aaaa',b:2222}
}
属性名表达式 与简单表示法 不能同时使用
const foo='bar'
const bar='baz'
const ob={a:'1'}
//const baz={[foo]} 报错
const baz={[foo]:bar}
console.log(baz) //{bar:'baz'}
key 值如果是一个对象会被转化成字符串
const oc={[ob]:'1111'}
console.log(oc) //{[object object]:'1111'}
对象的可枚举性
对象的每一个属性,都有一个描述对象(Descripter),用来控制该属性的行为
enumerable 属性称为可没举性 如果该属性为false 某些操作会忽略当前属性
for in 只遍历自身和继承的可枚举属性
Object.keys() 返回自身所有的可枚举属性
JSON.stringify
Object.assion() 忽略只拷贝对象自身的可枚举属性
obj={
name:'1111'
}
console.log(Object.getOwnPropertyDescriptor(obj,'name'))
// configurable:true enumerable:true value:'1111' writable:true
对象的toString 就是改变可枚举属性 让for in 无法遍历到
console.log(Object.getOwnPropertyDescriptor(obj.toString,'name'))
// configurable:true enumerable:false value:'toString' writable:false
Es6 规定 有Class 的都是不可枚举的
console.log(Object.getOwnPropertyDescriptor(class{foo(){}}.prototype,'foo'))
// configurable:true enumerable:false value:'foo ()' writable:true
属性的遍历
遍历的都是自身属性 继承的属性无法遍历
1. for(const i in Object.getOwnPropertyDescriptor(obj.toString,'name')){
console.log(i,Object.getOwnPropertyDescriptor(obj.toString,'name')[i])
// value toString
// writable false
//enumerable false
//configurable true
}
//Object.keys(obj) 返回一个数组不含Symbol 属性
2. Object.keys(Object.getOwnPropertyDescriptor(obj.toString,'name'))
//[value,enumerable,...]
Object.getOwnPropertyNames 返回一个数组 不含Symbol 属性
console.log(Object.getOwnPropertyNames(Object.getOwnPropertyDescriptor(obj,'name')))
Object.getOwnPropertySymbols(obj) 返回一个数组 包含自身所有Symbol 属性键名
Reflect.ownKey(obj) 返回一个数组 包含自身所有键名 不管键名是 Symbol 还是字符串 还是是否可枚举
遍历对象遵循的次序,首先遍历所有的数值键 ,按照数值升序排序,其次遍历所有的字符串键 ,
按照加入的时间升序排序,最后遍历所有的Symbol 键 按照加入的时间升序排序
Super 关键字
setPrototypeOf() 给当前对象设置原型对象
super 指向对象的原型对象
super 只能写在方法中 只有对象方法的简写 才可以让javaScript 引擎确认定义的是对象的方法
const pro={
foo:‘222’,
x:2,
xx(){
//当前this还是obj
return this.x
}
}
obj={
foo:'hello',
x:1,
find(){
//super.foo 等同于 Object.getPrototypeof(this).foo(属性) 或者 Object.getPrototypeof(this).foo.call(this) 方法
super 查找的是原型上的属性
return super.foo
}
}
//设置当前对象的原型对象
Object.setPrototypeOf(obj,pro)
//不设置原型对象super 就无法找到 this 查找的是当前元素的属性
console.log(obj.find()) //222
创建对象的方法
Object.create() 参数只能是一个null 或者 对象 如果是null 没有原型链 对象有
里面可以创建两个参数 第一个是对象的原型 propertiesObject
第二个参数是 属性描述符 属性描述符 和 Object.defineProperties() 的第二个参数一样 参数对象不能为undefined
也就是说自身必须拥有可枚举属性才有效
字面量创建对象和构造函数创建对象
console.log({},new Object(),Object.create({}))
console.log({x:1}.length,new Object(1).length,Object.create({}).length) undefined undefined undefined
var proo={
a:1
}
var obj={
x:1
}
Object.setPrototypeOf(obj,proo)
console.log(Object.create(proo,Object.getOwnPropertyDescriptors({x:1}))) {x:1}
拷贝属于深拷贝 新创建了一块堆内存空间 虽然值相同但是内存不同
console.log(Object.create(proo,Object.getOwnPropertyDescriptors({x:1}))==obj) false
console.log(obj.__proto__===Object.create(proo).__proto__) true
Javascript 深拷贝和浅拷贝
深拷贝:简单来说就是旧对象 改变 ,新对象保持不变 浅拷贝 : 就是新对象发生改变
基本数据类型:名字和值都存储在栈内存空间内
深拷贝就是针对 引用数据类型 堆内存存储数据 名字地址 存储在栈内存中
栈内存提供一个引用的地址 指向 堆内存中的 存储的值
var arr=[1,2] var arr1=arr arr[0]='111' console.log(arr1) ['111',2]
arr1 只复制了arr 的地址 他们还在共有一块堆内存空间 这就是浅拷贝
深拷贝就是在堆内存中重新开辟一块空间 用来保存arr1的值,他们之间相互不干扰
var obj={
a:1,
b:{
c:'222'
}
}
var obj1=Object.assign({},obj)
obj.a='11'
obj.b.c='ccccc'
Object.assign() 第一层深拷贝 第二层浅拷贝
console.log(obj1) {a:1,b:{c:'cccc'}}
实现深拷贝的方法就是 将值取出来 重新赋值给新创建的对象
JSON.stringify() JSON.parse() 无法实现对象中方法的深拷贝
结构赋值
解构赋值 将一个对象的值拷贝到另一个对象上
结构赋值 要求等号右边是一个对象 如果是null 和 undefined 就会报错
结构赋值的拷贝是浅拷贝,如果一个键是复合类型的值(数组,对象,函数) 那么结构赋值是这个值的引用
obj={a:{b:1}}
let {...x}=obj
x.a.b x就相当于Obj这个值
扩展运算符的解构赋值,只是解构自身属性 不能赋值继承自原型对象的属性 只能复制自身
扩展运算符后面必须是一个变量名 不能是一个结构赋值表达式
let o1={a:1}
let o2={b:1}
o2.__proto_=o1
let {...o3}=02
console.log(o3.a)// undefined 扩展运算符无法拷贝原型上的东西
console.log(o3.b) //1
u 创建对象
let oo=Object.create(null) //创建的对象没有原型
let oq=Object.create({x:1,zz:'aaaa'})
oq.z='1111'
console.log(oq) //{z:'1111'} z:'1111' __proto__ :x:1 ,zz:'aaaa'
let {x,z,...newObj}=oq
console.log(x,z,newObj) //1 1111 {} 扩展运算符无法解析原型上的值
扩展运算符 后面如果不是对象 会自动转化成对象 正数会自动转化成数值的包装对象Number(1)
由于对象没有自身属性 所以会返回一个空对象
console.log(...1) {}
console.log(Object.assign({b:2},{x:1})) {b:2,x:1}
其他基本数据类型都是如此,字符串会转化成类似于数组的对象
扩展运算符和Object.assign({},obj) 一样 都是只拷贝单层数据 对复合数据 第二层 和原型上 的数据无法拷贝
Object.assign() 和 扩展运算符都是只拷贝 对象实例的属性 无法拷贝原型对象的属性
getOwnPropertyDescriptor和getOwnPropertyDescriptors的区别?
getOwnPropertyDescriptor:返回某个对象属性的描述对象
getOwnPropertyDescriptors:返回指定对象的所有自身属性 (非继承属性) 的描述对象
实现对对象继承属性的拷贝
let o1={a:1}
let o2={b:1}
o2.__proto__=o1
非浏览器下不一定部署
const clone1={
__proto__:Object.getPrototypeOf(o2),
...o2
}
// 实现对 o2 原型继承的克隆
console.log(clone1) b:1 __proto__ a:1
const clone2=Object.assign(Object.create(Object.getPrototypeOf(o2)),o2)
console.log(clone2) b:1 __proto__ a:1
const clone3=Object.create(
Object.getPrototypeOf(o2),
Object.getOwnPropertyDescriptors(o2)
)
console.log(clone3) b:1 __proto__ a:1
同一个对象如果key相同 后面会将前面覆盖
const ll={x:1,y:2}
console.log({...ll,x:sss,y:kkk}) {x:sss,y:kkk}
console.log({x:sss,y:kkk,...ll}) {x:1,y:2}
判断对象中是否包含某个属性
JavaScript 的继承属性 和 自身属性
function aa(){this.name="111" 自身属性,在this上定义的都是当前对象的自身属性}
判断 属性是否是自身属性和继承属性
其中in 判断包含自身属性和继承属性
hasOwnProperty 判断是否为自身属性,无法判断原型上的属性
propertylsEnumerable() 是 hasOwnProperty 的增强版
obj={x:1}
var obj1={x:undefined,y:null}
当前对象跟undefined 进行比较 若为true 表示当前对象有这个属性
为false 代表当前对象没有这个属性 toString 是从当前Object 原型上继承的属性
console.log(obj.x !==undefined,obj.y !==undefined,obj.toString !==undefined) true false true
in 可以判断值为undefined 的时候属性是否存在
console.log('x' in obj,'y' in obj 'toString' in obj) true false true
console.log(obj1.x !==undefined ,obj1.y !== undefined,'x' in obj1 ,'y' in obj1) false true true true
判断继承属性
pro={
ss:'2222'
}
obj={
aa:'1111'
}
Object.setPrototypeof(obj,pro)
console.log(Object.getPrototypeof(obj)) {ss:'2222'} 获取原型上的属性
console.log('ss' in obj,obj.hasOwnProperty('aa'),obj.hasOwnProperty('ss')) true true false
判断属性类型
typeof
instanceof :判断一个构造函数的Prototype属性所指向的对象,是否存在另一个要检测对象的原型链上,判断一个实例是否属于原型链上的属性
isPrototypeof : 判断实例是否指向某个对象的原型对象 判断这个实例是否是当前对象的实例
console.log(typeof null,typeof [],typeof window ,typeof global) object object object undefined
console.log([] instanceof Array,[] instanceof object) true true
funcrion a(){} function b(){} const c=new a()
console.log(a.prototype.isPrototypeof(c),Object.prototype.isPrototypeof(c),b.prototype.isPrototypeof(c)) true true false
const 定义常量
const 定义的基本类型都是无法更改的
栈内存空间 线性排列的每个小单元大小基本相等,已知大小,范围有上限,
null 为空 类型为Object 存储在栈内存中
对于基本数据类型 值就是指针 对于引用数据类型 常量就是指针
const 定义的对象 指向堆内存的地址指针是不可变的 堆内存的数据是可变的
const let 初始化一个变量首先要遍历当前的内存栈 有重名的返回错误
new 初始化之后返回一个对象
值类型 和 引用类型 就是栈变量和堆变量
const kk={o:1}
内存分配和垃圾回收
一般来说:栈内存是有序回收,容量小 ,分配效率高
堆内存需要重新分配存储区域,之后就把指针存储在堆内存中,效率相对低一些,
垃圾回收方面:栈内存用完就回收了,堆内存需要调用的变量全部销毁才可以回收。