深入js对象
对象是 JavaScript 的核心概念之一,也是最常用的数据类型,即引用型数据。对象可以包含多个属性,属性以名值对的形式存在,名称是字符串,值可以是任意类型的数据。除了字符串、数字、布尔、symbol、null 和 undefined 六种基本数据类型之外,JavaScript 中的值都是对象,包括Obiect类型,Array类型,Date类型,RegExp类型,Function类型,基本包装类型,单体内置对象(Global对象,window对象,Math对象)。
1.创建js对象
- var obj = new Object(); //创建空对象 有原型链属性
- var obj = {};//创建空对象 有原型链属性
- var obj = Object.create(null);//创建空对象 无属性 没有原型链指向
2.对象属性
1.属性定义:字符串,数字,变量,函数
var person={
name:"zhangsan",
age:"16"
}
var obj={}
obj.name="zhangsan";
obj['sex']="nan";
2.属性特性:可写,可枚举,可配置
var person={
age:'15'
};
Object.defineProperty(person,'name',{
configurable:false,//是否可以被删除
writable:false, //是否可以被修改
enumerable:true, //是否可以被枚举
value:'zhangsan'
}
person.name="lisi";
person.age="25"
console.log(person)//{
age:'33',//可以修改
name:'zhangsan'//不可修改
}
console.log(Object.getOwnPropertyNames(person))//getOwnPropertyNames 可以轮循所有属性 即使enumerable设置不可被枚举
3.对象继承
-
原型
每个构造函数都有一个prototype属性,指向函数的原型对象;原型对象中又有一个constructor属性,重新指向构造函数。而对象实例中有一个原型指针[[prototype]],指向原型对象。Javascript规定,每一个函数都有一个prototype对象属性,指向另一个对象(原型链上面的)。prototype(对象属性)的所有属性和方法,都会被构造函数的实例继承。
每个对象都有一个proto属性,原型链上的对象正是依靠这个属性连结在一起作为一个对象,当你访问其中的一个属性或方法的时候,如果这个对象中没有这个 方法或属性,那么Javascript引擎将会访问这个对象的proto属性所指向上一个对象,并在那个对象中查找指定的方法或属性,如果不能找到,那就会继续通过那个对象 的proto属性指向的对象进行向上查找,直到这个链表结束。
-
原型继承
var person = {
name:"zhangsan",
address:"henan"
};
var person2= Object.create(person);
console.log(person)//---{} 空对象有原型链
console.log(person2.name)//---zhangsan
function person(){
this.name="zhangsan "
}
function subPerson = {
}
subPerson.prototype=new person();
console.log(subPerson.name)//====>
//这是父类构造函数
function Parent() {
this.money = 1000;
this.colors = ["red", "blue"];
}
//给父类构造函数的原型上添加一个方法
Parent.prototype.getMoney = function() {
console.log(this.money);
}
//这是子类构造函数
function Child() {}
//子类通过原型链的方式继承父类
Child.prototype = new Parent();
Child.prototype.constructor = Child;
//声明一个子类实例
let child1 = new Child();
child1.colors.push("yellow");
console.log(child1.colors);//["red", "blue", "yellow"]
//再声明一个子类实例
let child2 = new Child();
console.log(child2.colors);//["red", "blue", "yellow"]
4.对象的序列化
对象序列化是指将对象的状态转换为字符串,也可将字符串还原为对象。ECMAScript 5 提供了内置函数JSON.stringify()和JSON.parse()用来序列化和还原js对象,这些方法都使用JSON作为数据交换格式。但是用JSON.stringify()原生序列化只能序列化对象的属性,方法是不能够被序列化的。
序列化最终的目的是为了对象可以跨平台存储、进行网络传输。而进行跨平台存储和网络传输的方式就是数据IO,数据IO支持的数据格式是字节数组(byte array)。序列化的目的就是将对象转换为字节数组已备跨平台存储和网络传输。
递归实现深拷贝
function deepClone(obj){
//数据类型为引用数据类型
if(typeof obj=='object'){
//初始化返回结果
let result = Array.isArray(obj)?[]:{};
fot(let key in obj){
//避免相互引用出现死循环导致爆栈
if(obj==obj[key]){
continue
}
if(obj.hsaOwnProperty(ket)){
//递归调用
result[key]=deepClone(obj[key])
}
}
return result;
}esle{
//基本数据类型
return obj
}
}
console.log(deepClone(obj))
5.loadsh
Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。 常用功能:数组去重,升序排序,random,range,max:数据处理等
参考官网:www.lodashjs.com/
//深拷贝
var _=require('loadsh');
var objects = [{'a':1},{'b':2}];
var shallow = _.cloneDeep(objects);
objects.a=10;
console.log(shallow)//{'a':1},{'b':2}
console.log(objects)//{'a':10},{'b':2} 内存地址发生改变
//浅拷贝
var o1 = { name: 'johan' };
var o2 = o1;
o2.name = 'elaine';
console.log(o1); // {name: 'elaine'}
console.log(o2); // {name: 'elaine'}
因为 Object 是引用类型,引用类型的拷贝拷贝的是引用地址,所以当 o2 被修改时,o1 也随之被修改
6.对象内存
var myNumber = 23;
var newVal=muNumber;
muNumber=muNumber+1;
js执行该代码时会进行一下操作:
1.为变量num创建一个唯一标识(myNumber),该标识符用于栈内存中的地址A形成映射关系。
2.在栈内存中为其分配一个地址A1.
3.将值24存储到分配的地址。
4.将newVal指向分配地址A1.
5。在内存中重新分配一块新的空间用于存放24这个值并分配给myNumber。//基本数据类型是不可变的
函数提升
var a =1;
function sa(){
congsole.log(a);//undefined 预编译的时候会对函数sa()进行提升至最上边
var a=10;
console.log(a);//10
}
sa();
console.log(a);//1