1、JS对象

1.1 JS对象特征

1、JS对象是基本数据数据类型之一,是一种复合值,可以看成若干属性的集合。

  • 属性是名值对的形式(key:value)
  • 属性名是字符串,因此可以把对象看成是字符串到值的映射

2、对象除了可以保持自有的属性,还可以从一个称为原型的对象继承属性。其中,原型链继承是JavaScript的核心特征。 3、对象是动态的,可以增加或删除属性。 4、除了字符串、数值、true、false、null和undefined,其它值都是对象。 5、对象最常见的用法是对其属性进行创建、设置、查找、删除、检测和枚举等操作。

  • 属性值是任意JavaScript值,或者是一个getter或setter函数
  • 每个属性还有一些与之相关的值,称为“属性特征。分别为:可写(writable attribute,表明是否可以设置属性的值)、可枚举(enumerable attribute,表明是否可以通过for/in结构返回该属性)和可配置(configurable attribute,表明是否可以删除或修改该属性)。

6、每个对象还拥有三个相关的对象特性。分别为:

  • 对象的原型 (prototype)指向另一个对象,该对象的属性会被当前对象继承)
  • 对象的类(class)一个标识对象类型的字符串
  • 对象的扩展标记(extensible flag)指明了是否可以向该对象添加新属性)。 7、对象分为内置对象、宿主对象、自定义对象。 8、属性分为自由属性和继承属性。

1.2 JS创建对象

1.2.1 通过字面量创建对象(key:value)

对象字面量是一个表达式,每次运算都会创建一个新的对象,其中的属性值也会重新计算。如:

let empty = {};
let point = { x: 0, y: 0 };
let book = {
"first title": "JavaScript",
"second-title": "HTML5 CSS3",
for: "readers",
author: {
firstname: "xiao",
lastname: "ming",
},
};

在这个例子里,先创建了一个空对象,没有任何属性,然后创建了point对象,赋予了它两种属性,分别是x和y,book对象,赋予了first title,second-title,for,author四个属性,属性名可以是字符串也可以是对象。若属性名有空格或特殊字符,必须用字符串表示。属性名可以是保留字,但尽量避免。 当然,通过字面量创建还可以先给对象留空{},通过对象名.属性名或对象名["属性名"]来进行对象的赋值,如:

let book = {}
book.author = {
firstname: "xiao",
lastname: "ming",
},
book.for = "readers"
book.salestate = "good"
book["first title"] = "JavaScript",
book["second-title"] = "HTML5 CSS3"

1.2.2 通过new创建对象

通过new调用构造函数来创建并初始化一个新对象,通过对象名.属性名或对象名["属性名"]来进行对象赋值。 JavaScript语言核心中的原始类型都包含内置构造函数,如Object()、Array()、Date()等,如:

let book = new Object()
book['author'] = {
firstname: "xiao",
lastname: "ming",
},
book.for = "readers"
book.salestate = "good"
book['first title'] = "JavaScript",
book['second-title'] = "HTML5 CSS3"
console.log(book);

1.2.3 通过Object.create()创建对象

对象也可以用Object.create(proto, [ propertiesObject ])方法创建,其中,proto指这个对象的原型对象,propertiesObject 可选参数,用以对对象的属性进行描述。该方法可以在创建对象时指定原型或若干属性的对象。如:

let obj1 = Object.create({ x: 1, y: 2 });
// obj1继承了属性x和y。
let obj2 = Object.create(null);
//obj2不继承任何属性和方法。
let obj3 = Object.create(Object.prototype);
//obj3是一个普通的空对象。

1.3 原型

1、每一个JavaScript对象(null除外)都和原型对象相关联。每一个对象都从原型继承属性。 2、所有通过对象字面量创建的对象都具有同一个原型对象,可通过Object.prototype获得原型对象的引用。 3、通过new和构造函数创建的对象的原型就是构造函数的prototype属性引用的对象。如:

let book = new Object()
book['author'] = {
firstname: "xiao",
lastname: "ming",
}
console.log(Object.prototype); // [Object: null prototype] {}
console.log(Object.getPrototypeOf(book)); // [Object: null prototype] {}
console.log(book.__proto__); // [Object: null prototype] {}

4、极少数的对象没有原型,如:Object.prototype,它不继承任何属性。 5、所有内置构造函数都具有一个继承自Object.prototype的原型。

  • Array.prototype的属性继承自Object.prototype
  • 这种通过层级的原型继承形成的链接,称为“原型链”

示例:

let obj = { value: 100 };
Object.prototype.sex= "boy";
console.log(obj.sex); // boy
let arr = [1, 2, 3, 4];
console.log(arr.sex); // 继承了Object新添加的sex属性,输出boy

1.4 对象的属性

1.4.1 对象中属性的访问方式

若存在一个对象person,里面有fullname,sex,age属性。要访问这些属性,可以通过person.sex等进行访问。也可以通过person['sex'],如:

let person = Object.create({
fullname:"小明",
age: 12,
sex: "男"
})
console.log(person.fullname); // 小明
console.log(person['age']); // 12
console.log(person['sex']); // 男

1.4.2 作为关联数组的对象

举个例子:

let result = {
data1: {
name: "Language",
value: "Chinese",
},
data2: {
name: "Country",
value: "China",
},
data3: {
name: "Gender",
value: "Male",
},
};
for (let i = 1; i < 4; i++) {
let data = result["data" + i];
console.log(`${data.name}-->${data.value}`);
}

输出结果: Language-->Chinese Country-->China Gender-->Male

1.4.3 对象中属性的继承(原型链继承)

原型链继承是将父类的实例作为子类的原型,继承后父类方法可以复用,但是父类的引用属性会被所有子类实例共享,并且子类构建实例时不能向父类传递参数。如:

function Parent() {
this.parentName = '父级函数';
}
Parent.prototype.getParentName = function () {
return this.parentName;
};
function Child() {
this.childName = '子级函数';
}
// 继承 Parent
Child.prototype = new Parent();
Child.prototype.getChildName = function () {
return this.childName;
};
let a = new Child();
console.log(a.getParentName());

运行结果: 父级函数

1.4.4 属性访问错误

  • 查询一个不存在的属性并不会报错,如果在对象o自身的属性或继承的属性中均未找到属性x,属性访问表达式o.x返回undefined。

  • 但是,如果对象不存在,那么试图查询这个不存在的对象的属性就会报错。

  • null和undefined值都没有属性,因此查询这些值的属性会报错。 举个例子: 改变前:

    let one = { two: { three: 3 } };
    console.log(one.two.three);
    if (one) {
    if (one.two) {
    if (one.two.three) console.log(one.two.three);
    }
    }
    console.log(one && one.two && one.two.three);
    console.log(one?.two?.three); // Null传导运算符

    输出: 3 3 3 3

    改变后:

    let one = {};
    console.log(one.two.three);
    if (one) {
    if (one.two) {
    if (one.two.three) console.log(one.two.three);
    }
    }
    console.log(one && one.two && one.two.three);
    console.log(one?.two?.three); // Null传导运算符

    输出结果: TypeError: Cannot read property 'three' of undefined

  • 在以下场景下给对象o设置属性p会失败:

    • o中的属性p是只读的:不能给只读属性重新赋值(defineProperty()方法中有一个例外,可以对可配置的只读属性重新赋值)。
    • o中的属性p是继承属性,且它是只读的:不能通过同名自有属性覆盖只读的继承属性。
    • o中不存在自有属性p:o没有使用setter方法继承属性p,并且o的可扩展性(extensible attribute)是false。如果o中不存在p,而且没有setter方法可供调用,则p一定会添加至o中。但如果o不是可扩展的,那么在o中不能定义新属性。

1.4.5 删除属性方法

delete运算符可以删除对象的属性。

  • 它的操作数应当是一个属性访问表达式
  • delete只是断开属性和宿主对象的联系,而不会去操作属性中的属性。
  • delete运算符只能删除自有属性,不能删除继承属性。若要删除继承属性必须从定义这个属性的原型对象上删除它,而且这会影响到所有继承自这个原型的对象。
  • delete不能删除那些可配置性为false的属性。某些内置对象的属性是不可配置的,比如通过变量声明和函数声明创建的全局对象的属性。

举个例子:

let book = new Object()
book['author'] = {
firstname: "xiao",
lastname: "ming",
}
book.name="致明天",
book.salenum=123456,
book.price=12
console.log("删除前:",book);
delete book.author;
delete book.toString()
console.log("删除后:",book);

运行结果: 删除前: { author: { firstname: 'xiao', lastname: 'ming' }, name: '致明天', salenum: 123456, price: 12 } 删除后: { name: '致明天', salenum: 123456, price: 12 }

1.4.6 检测属性方法

判断某个属性是否存在于某个对象中,可以通过in运算符、hasOwnPreperty()和propertyIsEnumerable()方法,甚至也可以仅通过属性查询。如:

let o = { x: 1 };
console.log("x" in o); // true
console.log("y" in o); // false
console.log("toString" in o); // true console.log(o.hasOwnProperty("x")); // true
console.log(o.hasOwnProperty("y")); // false
console.log(o.hasOwnProperty("toString")); // false console.log(o.propertyIsEnumerable("x")); // true
console.log(o.propertyIsEnumerable("y")); // false
console.log(o.propertyIsEnumerable("toString")); // false
console.log(Object.prototype.propertyIsEnumerable("toString")); // false

1.4.7 枚举属性方法

1、for/in循环可以在循环体中遍历对象中所有可枚举的属性(包括自有属性和继承的属性),把属性名称赋值给循环变量。 注意:对象继承的内置方法不可枚举的,但在代码中给对象添加的属性都是可枚举的。

let obj = Object.create({ a: 10, b: 20 });
obj.c = 30;
for (let i in obj) {
console.log(i, obj[i]);
}

输出结果: c 30 a 10 b 20

2、利用for/in循环,可以对两个对象进行各种形式的合并。 3、Object.keys(),它返回一个数组,这个数组由对象中可枚举的自有属性的名称组成。如:

let obj = Object.create({ a: 10, b: 20 });
obj.c = 30;
obj.d = 40;
console.log(Object.keys(obj));

输出结果: [ 'c', 'd' ]

4、Object.getOwnPropertyNames(),它和Ojbect.keys()类似,只是它返回对象的所有自有属性的名称,而不仅仅是可枚举的属性。如:

let obj = Object.create({ a: 10, b: 20 });
obj.c = 30;
obj.d = 40;
console.log(Object.getOwnPropertyNames(obj));

输出结果: [ 'c', 'd' ]

1.4.8 属性的getter和setter

  • 对象属性是由名字、值和一组特性构成的。 在es5中,属性值可以被getter和setter两种方法替换,由getter和setter定义的属性称为存储器属性,它不同于数据属性,数据属性只是简单的一个值。
  • 当程序查询存取器属性的值时,JS调用getter方法(无参数),这个方法的返回值就是属性存取表达式的值。
  • 当程序设置一个存取器属性的值时,JS调用setter方法,将赋值表达式右侧的值当做参数传入setter。从某种意义上讲,这个方法负责“设置”属性值。可以忽略setter方法的返回值。

实例:

let circle = {
r: 10,
get round() {
return 2 * this.r * Math.PI
},
set round(v) {
this.r = v / 2 / Math.PI
},
get area() {
return Math.PI * this.r ** 2
}
}
console.log(circle.round, circle.area)
circle.round = 60
console.log(circle.r, circle.area) let circle1 = Object.create(circle);
// 和数据属性一样,存取器属性是可以继承的。
circle1.r = 20;
console.log(circle1.round);
circle1.round = 500;
console.log(circle1.r, circle1.area);

输出结果: 62.83185307179586 314.1592653589793 9.549296585513721 286.47889756541167

125.66370614359172 79.57747154594767 19894.367886486918

1.4.9 属性的特性

1、除了包含名字和值之外,属性还包含一些标识它们可写、可枚举和可配置的特性。

  • 可以通过这些API给原型对象添加方法,并将它们设置成不可枚举的,这让它们看起来更像内置方法。
  • 可以通过这些API给对象定义不能修改或删除的属性,借此“锁定”这个对象。

2、数据属性的4个特性 值(value)、可写性(writable)、可枚举性(enumerable)和可配置性(configurable)。

3、存取器属性不具有值(value)特性和可写性。

  • 它们的可写性是由setter方法存在与否决定的。
  • 因此存取器属性的4个特性是读取(get)、写入(set)、可枚举性和可配置性。

4、通过一个名为“属性描述符”(property descriptor)的对象实现属性特性的查询和设置操作。

  • 这个对象代表那4个特性。
  • 描述符对象的属性和它们所描述的属性特性是同名的。因此,数据属性的描述符对象的属性有value、writable、enumerable和configurable。
  • Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述符。
  • 对于继承属性和不存在的属性,返回undefined。

如:

let circle = {
r: 10,
get round() {
return 2 * this.r * Math.PI
},
set round(v) {
this.r = v / 2 / Math.PI
},
get area() {
return Math.PI * this.r ** 2
}
} let circle1 = Object.create(circle); console.log(Object.getOwnPropertyDescriptor(circle, "r"));
console.log(Object.getOwnPropertyDescriptor(circle1, "r"));

输出: { value: 10, writable: true, enumerable: true, configurable: true } undefined

5、要想设置属性的特性,或者想让新建属性具有某种特性,则需要调用Object.definePeoperty(),传入要修改的对象、要创建或修改的属性的名称以及属性描述符对象。传入Object.defineProperty()的属性描述符对象不必包含所有4个特性。如:

let o = {};
Object.defineProperty(o, "x", {
value: 10,
writable: true,
enumerable: false,
configurable: false,
}); console.log(o.x, Object.keys(o)); // 10 []

6、如果要同时修改或创建多个属性,使用Object.defineProperties()。第一个参数是要修改的对象,第二个参数是一个映射表,它包含要新建或修改的属性的名称,以及它们的属性描述符。如:

let p = Object.defineProperties(
{},
{
x: { value: 1, writable: true, enumerable: true, configurable: true },
y: { value: 1, writable: true, enumerable: true, configurable: true },
r: {
get: function () {
return Math.hypot(this.x, this.y);
},
enumerable: true,
configurable: true,
},
}
);

1.5 对象的特性和序列化对象

1.5.1 原型属性

原型属性是在实例对象创建之初就设置好的。

  • 原型属性是在实例对象创建之初就设置好的
  • 将对象作为参数传入Object.getPrototypeOf()可以查询它的原型
  • 要想检测一个对象是否是另一个对象的原型(或处于原型链中),使用isPrototypeOf()方法。(和instanceof运算符非常类似) 如:

    let o = { x: 1 };
    let p = Object.create(o);
    p.y = 2;
    console.log(Object.getPrototypeOf(p)); // { x: 1 }
    console.log(o.isPrototypeOf(p)); // true

1.5.2 可扩展性

对象的可扩展性用以表示是否可以给对象添加新属性。

  • 所有内置对象和自定义对象都是显式可扩展的。
  • 宿主对象的可扩展性是由JavaScript引擎定义的。

1.5.3 序列化对象

1、对象序列化是指将对象的状态转换为字符串,也可将字符串还原为对象。 2、ES5提供了内置函数JSON.stringify()和JSON.parse()用来序列化和反序列化JavaScript对象。 3、注意事项

  • 函数、RegExp、Error对象和undefined值不能序列化和还原。
  • JSON.stringify()只能序列化对象可枚举的自有属性
  • 对于一个不能序列化的属性来说,在序列化后的输出字符串中会将这个属性省略掉

1.6 Object 构造函数的方法

Object构造函数提供了如下方法:

方法 描述
Object.assign() 通过复制一个或多个对象来创建一个新的对象。
Object.create() 使用指定的原型对象和属性创建一个新对象。
Object.defineProperty() 给对象添加一个属性并指定该属性的配置。
Object.defineProperties() 给对象添加多个属性并分别指定它们的配置。
Object.entries() 返回给定对象自身可枚举属性的 [key, value] 数组。
Object.freeze() 冻结对象,其他代码不能删除或更改任何属性。
Object.getOwnPropertyDescriptor() 返回对象指定的属性配置。
Object.getOwnPropertyNames() 返回一个数组,它包含了指定对象所有的可枚举或不可枚举的属性名
Object.getOwnPropertySymbols() 返回一个数组,它包含了指定对象自身所有的符号属性。
Object.getPrototypeOf() 返回指定对象的原型对象。
Object.is() 比较两个值是否相同。所有 NaN 值都相等(这与==和===不同)。
Object.isExtensible() 判断对象是否可扩展。
Object.isFrozen() 判断对象是否已经冻结。
Object.isSealed() 判断对象是否已经密封。
Object.keys() 返回一个包含所有给定对象自身可枚举属性名称的数组。
Object.preventExtensions() 防止对象的任何扩展。
Object.seal() 防止其他代码删除对象的属性。
Object.setPrototypeOf() 设置对象的原型(即内部 [[Prototype]] 属性)。
Object.values() 返回给定对象自身可枚举值的数组。

JS学习笔记 (三) 对象进阶的更多相关文章

  1. [JS学习笔记]Event对象

    写在前面 学习和总结JS时会伴随性的生成一些dome,其中包含一些动态输出的结果和标注. 之前通过鸡贼的办法实现了在博客中执行JS,但很多时候需要一张干净的页面编写dome,所以尝试通过一些在线的JS ...

  2. JS学习笔记 (五) 函数进阶

    1.函数基础 1.1 函数的基本概念 函数是一段JavaScript代码,只被定义一次,但是可以被调用或者执行许多次.函数是一种对象,可以设置属性,或调用方法. 函数中的参数分为实参和形参.其中,形参 ...

  3. Node.js学习笔记(三) --- package.json 及cnpm

    一.包 Nodejs   中除了它自己提供的核心模块外,我们可以自定义模块,也可以使用第三方的模块.Nodejs 中第三方模块由包组成,可以通过包来对一组具有相互依赖关系的模块进行统一管理. 完全符合 ...

  4. JS学习笔记 (四) 数组进阶

    1.基本知识 1.数组是值的有序集合.每个值叫做一个元素,而每个元素在数组中的位置称为索引,以数字表示,以0开始. 2.数组是无类型的.数组元素可以是任意类型,并且同一个数组中的不同元素也可能有不同的 ...

  5. 【学习】js学习笔记:对象的遍历和封装特性

    1.对象的属性访问: 对象.属性 对象[属性],但中括号中必须是字符串 2.属性的遍历: for in方法举例: var ren={}; ren.name="名字"; ren.ea ...

  6. 【学习】js学习笔记:对象的一些基础知识

    1.创建对象 //构造函数方法 function fun1(){} var obj=new fun1(); //Object方法,O要大写 var obj1=new Object(); //json方 ...

  7. js学习笔记25----Event对象

    Event : 事件对象,当一个事件发生的时候,和当前这个对象发生的这个事件有关的一些详细的信息都会被临时保存到一个指定的地方-event 对象,供我们在需要时调用. 事件对象必须在一个事件调用的函数 ...

  8. js学习笔记-日期对象

    <body> <script> var d = new Date() console.log(d) var arr = ['星期日', '星期一', '星期二', '星期三', ...

  9. 【学习】js学习笔记---数组对象

    一.属性 length 数组的大小.数组的length属性总是比数组中定义的最后一个元素的下标大一,设置属性length的值可以改变数组的大小.如果设置的值比它的当前值小,数组将被截断,其尾部的元素将 ...

随机推荐

  1. JWT签发与解析

    需要的依赖: <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</ ...

  2. Java对象已死吗 深入理解Java虚拟机笔记

    1.引用计数器法 给每个对象设置一个计数器,每当有一个引用就给计数器的值+1,引用时小时就减一,当计数器值为0是就可以回收掉了. 主流虚拟机都没有使用这种算法,循环依赖问题 2.可达性分析: 思路是通 ...

  3. 「2020-2021 集训队作业」Yet Another Linear Algebra Problem(行列式,Binet-Cauchy 公式)

    题面 出题人:T L Y \tt TLY TLY 太阳神:Tiw_Air_OAO 「 2020 - 2021 集 训 队 作 业 」 Y e t A n o t h e r L i n e a r A ...

  4. logstash客户端传送symantec日志到elasticsearch

    一.安装相应版本的logstash wget https://artifacts.elastic.co/downloads/beats/logstash/logstash-7.5.2-x86_64.r ...

  5. Openstack Neutron:三层技术和实现

    目录 - 1.Neutron 三层技术简介 - 2.集中式router - 1.在节点上安装L3 agent - 2.配置外部网络 - 3.通过CLI或者Horizon 来创建路由 - 4.连接租户网 ...

  6. 从Java 9 到 Java 17 新特性梳理

    Java 9 新的创建集合的方法  // [1, 2, 3, 4]  List<Integer> integers = List.of(1, 2, 3, 4);  // {1,2,3}   ...

  7. 新渲染引擎、自定义设计和高质量用户体验的样例应用 Wonderous 现已开源

    探索世界奇观,并体验 Flutter 的强大之处. Flutter 的愿景是让你能够在空白画布上绘制出不受限制的精美应用.最近,通过与 gskinner 团队的通力合作,我们打造了一个全新的移动应用 ...

  8. 当 EDA 遇到 Serverless,亚马逊云科技出招了

    近二三十年来,软件开发领域毫无疑问是发展最为迅速的行业之一. 在上个世纪九十年代,世界上市值最高的公司大多是资源类或者重工业类的公司,例如埃克森美孚或者通用汽车,而现在市值最高的公司中,纯粹的软件公司 ...

  9. ProxySQL(6):管理后端节点

    文章转载自:https://www.cnblogs.com/f-ck-need-u/p/9286922.html 配置后端节点前的说明 为了让ProxySQL能够找到后端的MySQL节点,需要将后端的 ...

  10. Java 基础三、接口与内部类

    1.   在Java程序语言中,接口是对类的一种描述.例如Arrays类中sort方法声明可以对对象进行排序,但前提是对象所属的类必须实现Comparable接口. public interface ...