原型、原型链、继承

306 阅读3分钟

构造函数

  • 构造函数一般函数名大写
  • 通过new关键字调用
  • 箭头函数不可以做为构造函数

看个例子:

function Person(name, age, job) {
  this.name = name
  this.age = age
  this.job = job
  this.sayName = function() {
    alert(this.name)
  }
}
var person1 = new Person('Zaxlct', 28, 'Engineer')
var person2 = new Person('Mick', 23, 'Doctor')

构造函数内部原理

1.在函数体最前面隐式加上

this = { 
    __proto__:Preson.prototype (隐式属性__proto__,它指的是构造函数构造出对象的原型)
}

2.执行this.xx = xx

3.隐式的返回this 

prototype

每一个函数都有一个属性叫prototype(原型),它其实指向的是一个对象,这个对象有两个隐式属性constructor和__proto__,我们称这个对象叫原型对象,它的好处是用于扩展属性和方法。

看个例子:

Preson.prototype.name = 'wang'
function Preson() {

}

let Preson1 = new Preson()
let Preson2 = new Preson()
console.log(Preson1.name) // wang 
console.log(Preson2.name) // wang

constructor

每个原型都有一个隐式属性construetor,它指向的是该实例对象的构造函数

Preson.prototype.constructor = function Preson() {}

proto

每一个js对象(除null)都有一个隐式属性叫__proto__,它指向的是该对象的原型

Preson.prototype.__proto__ = Object

Preson.prototype.__proto__ == Object.prototype

原型链

当查找实例对象的属性或方法时,如果对象本身没有,会向该对象原型查找,如果原型还没有,就向原型的原型查找,直到原型顶端,如果原型顶端还没有就返回undefined,它们之间是通过__proto__进行连接。

看个例子

Preson.prototype.name = 'wang'
function Preson() {

}

let preson = new Preson()
preson.name = 'zhang'

console.log(preson.name) // zhang

delete preson.name 

console.log(preson.name) // wang

不是所有的对象最终都继承于Object.prototype,列如 Object.create(null)

继承

通俗的讲就是儿子能使用父辈的东西(东西指的是属性和方法)

原型链实现继承

原理;prototype的所有属性和方法可供该实例对象使用


function Parent() {

  this.name = 'Loner'
  
  this.sayHi = function() {
    console.log('hello' + this.name)
  }
  
}

let parent = new Parent()

function Child() {

}

Child.prototype = parent

let child = new Child()

child.sayHi() // helloLoner
parent.sayHi() // helloLoner

call和apll实现继承

原理:通过改变this指向实现继承,call和aplly区别在于传递的参数不一样,call是一个一个的传,apply第二个参数必须是一个数组

function Parent(name) {
  this.name = name
  this.sayHi = function() {
    console.log('hello' + this.name)
  }
}


function Child(name) {
  Parent.call(this,name)
  this.hi = function () {
    console.log('hello' + this.name)
  }  
}

let child = new Child('老王')

child.sayHi() // heiio 老王
child.hi() // heiio 老王

圣杯模式实现继承

原理:核心点就是利用一个中间层做转换

var inherit = (function () { 
  var F = function() {};
  return function(Target,Origin) {
    F.prototype = Origin.prototype;
    Target.prototype = new F();
    Target.prototype.constuctor = Target;
    // 可用于查看最终继承于谁
    Target.prototype._suber = Origin.prototype; 
  }
}())

Father.prototype.lastName = 'Loner'
function Father() {

}

function Son() {
  
}

inherit(Son,Father)

let son = new Son();
let father = new Father();
console.log(son)

extends关键字实现继承

注意: 子类的constructor方法没有调用super之前,就使用this关键字会报错。原因是:子类Children的构造函数之中的super(),代表调用父类Parent的构造函数。

super虽然代表了父类Parent的构造函数,但是返回的是子类Children的实例,即super内部的this指的是Children,因此super()在这里相当于Parent.prototype.constructor.call(this);

class Parent {  
  constructor(name,age) {
    this.name = name;
    this.age = age
  }
  sayHi() {
    console.log(this.name)
  }
}

class children extends Parent {
  constructor(num) {
    // super() 相当于Parent.prototype.constructor.call(this)
    super('Loner','20')  //super必须在前,否则代码报错
    this.num = num
  }
  hi() {
    console.log(this.num) 
  }
}

let c = new children(4)

c.hi() // 4
c.sayHi() // Loner
console.log(c.age) // 20