详解 对象 原型 原型链 继承

做前端的同学应该对红宝书高级程序设计很熟悉,堪称前端人员必读经典,也是我入行买的第一本书。现在总结一下关于对象 原型 原型链 继承 的一些内容

1. 创建对象

  • 1) 工厂模式

function creat(name,age){
    var obj = new Object()
    obj.name = name
    obj.age = age
    obj.getAge = function(){
        console.log(this.age)
    }
    return obj
}

var studentA = creat('xiaohong',18)
studentA.getAge() // 18
console.log(studentA.name) // xiaohong
复制代码

每次调用 creat函数都会返回一个对象 这个对象包含 name age 属性 和一个 getAge方法
缺点:没解决对象识别问题

  • 2) 构造函数模式

function Creat(name,age){
    this.name = name
    this.age = age
    this.getAge = function(){
        console.log(this.age)
    }
}

var studentA = new Creat('xiaohong',18)
studentA.getAge() // 18
console.log(studentA.name) // xiaohong
复制代码

构造函数的首字母为大写 要创建构造函数的实例,必须使用关键字 new 操作符
new操作符创建实例的过程是面试常考题!!!可以重点看下

a.创建一个新对象

b.将构造函数的作用域赋值给新对象(修改this指向)

c.执行构造函数(为新对象添加对象和方法)

d.返回新对象

studentA是Creat的一个实例,

这个实例中包含一个 constructor属性 , constructor属性指向Person.

这个实例中包含一个 constructor属性 , constructor属性指向Person.

这个实例中包含一个 constructor属性 , constructor属性指向Person.

console.log(studentA.constructor == Creat) //true
复制代码

instanceof 操作符可以 检测对象类型 studentA 是 Creat的实例 也是Object的实例

console.log(studentA instanceof Creat) //true
console.log(studentA instanceof Object) //true
复制代码

构造函数的问题 每个方法都要在每个实例上创建一遍。解决方案

function Creat(name,age){
    this.name = name
    this.age = age
    this.getAge = getAge
}

function getAge (){
    console.log(this.age)
}
复制代码

每个实例都共享了全局对象中的方法 ,但是如果定义多个方法就要定义很多全局函数

3) 原型模式

function Person(){}
Person.prototype.age = '18'
Person.prototype.name = 'xiaohong'
Person.prototype.getAge = function(){
    console.log(this.age)
}
var studentA = new Person()
studentA.getAge() //18
复制代码

无论什么时候创建一个函数 该函数的 prototype属性 指向函数的原型对象。所有的原型对象都会获得一个constructor属性 这个属性包含一个指向 prototype属性所在函数的指针

image.png
如果实例中新添加的属性和原型上的属性重名,那么原型上的属性就会被屏蔽(只屏蔽不修改)

function Person(){}
Person.prototype.age = '18'
Person.prototype.name = 'xiaohong'
Person.prototype.getAge = function(){
    console.log(this.age)
}
var studentA = new Person()
studentA.name='lucy'
console.log(studentA.hasOwnProperty('name')) //true
console.log('name' in studentA) //true
console.log('job' in studentA)  //false
复制代码

hasOwnProperty()方法 可以判断属性是来自实例 还是来自原型

in 操作符 只要能通过对象能够访问到的属性都返回 true

所以通过 hasOwnProperty() 和 in 就可以确定该属性是来自 原型还是实例

缺点:所有实例在默认情况下都有相同的属性和方法 如果实例修改了原型对象的属性值 其他实例也被修改

4)组合使用构造函数和原型模式

创建自定义类型最常见的方法就是 使用构造函数创建属性 , 原型模式定义方法和共享的属性

function Person(name,age){
    this.name = name
    this.age = age
}
Person.prototype={
    construtor:Person,
    getAge:function(){
        console.log(this.age)
    }
}
var studentA = new Person()
studentA.name='lucy'
console.log(studentA.name) //lucy
复制代码

5) 寄生构造函数

这个模式其实和工厂模式一样。但是不能用instanceof 来定义类型 所以一般不用这种模式。

function Person(name,age){
    var o = new Object()
    o.name = name;
    o.age = age;
    o.sayAge = function(){
        console.log(this.age)
    }
    return o
}
var studentA = new Person('lucy','18')
studentA.sayAge()//18
复制代码

2.原型链

  • 原型链-是实现继承的主要方法

利用原型对象让一个引用类型继承另外一个引用类型的属性和方法

function Father(){
    this.property=true
}
Father.prototype.sayFatherName = function(){
    return this.property
}

function Child(){
    this.subproperty=false
}
Child.prototype = new Father()
Child.prototype.sayChildName = function(){
    return this.subproperty
}
var child1 = new Child()
console.log(child1.sayFatherName()) //true
复制代码

注意: 子类型添加方法要放在替换类型之后

给子类添加方法 不可以使用字面量!!!会导致继承失效!!!

原型练的继承是通过创建Father的实例

instanceof 可以确定原型和实例的关系

console.log(child1 instanceof Child ) //true
console.log(child1 instanceof Father ) //true
console.log(child1 instanceof Object ) //true
复制代码
  • 借用构造函数继承 借用 call apply

function Father(){
    this.color=['red','green']
}

function Child(){
    Father.call(this)
}
var child1 = new Child()
var child2 = new Child()
child1.color.push('blue')
console.log('child1:',child1.color) //[ 'red', 'green', 'blue' ]
console.log('child2:',child2.color) //[ 'red', 'green' ]
复制代码

缺点:方法都是在构造函数中定义的 无法复用

  • 组合继承

function father(name,age){
    this.name = name
}
Father.prototype.sayName = function(){
    console.log(this.name)
}

function Child(name,age){
    Father.call(this,name) //第二次调用 Father
    this.age = age
}
Child.prototype = new Father() //第一次调用 Father
Child.prototype.constructor = Child
Child.prototype.sayAge = function(){
    console.log(this.age)
}

var child1 = new Child('Lucy','18')
child1.sayName()//Lucy
child1.sayAge()//18
复制代码

组合继承避免了原型链和构造函数继承的缺点 是最常用的继承模式

  • 寄生组合式继承

function inheritPrototype(subtype,supertype){
    var prototype = Object(supertype.prototype) //创建对象
    prototype.constructor = subtype //增强对象
    subtype.prototype = prototype  //指定对象

}

function Father(name,age){
    this.name = name
}
Father.prototype.sayName = function(){
    console.log(this.name)
}

function Child(name,age){
    Father.call(this,name)
    this.age = age
}
inheritPrototype(Child,Father)

Child.prototype.sayAge = function(){
    console.log(this.age)
}

var child1 = new Child('Lucy','18')
child1.sayName()//Lucy
child1.sayAge()//18
复制代码
总结

JavaScript中主要通过 原型链实现继承。

原型链的构建是通过将一个类型实例 赋值给另外一个构造函数的原型 而实现的。

使用最多的继承方式是组合继承,通过构造函数继承实例实例属性 使用原型链继承共享的属性和方法。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享