理解js对象
首先理解对象是什么?类似其他语言中类的概念,作用是可以批量声明相同属性和方法, 特征属性序列的集合
->
既然对象是属性集合,那需要了解下对象的属性
属性为两类 1,数据属性 2,访问器属性
数据属性由四个特性: 1,Configourable(是否可修改配置,修改后无法恢复) 2,Enumerable(是否可枚举)3,Writable(是否可读)4,Value(value,默认Undefine,这就是我们congsole.log不存在会undefine的原因)
我们可以通过Object.defineProperty(obj,arg,{}) 来修改特性 ,查看属性特性Object.getOwnPropertyDescriptor(obj,arg)
访问器属性有四个特征:1,Configourable 2,get(获取值) 3,set(更新值) 4,Enumerable
理解getter,setter
let obj = {
name: 'TEST',
_year: 2000
}
//提示:_year 前面 的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性
Object.defineProperty(obj,'year',{
get: function () {
return this._year
}
set: function (newValue) { if (newValue === 2001) {
this._year = newValue
this.name = 'tank'
}
}})
obj.year = 2001
console.log(obj.name)
了解对象属性后,接着创建对象
最初使用过字面量创建对象,和直接new一个对象那个,如果批量引用相同属性和方法就不适用了
这里我们引入第一个模式,工厂模式,顾名思义通过类似工厂方式定义相同属性和方法
在一个函数内new一个对象,并增加属性和方法,最后return返回这个对象
function person (name, age) {
var p = new Object()
p.name = name
p.age = age
p.say = function () { console.log(p.name) }
return p
}
这样就创建好一个工厂模式
var p1 = person('TEST',19)
工厂模式有个缺点,不知道对象来自哪里 instanceof
->
这里我们可以使用 构造函数模式
fucntion Person (name,age) {
this.name = name
this.age = age
this.sayName = function () { console.log(this.nam) }
}
var p = new Person('test',12)
// this指向实例化对象
// 构造函数内部 首字母大写 ,任何函数通过new操作符调用都可以是构造函数,如果没有,都是普通函数这了要知道,创建构造函数都会产生一个原型对象,都包含一个构造属性,指向构造函数(construstor)本身
显示使用时,不同实例需要的属性和方法不同,公共部分可以放在原型对象中,原型特性在于共享,每个实例都能访问到
如下例子
function Person() {}
Person.prototype.name = 'tank' // 发现了吗,原型必须有一个默认值
Person.prototype.age = 10
Person.prototype.sayName = fucntion () { console.log(this.name) }
var p = new Person()这样我们得到了共享的name,age,一个方法
原型的问题在于1,无法传参 2,最大的问题也是源于它共享的特性,在使用引用类型时,比如一个数组,在一个实话对象中push一个字段时,这是我们不想看到的
-》
改进... 组合使用构造函数模式和原型模式
function Person (name, color) {
this.name = name
this.color = color
}
Person.prototype.sayName = function () {}
Person.prototype.class = 17
Person.school = 'wuan10zhong'var p = new Person('tank', ['#fff','#fcfcfc'])
这样我们获得了通用的class,school,sayName方法,也可以自定义名字,颜色字段
其他
动态原型模式,寄生构造模式,稳妥构造模式自行脑补...
在常见对象的过程原型链已经产生
创建构造函数时,会生成一个原型对象,并默认包含一个构造函数属性,指向构造函数,在创建原型时注意如果使用字面量方式创建,相当于重写了原型对象,为保持和之前一直需要prototype.coustrustor = construstorFunction, 实例化后,实例对象指向原型对象,如果将一个实例对象等于一个实例对象,会发生什么呢?原型链产生....
接着写写继承....
---分割线---
继承
原型链继承
1, 理解原型链
ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。
function SurpeType () {
this.property = true
}
SurpeType.prototype.getSuperValue = function () { return this.property }
fucntion SubType () {}
SubType.prototype = new SurpeType()
var p = new SubType()
// 原型链继承和创建原型对象由相同问题,不能传参,且引用类型问题 而且new SurpeType重写了原型对象
// p 指向SubType原型,SubType原型指向SuperType原型,脑补原型链(所有原型最后指向的是Object.prototype)
2,确定原型和实例关系
使用instanceof,isPrototypeof 来确定原型和实例的关系
实例 instancof Object/coustrustorFunction // true
Object.prototype.isPrototype(实例) // trueisPrototypeof:只要原型出现的原型,都可以说改原型链派生的实例
instanceof: 测试实例与原型链中出现过的构造函数,则返回true
3,谨慎定义方法
这里主要说了方法覆盖,子继承父原型后,如果修改父方法,引用时按修改方法走,原父方法不变,你看乱不乱,所以不用了吧....
4,原型链问题
原型链继承缺点:1,无法传参 2,引用类型共享问题
借用构造函数继承,使用.call() 方法获取上级属性
这里主要知识点就是使用call()来实现继承父属性
function School (name,address,color) {
name: this.name,
address: this.address,
collor: color
}
function Class () {
School.call(this, '十中', '人民路29号', ['#898989','#cccccc'])
}
var c1 = new Class()
缺点:方法无法复用的问题(和创建方法类似)
组合继承,借用构造函数和原型继承
组合继承,结合原型链和构造函数的优点实现
function School (name,address,color) {
name: this.name,
address: this.address,
collor: color
}
School.prototype.sing = function () { console.log('sing') }function Class (name,address,color) {
School.call(this, name,address,color)
}
Class.prototype = new School()
// 这里注意,原型被重写了,需要重新指向构造函数
Class.prototype.construstor = Class
var c2 = new Class('十中','人民路20号',['#cccccc','#eeeeee'])