属性的类型:
js使用一些内部特性来描述属性的特征,但是不能直接访问。
属性分两种:数据属性 和 访问器属性
1.数据属性
数据属性包含一个保存数据值的位置。
数据属性有4个特性描述它的行为:
- [[Configurable]] 表示属性是否可以通过 delete 删除并重新定义,是否可以修改它的特性,以及是否可以把它改为访问器属性。
- [[Enumerable]] 表示属性是否可以通过 for-in 循环返回。
- [[Writeable]] 表示属性的值是否可以被修改。
- [[Value]] 包含属性实际的值。
要修改属性的默认特性,需要使用Object.defineProperty()。在调用 Object.defineProperty()时,configurable、enumerable 和 writable 的值如果不指定,会都默认为 false。
2.访问器属性
包含一个getter 和一个setter函数,必须使用 Object.defineProperty()来定义。
- [[Get]]:获取函数,在读取属性时调用。默认值为 undefined。
- [[Set]]:设置函数,在写入属性时调用。默认值为 undefined。
读取属性的特性
Object.getOwnPropertyDescriptor() 获得指定属性的属性描述符。
let book = {}; Object.defineProperties(book,{ year_:{ value:2017, }, edition:{ value:1 }, year:{ get:function(){ return this.year_; }, set:function(newValue){ if(newValue>2017){ this.year_ = newValue; this.edition += newValue - 2017; } } } }) let descriptor = Object.getOwnPropertyDescriptor(book,'year_'); console.log('descriptor.value',descriptor.value); // 2017 console.log('descriptor.configurable',descriptor.configurable); // false console.log('descriptor.enumerable',descriptor.enumerable); // false console.log('descriptor.writable',descriptor.writable); // false let descriptor2 = Object.getOwnPropertyDescriptor(book,'year'); console.log('descriptor2.value',descriptor2.value); //undefined console.log('typeof descriptor2.get',typeof descriptor2.get); // function
合并对象:
ES6 :Object.assign() —— 将源对象中 可枚举属性(Object.propertyIsEnumerable() 返回true) 和 自有属性 (Object.hasOwnProperty()返回true)复制到目标对象。
对象解构:
let person = { name:'ZY', age:25 } let {name,age} = person; console.log(name,age); let {name:personName,age:personAge} = person; console.log(personName,personAge); let { job } = person; console.log(job); // 如果没有定义就是undefined let { job='teacher' } = person; console.log(job); // 'teacher' 可以设定默认值 let { _ } = null; // TypeError null和undefined不能解构 let { _ } = undefined; // TypeError
创建对象:
构造函数模式:
new ,使用new方式调用构造函数会执行以下操作:
- 创建一个新对象
- 将新对象内部的prototype指向构造函数的prototype属性
- 构造函数内部的this指向这个新对象。
- 如果构造函数返回非空对象,则返回该对象,否则,返回刚创建的对象。
1.构造函数 也是函数。 任何函数只要使用new调用就是构造函数。
2.构造函数的问题:
原型模式:
每个函数都会创建一个prototype属性,这个属性是一个对象。包含应该由特定引用类型的实例 共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型。
hasOwnProperty() :用于确定属性是在实例上还是原型上(继承自Object)
如果属性是存在于对象实例上,返回true
原型和in操作符:
in操作符:
- 单独使用: 判断是否可以通过对象访问指定属性。 无论属性是在实例上还是原型上。(可以通过原型链查找)
所以in和hasOwenProperty()属性可以用于判断属性是在原型上还是实例上。
- for-in: 可以通过对象访问且可被枚举的属性 。包括实例属性和原型属性。
Obejct.keys():可获得对象上所有可枚举的 实例属性。
Object.getOwnPropertyNames() :可以获得所有实例属性,无论可否枚举。
Object.getOwnPropertySymbols():可以获取使用symbol命名的实例属性。
属性枚举顺序:
Object.keys() 和 for-in 枚举顺序不确定,取决于JS引擎。
Object.getOwenPropertyNames()和 Object.getOwenPropertySymbols() 顺序:先按照升序枚举数值键,然后以插入顺序枚举字符串和符号键。
对象的迭代:
Object.values() 返回对象值的数组。
Object.entries() 返回键值对的数组。
重写对象原型:
要注意constructor属性。
继承:
一般继承分为 接口继承 和 实现继承。
JS中只有实现继承,主要是通过原型链实现的。
每个构造函数都有一个原型对象,原型有 一个属性指回构造函数,而实例有一个内部指针指向原型。如果原型是另一个类型的实例呢?那就意味 着这个原型本身有一个内部指针指向另一个原型,相应地另一个原型也有一个指针指向另一个构造函 数。这样就在实例和原型之间构造了一条原型链。这就是原型链的基本构想。
原型与实例的关系:
- instanceof 操作符 :如果一个实例的原型链中出现过相应的构造函数,那么返回true
2. isPrototypeOf()
继承: