javascript-对象object
1.对象是引用操作而不是值操作
object a;object b;
a=b;如果b中有属性x;更改b.x会同时更改a.x,两者指向同一片内存空间。
2.对象的定义会每次为对象分配内存空间。使用For循环创建的对象每个都是独立内存空间,是不同的对象。
3.对象的创建
Object.create();
let o2=Object.create(null);
null导致o2不会继承任何prototype的任何属性方法,例如toString()
如果需要创建一个空对象可以使用
let o3=Object.create(Object.prototype);
object.create()方法的一个应用时其他函数无意之间的对对象的修改
let o={x:"don't change this value"};
library.function(Object.create(o));//防止修改o
4.查询和设置属性
可以使用.运算符和[]运算符访问对象的属性。
.运算符必须访问对象的属性名。[]运算符中必须得到一个字符串。例
let author=book.author;
let name=author.name;
let title=book["main title"];
设置,方法类似
book.edition=7;
book["main title"]="ECMAscript";
下述方法得到的值是相同的
object.property
object["property"]
5.下面的代码将address0-3属性拼接到addr中
let addr=""
for(let i=0;i<4;i++){
addr+=customer[`address${i}`]+"\n";
}
[]运算的优势在于可以在运行时动态添加查询数据,.运算符则不行。
5.防止空对象的一种赋值方式
let surname=undefined;
if(book){
if(book.author){
surname=book.author.surname;
}
简写为:
surname=book&book.author&book.author.surname;运用了短路机制
也可写为
let surname=book?.author?.surname;
6.在严格模式中,设置变量失败会抛出TypeError。非严格模式则不会。
6.4删除运算符
用于删除对象属性
delete book.author;
delete book["main title"];
delete只能删除对象自身拥有的属性,继承过来的属性无法删除。
delete会被判定为true,三种情况,删除成功,或删除没有生效或试图删除没有访问权限的元素
let o={x:1};
delete o.x;//true 成功删除
delete o.x;//true x不存在,删除没有生效
delete o.toString//true toString是继承的方法,不是o的属性。但是返回true、
delete 1;//没有意义,但是是true
试图删除不可配置的对象会返回false。严格模式会抛出TypeError,非严格模式返回False
delete Object.prototype;//false 不可配置对象
var x=1;
delete globalThis.x;//false 无法删除
function f(){};
delete globalThis.f;//false
严格模式,删除未初始化标识符抛出异常,必须明确指定删除元素
globalThis.x=1;
delete x;//SyntaxError不存在x
delete globalThis.x;//true
6.5测试属性
测试属性是否存在
let o={x:1};
"x" in o//true
"y" in o//false
"toString" in o//true 继承属性
使用hasOwnProperty()方法测试自身属性是否存在,继承属性返回false
let o={x:1};
o.hasOwnProperty("x");//true
o.hasOwnProperty("y");//false 不存在y
o.hasOwnProperty("toString");//false 继承属性返回false
使用propertyIsEnumerable()测试属性是否可枚举。内置属性时不可枚举的。被Js代码创建的属性一般是可枚举的,除非设置属性不可枚举。
测试是否枚举前函数会测试是否是自身属性。hasOwnProperty
let o={x:1};
o.propertyIsEnumberable("x");//true
o.propertyIsEnmberable("toString");//false 非自身属性
Object.prototype.propertyIsEnmberable("toString");//false 不可枚举
也可使用!==判断属性存在否
let o={x:1};
o.x!==undefined;//true
o.y!==undefined;//false
o.toString!==undefined;//false
6.5枚举属性
let o={x:1,y:2,z:3};//可枚举
o.propertyIsEnumberable("toString")//不可枚举
for(let p in o){
console.log(p);
}
for(let p in o){
if(!o.hasOwnProperty(p))continue;//skip 继承属性
}
for(let p in o){
if(typeof o[p]==="function")continue;//skip 所有方法
}
四个方法:
Object.keys()返回可枚举自有属性名的数组。不含不可枚举类型,继承类型,类型名为Symbol的属性
Object.getOwnPropertyNames();与key方法类似,返回自有属性名数组,包含不可枚举属性,比如string
Object.getOwnPropertySymbols();返回属性名为Symbol的类型数组,包含可枚举和不可枚举的。
Reflect.ownKeys()返回所有自有属性名,包含可枚举,不可枚举,字符串和Symbol类型
6.6.1属性枚举顺序
1.字符串属性是非负整数首先列出,从小到大。所以数组和数组对象会按顺序枚举。总小到大
2.剩余以字符串命名的属性被列出。包含属性类似于负数和浮点数的。这一类型的属性以加入对象的顺序从先往后列出。
3.Symbol类型的对象被列出,按加入对象的顺序从前往后。
6.7扩展对象
ES6 Object.assign();参数为两个或更多的对象。方法修改和返回第一个对象,对第二个和后续的对象,拷贝其中的可枚举类型至第一个对象。会覆盖第一个对象拥有的同名属性。
使用技巧
Object.assign(o,defaults);//会将o中的属性全部用defaults覆盖
o=Object.assign({},defaults,o);//会保留o中属性的值,Default中其他的属性也会正常保存
此类操作的方法还有restrict(),subtract()
6.9.2 toLocaleString()方法
Date,Number,Array拥有toLocaleString()方法,会对字符串进行特殊处理,格式化。(待实验)
6.9.3 valueOf()方法。定义valueOf方法会允许进行比较操作例
let point={
x:3,
y:4,
valueOf:function(){return Math.hypot(this.x,this.y);}
Number(point);//调用valueOf方法进行类型转换。
point>4;//true
point>5;//false
point<6;//true
6.9.4 toJSON方法。会对字符串进行序列化。
6.10.2 使用[]计算属性名
一些属性名是要经过计算才得出的可以使用[]
例:
const PROPERTY_NAME="p1";
function computePropertyName(){return "p"+2;}
let p={
[PROPETY_NAME]:1,//p1:1
[computePropertyName()]:2;//p2:2
};
p.p1+p.p2;//3
6.10.3 Symbol作为属性名
const extension=Symbol("my extension symbol");
let o={
[extension]:{/*somedata*/}
};
o[extension].x=0;
Symbol的使用是调用Symbol()工厂函数,Symbol是基础类型,它的特点是不会重复。适合储存唯一的变量名。两次调用Symbol即使传入相同的内容也会得到不同的结果。
如果你使用第三方库,想向第三方库中的对象添加一些属性,但不能更改原有属性,使用Symbol是一种比较安全的做法。这样你不会无意间修改了第三方库的对象。
但第三方库也可以调用Object.getOwnPropetySymbols()发现你添加的属性。所以Symbol不是一种特别安全的机制。
6.10.4 Spread操作符
let position={x:0,y:0};
let dimensions={width:100,height:75};
let rect={...position,...dimensions};
rect.x+rect.y+rect.width+rect.height;//result=175
...被称为Spread Opertator
如果对象中含有同名属性,后者覆盖前者
let o={x:1};
let p={x:0,...o};
p.x;// 1 后者覆盖前者
let q={...o,x:2};
q.x;//2 同理
Spread操作符不Spread嵌套属性
let o=Object.create({x:1});
let p={...o};
p.x//undefined
循环嵌套时注意效率,...操作符可能会引起n方的时间复杂度。
6.10.5 速记方法Shorthand Methods
传统定义方法:
let square={
area:function(){return this.side*this.side;},
side:10
};
ES6后的速记法:省略function,使用{}表示是方法。
let square={
area(){return this.side*this.side;},
side:10
};
square.area();
使用[]的速记法
const METHOD_NAME="m";
const symbol=Symbol();
let weirdMethods={
“method with Spaces”(x){return x+1;},
[METHOD_NAME](x){return x+2;},
[symbol](x){return x+3;}
};
weirdMethods["method With Spaces"](1)//result=2
weirdMethods[METHOD_NAME](1)//result=3
weirdMethods[symbol](1)/result=4
6.10.6 getter setters
属性只有getter方法,只读
只有setter方法,只写
let o={
dataProp:value,
get accessorProp(){return this.dataProp;}
set accessorProp(value){this.daProp=value;}
};
let p={
x:1.0;
y:1.0;
//read-write accessor
get r(){return Math.hypot(this.x,this.y);},
set r(newvalue){
let oldvalue=Math.hypot(this.x,this.y);
let ratio=newvalue/oldvalue;
this.x*=ratio;
this.y*=ratio;
},
get theta{return Math.atan2(this.y,this.x);}//read-only
}
p.r//调用get方法
p.theta//调用Get方法
Accessor属性可被继承。
let q=Object.create(p);
q.x=3;q.y=4;
q.r//继承自p的get方法
q.theta//同上
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)