Bootstrap

js之原型链与继承

目录

1、构造函数的prototype原型修改

2、原型式继承

3、借助构造函数继承

4、寄生式工厂继承 (不推荐使用) 

5、寄生组合式继承 (推荐)


1、构造函数的prototype原型修改

在JavaScript中,用new关键字来调用的函数,称为构造函数,构造函数首字母一般大写

function foo() {}


// 给原型添加数据
foo.prototype = {
 name: 'test',
 age: 18
}

let p1 = new foo()

// 通过Object.defineProperty方式添加constructor
Object.defineProperty(foo.prototype, 'constructor', {
 enumerable:false,
 configurable: true,
 writable: true,
 value: foo
})

2、原型式继承

注意:是原型式继承,不是原型链继承

该方法的原理是创建一个构造函数,构造函数的原型指向对象,然后调用 new 操作符创建实例,并返回这个实例,本质是一个浅拷贝。

let obj = {
 name: 'why',
 age: 18
}

// 原型式继承函数
function createObject (o) {
 let newObj = {}
 Object.setPrototypeOf(newObj, o)
 return newObj
}

let info = createObject(obj)

console.log(info) // 输出 {}
console.log(info.__proto__) // 输出 {name: 'why', age: 18}


// 或者直接用Object.create() 也是一样的效果

let obj = {
 name: 'why',
 age: 18
}

let info = Object.create(obj)

3、借助构造函数继承

 在解决原型中包含引用类型值所带来问题的过程中,开始使用一种叫做借用构造函数(伪造对象/经典继承)的技术。基本思想:在子类型构造函数的内部调用超类型构造函数。

借用构造函数的优势:可以在子类型构造函数中向超类型构造函数传递参数。

function Person(name, age) {
 this.name = name
 this.age = age
}

function Student(name, age) {
 Person.call(this, name, age)
}

let p1 = new Student('test1', 18)

let p2 = new Student('test2', 19)

console.log(p1) // 输出 Student {name: 'test1', age: 18}

console.log(p2) // 输出 Student {name: 'test2', age: 19}

4、寄生式工厂继承 (不推荐使用) 

寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,后再像真的是它做了所有工作一样返回对象。

let personObj = {
 running: function() {
  console.log('running')
  }
}

function createStudent(name) {
 let stu = Object.create(personObj)
 stu.name = name
 stu.studing = function() {
  console.log('studing')
 }
 return stu
}

let stuObj = createStudent('why')

5、寄生组合式继承 (推荐)

通过借用构造函数来继承属性,通过原型链的方式来继承方法,而不需要为子类指定原型而调用父类的构造函数,我们需要拿到的仅仅是父类原型的一个副本。因此可以通过传入子类和父类的构造函数作为参数,首先创建父类原型的一个复本,并为其添加constrcutor,最后赋给子类的原型。这样避免了调用两次父类的构造函数,为其创建多余的属性。

JS的继承方式有很多种,最理想的继承方式是寄生组合式继承。

function Person(name, age, friends) {
 this.name = name
 this.age = age 
 this.friends =friends
}

Person.prototype.running = function() {
 console.log('running')
}

function Student(name, age, friends, son, score) {
 Person.call(this, name, age, son, friends)
 this.son = son
 this.score = score
}

Student.prototype = Object.create(Person.prototype)
// 将stu.constructor.name的指向为Student
Object.defineProperty(Student.prototype, 'constructor', {
  enumerable: false,
  configurable: true,
  writable: true,
  value: Student
})

Student.prototype.studing= function() {
 console.log('studing')
}

let stu = new Student('why', 18, ['kobe'], 111, 100)

console.log(stu)
// 输出
stu.running()
stu.studing()


// 如果是多个需要更改construcotr 可以封装一个工具类函数
// 第一个参数是子参数,第二个参数是要继承的
function inheritPrototype(SubType, SuperType) {  
  SubType.prototype = Object.create(SuperType.prototype)
  // 将stu.constructor.name的指向为Student
  Object.defineProperty(SubType.prototype, 'constructor', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: SubType
  })
}


function Person(name, age, friends) {
 this.name = name
 this.age = age 
 this.friends =friends
}

Person.prototype.running = function() {
 console.log('running')
}

function Student(name, age, friends, son, score) {
 Person.call(this, name, age, son, friends)
 this.son = son
 this.score = score
}

inheritPrototype(Student, Person)

Student.prototype.studing= function() {
 console.log('studing')
}

let stu = new Student('why', 18, ['kobe'], 111, 100)

console.log(stu)
// 输出
stu.running()
stu.studing()

6、原型内容判断方法

let obj = {
  name: 'why',
  age: 18
}

let info = Object.create(obj, {
 address: {
  value: '长沙市',
  enumerable: true
  }
})


// 判断属性是否在自己原型上

// hasOwnProperty方法判断
console.log(info.hasOwnProperty('address')) // 输出 true

console.log(info.hasOwnProperty('name')) // 输出 false

// in 操作符: 不管在当前对象还是原型中返回的都是true
console.log('address' in info) // 输出 true

console.log('name' in info) // 输出 true

hasOwnProperty: 对象是否有某一个属于自己的属性(不是在原型上的属性)

in / for in:判断某个属性是否在某个对象或对象的原型上 

instanceof:用于检测构造函数的prototype,是否出现在某个实例对象的原型链上 

isPrototypeOf:用于检测某个对象,是否出现在某个实例对象的原型链上 ,譬如

function Person() {

}

let p = new Person()

console.log(p instanceof Person) // 输出 true

console.log(Person.prototype.isPrototypeOf(p)) // 输入 true

;