1,理解对象
通过对象字面量的方式,创建一个对象,为它添加属性和方法:
var obj = { a: 1, b:2, sayA(){ console.log(this.a)}}
1,属性类型:
数据属性 :
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。有四个特性
configurable enumerable writable value : 分为的意思为:是否能通过delete删除(能否修改特性)、是否能通过for-in循环、是否能修改属性的值、包含这个属性的值
通过对象字面量创建的对象,这四个特性都为true
要修改属性的特性,必须使用Object.defineProperty()方法,这个方法接收三个参数,对象,属性名和 特性名称。
访问器属性:
访问器属性不包含数据值,它们包含一对getter和setter函数,在读取访问器属性时,会调用getter,此函数会返回有效的值;在写入访问器属性时,会调用setter并传入新值,这个函数负责处理数据
Configurable enumerable : 同数据属性
get: 读取属性时调用,
set: 写入属性时调用
在属性名的前面加_ 表示 只能通过对象的方法访问的属性。
定义多个属性:
Object.defineProperties () :
读取属性的特性:
Object.getOwnPropertyDescriptor () : 第一个参数为 指定的对象,第二个参数为要读取描述符的属性名;
2,创建对象
1,工厂模式
2,构造函数模式
要创建实例,必须使用new操作符。以这种方式调用构造函数会经历以下四个步骤: 1, 创建一个新对象; 2, 将构造函数的this指向新对象; 3,执行构造函数中的代码; 4, 返回新对象。
构造函数的问题是: 每个方法都要在每个实例上重新创建一遍,因为有this在,根本不用在执行代码前就把函数绑定到特定的对象上。
3,原型模式
每个函数都有一个prototype属性,这个指针指向该函数的原型对象。使用原型对象可以让所有实例共享它所包含的属性和方法
可以通过实例去访问保存在原型中的值,但不能通过对象实例重写原型中的值。 调用Object.hasOwnProperty()可以检查一个属性是存在实例中还是存在原型中。
for in循环的是所有能够通过对象访问的、可枚举的属性。既包含存在于实例的也包含存在于原型的属性。
Object.keys() : 获取对象自身所有的可枚举的属性值,不包括原型的属性,返回属性组成的数组。
Object.getOwnPropertyNames() : 获取对象自身的所有属性,包括不可枚举的,不包括原型的。 返回组成的数组。
原型对象的问题是: 所有属性都是被实例共享的,那么如果有一个引用类型的属性,如果一个实例修改了,那么所有实例的这个属性都会修改。
4,组合使用构造函数和原型对象
实例属性在构造函数中定义,方法在原型对象中定义。
5,动态原型模式
通过构造函数来初始化原型,通过判断 原型中没有,再添加。
6,寄生构造函数模式
在函数中new一个对象,将参数放入这个对象,返回这个对象。 这个对象和构造函数、构造函数的原型没有任何关系。
7,稳妥构造函数模式
适合在安全的环境,不使用this,不使用new,返回一个对象,只能通过对外的接口来访问其中的原始数据成员。 这个对象和构造函数
3,继承
1,原型链
function Person(){}
function Men () {}
Men.prototype = new Person()
Men.prototype.constructor = Men
Men的实例查找一个属性的时候,会先在实例上查找,如果没有的话,就在实例的原型,也就是Men.prototype上查找,如果没有,则会继续沿着原型链向上,在Person的prototype上查找,如果没有,则继续向上,在Object.prototype上查找。
确定原型和实例的关系
1,使用instanceof : 只要实例与原型链中出现过的构造函数,都会返回true
2,使用 isPrototypeOf() : 只要是原型链中出现过的原型,都会返回true
谨慎的定义方法
使用原型链继承方法的时候,不能使用对象字面量创建原型方法,因为这样会重写原型链。
原型链的问题
因为在通过原型继承的时候,原型会变成另一个类型的实例,那么,原先的实例属性就变成了现在的原型属性了。 如果修改的话,会影响所有实例。
2,借用构造函数
子类的构造函数中, 使用 父类构造函数.call(this, ...args),此方法可以在子类构造函数中向超类构造函数传递参数。
这种方法的问题是: 超类的原型 对子类来说是不可见的。
3,组合继承
将原型链和借用构造函数的技术组合。
function Person (name) { this.name = name}
Person.prototype.sayName = function (){ console.log(this.name) }
function Men (name) { Person.call(this, name) }
Men.prototype = new Person()
Men.prototype.constructor = Men
4,原型式继承
function Person(o) { function F(){}; F.prototype = o; return new F() }
es5通过Object.create() 模拟了原型式继承。只是想让一个对象与另一个对象保持类似的话,这种方法时完全可以的。
注意:包含的引用类型的属性 始终都会共享相应的值。
5,寄生式继承
通过Object.create(obj)来创建一个传入参数obj的模板,然后在这个模板上加新方法,返回这个模板对象。
6,寄生组合式继承
在组合继承的时候,会调用两次超类的构造函数, 在给子类的原型赋值 给 超类的实例对象时,这一步完全可以换成 Object.create(超类原型),这样就只用调用一次超类的构造函数了。
小结: es支持面向对象编程。对象在代码执行过程中创建和曾强,所以具有动态性而非严格定义的实体。可以采用以下的模式创建对象:
1,工厂模式 2,构造函数模式 3,原型模式
js主要是通过原型链进行继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。这样子类型就能访问超类型的所有属性和方法。