js对象理解,创建,继承

135 阅读5分钟

理解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(实例) // true

isPrototypeof:只要原型出现的原型,都可以说改原型链派生的实例

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'])