JS —— 对象

5 篇文章 0 订阅

对象

  • 对象的定义:属性的无序集合
  • JS中一切皆对象,原始值也有对应的包装类对象
  • 大致可分为 内置对象 宿主对象 自定义对象

1. 创建自定义对象

同样,有两种方式:字面量创建、构造函数创建

// 字面量(常用)
> let obj1 = {
... name: "JS",
... getName() { return this.name; }
... }
// 构造函数
> let obj2 = new Object();	// {} 空对象
> obj2.name="JS";			// 可以添加属性和方法
> Obj2.getName=function() { return this.name; }

因为JS中一切皆对象,所以引用类型都可为其添加属性和方法:

> let arr = new Array(1,2);		// [ 1, 2 ]
> arr.name = "JS";				// 添加属性和方法
> arr.getName() = function() { return this.name; }
> arr				// [ 1, 2, name: 'JS', getName: [Function] ]
> for( let v in arr) { console.log(v); }	// 添加的属性和方法可遍历
0
1
name
getName

2. 内置对象

如 String Array Function Date RegExp。。。

  • 实际上,内置对象不过是拥有自己特有属性,且在其原型对象上定义了自己的特有方法而已。
    所以,对应实例对象可以共享原型中的方法!
> console.dir(new String());	// 特有属性length
String
  length: 0
  __proto__: String
  [[PrimitiveValue]]: ""
> console.dir([]);				// 特有属性length
  length: 0
  __proto__: Array(0)
  • 原型对象其实都是Object的实例对象
    所以内置对象可以使用Object原型中的方法
(new RegExp()).__proto__ instanceof Object	// true
  • 原型对象的源头:Object原型对象
> console.dir({});
  Object
  __proto__: // Object的原型对象
	constructor: ƒ Object()							// 构造函数
	hasOwnProperty: ƒ hasOwnProperty()				// 判断自有属性
	isPrototypeOf: ƒ isPrototypeOf()				// 判断原型
	propertyIsEnumerable: ƒ propertyIsEnumerable()	// 判断属性的枚举特性
	toLocaleString: ƒ toLocaleString()				// 字符串字面量本地化
	toString: ƒ toString()							// 字符串字面量
	valueOf: ƒ valueOf()
	__defineGetter__: ƒ __defineGetter__()			// 拓展中解释	
	__defineSetter__: ƒ __defineSetter__()
	__lookupGetter__: ƒ __lookupGetter__()
	__lookupSetter__: ƒ __lookupSetter__()
	get __proto__: ƒ __proto__()
	set __proto__: ƒ __proto__()

3. 宿主对象

依赖于具体的JS运行环境,如 浏览器中的全局上下文对象 —— window对象。

对象属性、方法

1. 实例属性

JS中不同特性的对象会预置不同的实例属性:

// 预置属性
> [].length					// 0 可见数组对象天生就有length属性
> "".length					// 0 同理
> {}						// Object实例对象则没有length属性
> [].__proto__ instanceof Object && // 原型对象都是Object的实例
    "".__proto__ instanceof Object;	// true
> let arr = [1,2];
> Object.getOwnPropertyDescriptor(arr, "length");
{value: 2, writable: true, enumerable: true, configurable: true}

// 自定义属性
arr.name = "JS";
Object.getOwnPropertyDescriptor(arr, "name");
{value: "JS", writable: true, enumerable: true, configurable: true}
属性的内部特性
  1. 数据属性
    对象中的每个属性都有属性特性(描述符对象)来记录可进行的操作:
    点语法添加自定义属性时,描述符对象默认为可配置、可枚举、可写!

均为布尔值,value值类型任意!

  • configurable 可配置性
    是否可delete、是否可修改特性、是否可改为访问器属性
  • enumerable 可枚举性
    for-in是否可返回
  • writable 可写性
    value是否可修改
  • value
    属性值

特别注意:

  • 设为不可配置后,则不能再改为可配置了
  • 点语法添加自定义属性时,默认为可配置、可枚举、可写!
  • defineProperty()方法添加自定义属性时,特性默认为 false!

可通过 Object.defineProperty() 方法修改属性的内部特性:

> let obj = new String("abc");
> obj.name = "JS";
// 自定义属性
> Object.getOwnPropertyDescriptor(obj,"name");	// 获取属性的描述符
{ value: 'JS',writable: true,enumerable: true,configurable: true }
// 字符串元素属性
> Object.getOwnPropertyDescriptor(obj,"0");
{value: "a", writable: false, enumerable: true, configurable: false}
// 修改属性的描述符
> Object.defineProperty(obj,"name",{enumerable:false});	// 修改配置性
> Object.getOwnPropertyDescriptor(obj,"name");	// 获取属性的描述符
{ value: 'JS',writable: true,enumerable: false,configurable: true }
> delete obj.name;								// false 不可delete
> Object.defineProperty(obj,"name",{writable:false});	// 修改可写性
> obj.name = "ES";
> obj.name				// 'JS' 不可修改
// 特别注意(严格模式下):
// 不可配置后不能再修改:
Object.defineProperty(obj,"0",{configurable: true});	// 报错
TypeError: Cannot redefine property: 0 at Function.defineProperty
// 点语法添加,默认可写可枚举可配置
> Object.getOwnPropertyDescriptor(obj,"name");	// 获取属性的描述符
{ value: 'JS',writable: true,enumerable: true,configurable: true }
// defineProperty()方法添加,默认为false
> Object.defineProperty(obj, "age",{});
> Object.getOwnPropertyDescriptor(obj,"age");
{value: undefined, writable: false, enumerable: false, configurable: false}

  1. 访问器属性
    重点是 set get 设置和获取函数。

前两个均为布尔值(也是数据属性),后两个默认为undefined!

  • configurable 可配置性
    是否可delete、是否可修改特性、是否可改为数据属性
  • enumerable 可枚举性
    for-in是否可返回
  • get 获取函数
    读取属性时自动调用
  • set 设置函数
    设置属性时自动调用,可修改其他属性

特别注意:

  • get set方法是可选的
  • 只写get方法则属性是只读的
  • 只写set方法则属性是只写的

不可直接定义,必须通过Object.defineProperty()方法定义:

// 实现功能:月份超出向年份进位

> birth = {
    year: 2000,
    month_:1
}
> Object.defineProperty(birth, "month", { // 添加 month 访问器属性
    get() {
        return this.month_;
    },
    set(value) {
        this.month_ = (value-1)%12 + 1;
        let temp = parseInt((value-1)/12);
        if(temp) {
            this.year += temp;
        }
    }
});
> birth.month = 26;
> console.log(birth.year, birth.month);	//  2002 2 自动进位
> Object.getOwnPropertyDescriptor(birth,"month");	// 默认为false
{enumerable: false, configurable: false, get: ƒ, set: ƒ}
> Object.getOwnPropertyNames(birth);// ["year", "month_", "month"]
	month_: 1
	year: 2001
	month: (...)
	get month: ƒ get()
	set month: ƒ set(value)
	__proto__: Object
  • 拓展:
    前面看到的函数:
    __defineGetter__: ƒ __defineGetter__()
    __defineSetter__: ƒ __defineSetter__()
    ES5之前,使用这两个非标准的属性来设置访问器属性,现在已经弃用了。

2. 原型方法

不同类型,JS预置了一些不同原型方法,以便实例对象共享,如Array:

// 数组的原型方法:
concat: ƒ concat()				// 数组连接
copyWithin: ƒ copyWithin()		// 复制数组元素替换
entries: ƒ entries()			// 生成[key,value]迭代器
every: ƒ every()				// 任意性
fill: ƒ fill()					// 填充
filter: ƒ filter()				// 过滤
find: ƒ find()					// 条件查找,返回值
findIndex: ƒ findIndex()		// 条件查找,返回索引
flat: ƒ flat()					// 扁平化,浏览器环境实现了
flatMap: ƒ flatMap()			// 映射后扁平化,浏览器环境实现了
forEach: ƒ forEach()			// 遍历
includes: ƒ includes()			// 判断是否存在
indexOf: ƒ indexOf()			// 返回目标的索引
join: ƒ join()					// 元素拼接为字符串
keys: ƒ keys()					// 生成key的迭代器
lastIndexOf: ƒ lastIndexOf()	// 返回目标的索引,由后向前查找
map: ƒ map()					// 映射
pop: ƒ pop()					// 出栈
push: ƒ push()					// 入栈
reduce: ƒ reduce()				// 归并
reduceRight: ƒ reduceRight()	// 归并,由后向前
reverse: ƒ reverse()			// 数组翻转
shift: ƒ shift()				// 出队
slice: ƒ slice()				// 获取子串
some: ƒ some()					// 存在性
sort: ƒ sort()					// 排序
splice: ƒ splice()				// 可删除、添加、替换元素
toLocaleString: ƒ toLocaleString()	// 字符串字面量本地化
toString: ƒ toString()			// 字符串字面量化
unshift: ƒ unshift()			// 入队
values: ƒ values()				// 生成value迭代器
Symbol(Symbol.iterator): ƒ values()
Symbol(Symbol.unscopables): {copyWithin: true, entries: true, fill: true, find: true, findIndex: true,}

Array专题:https://blog.csdn.net/qq_45668041/article/details/115706018

不同类型的原型对象共有的部分:

// 内置类型的原型对象都是Object实例,自然由Object构造函数创建出来的
length: 0		 // 创建实例时传入的参数个数,默认使用Object()创建
__proto__: Object// 指向原型对象的原型

3. Object原型方法

> console.dir({});
  Object
  __proto__: // Object的原型对象
	constructor: ƒ Object()							// 构造函数
	hasOwnProperty: ƒ hasOwnProperty()				// 判断自有属性
	isPrototypeOf: ƒ isPrototypeOf()				// 判断原型
	propertyIsEnumerable: ƒ propertyIsEnumerable()	// 判断属性的枚举特性
	toLocaleString: ƒ toLocaleString()				// 字符串字面量本地化
	toString: ƒ toString()							// 字符串字面量
	valueOf: ƒ valueOf()
	__defineGetter__: ƒ __defineGetter__()		// 访问器属性(非标准)
	__defineSetter__: ƒ __defineSetter__()
	__lookupGetter__: ƒ __lookupGetter__()
	__lookupSetter__: ƒ __lookupSetter__()
	get __proto__: ƒ __proto__()
	set __proto__: ƒ __proto__()

那么,前面用到的方法哪来的呢?
其实还是Object构造函数的实例属性,只是不可枚举!

// getOwnPropertyDescriptor是不可枚举属性
> Object.getOwnPropertyDescriptor(Object, "getOwnPropertyDescriptor");
{writable: true, enumerable: false, configurable: true, value: ƒ}
// 所以,下面方法不能判断是否为自身属性:
> Object.hasOwnProperty(Object, "getOwnPropertyDescriptor");// false
// 应该通过下面的方法查看所有的自身属性:
> Object.getOwnPropertyNames(Object);
  ["length", "name", "prototype", "assign", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", "getOwnPropertyNames", "getOwnPropertySymbols", "is", "preventExtensions", "seal", "create", "defineProperties", "defineProperty", "freeze", "getPrototypeOf", "setPrototypeOf", "isExtensible", "isFrozen", "isSealed", "keys", "entries", "fromEntries", "values"]

下图可能有助于理解构造函数和原型对象的关系:
在这里插入图片描述

对象解构

ES6新语法,null undefined不支持对象解构!

  • 解构的优点:
    可快速取出对象中的属性!
// 解构
> let person = {
    name: "JS",
    age:18
  };
// 部分解构
> let { name: personName, age: personAge } = person;
> console.log(personName, personAge);	// JS 18
// 简写形式
> let { name,age } = person;
> console.log(name, age);	// JS 18
// 嵌套解构
> let body = {
	name: "JS",
	job: {
    title: "Dev",
	},
  };
> let { job:{title:Title} } = body;
> console.log(Title);		// Dev
// 参数上下文匹配:不影响arguments对象
> function printPerson(foo,{ name, age }, bar) {
	console.log( arguments, name, age );
  }
> printPerson('1st',person,'2nd');
  [Arguments] { '0': '1st', '1': { name: 'JS', age: 18 }, '2': '2nd' }
  JS 18

对象序列化

用于和后台进行数据传递,为后台提供JSON字符串。

> let obj = {
	name: "JS",
	age: 18
  }
> let str = JSON.stringify(obj);	// '{"name":"JS","age":18}'
> JSON.parse(str);					// { name: 'JS', age: 18 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值