原型和继承

原型和继承

1、原型

说到原型以前,先复习一下对象建立方式:app

1. 使用对象字面量的形式建立 (最简单)

<script>

  var obj = { a: 1}
  obj.b = 2
  console.log(obj)

</script>

2. 使用工厂函数的方式

<script>

  function CreatePerson (name, age) {
    var obj = new Object ()
    obj.name = name
    obj.age = age
    obj.sayHi = function () {
      console.log('哈喽')
    }
    return obj
  }
  var person1 = CreatePerson('张三', 18)
  var person2 = CreatePerson('李四', 20)

</script>

3. 使用构造函数的方式(对工厂函数的改进)

<script>

  function Person (name, age) {
    this.name = name
    this.age = age
    this.sayHi = function () {
      console.log('哈喽')
    }
  }
  var person1 = new Person('张三',18)
  var person2 = new Person('李四',20)

</script>
  • 用new操做符调用函数时,会自动执行下面的操做函数

    • 建立(或构造)一个新的对象
    • 这个新对象会执行prototype链接
    • 这个新对象会绑定到函数调用的this
    • 若是函数没有返回其余对象, 那么new表达式中的函数调用自动返回这个新对象
//咱们来举个例子
var Foo() {
  //这是一个普通函数
}
Foo() //普通函数调用
var a = new Foo()//在普通调用前加一个new关键字后,这个调用就变成了构造函数调用
  • new会劫持全部普通函数,并用构造函数的形式调用它优化

    var a = new Foo() 这句话的执行机制: Foo是一个普通函数,在使用new调用时,它就会构造一个对象,而且赋值给athis

  • 简单点来讲 js中的 构造函数 :全部带new的函数调用
  • 用new的方法来调用Foo会产生一个新对象a,这个新对象的内部连接__proto__会关联到Foo的原型对象上
    a.__proto__ == Foo.prototypeprototype

4. 使用原型的方式

  • 原型的初步模式
<script>
  function Person () { }

  Person.prototype.name = '张三'
  Person.prototype.age = 18
  Person.prototype.sayHi = function () {
      console.log('哈喽')
    }

  var person1 = new Person()
  var person2 = new Person()
</script>
  • 优势:原型中全部的属性和方法均可以被实例对象共享
  • 缺点:全部的实例对象都公用一套原型和方法,没有差别化,不能修改
咱们来了解一下实例对象、构造函数和原型之间的联系

咱们来了解一下实例对象、构造函数和原型之间的联系

  • 优化模式(原型重构)
    上面例子,每次添加一个属性和方法,就要从新写一遍,比较繁琐,如今把这些属性和方法都放入一个对象中,再赋值给Person的原型
<<script>

  function Person () { }

  Person.prototype = {
    name: '张三',
    age: 18,
    sayHi: unction () {
      console.log('哈喽')
    }
  }

  var person1 = new Person()
  var person2 = new Person()

  console.log(person1.constructor == Person) // false
  console.log(person1.constructor == Object) // true

</script>
  • js 中全部的对象都有一个特殊的内置属性[[prototype]] ,这个属性其实就是用来对其余对象的引用
  • 这种写方法改变了原型内部的constructor指针的属性了 ,再也不指向Person函数了,若是这个指针很重要,那么能够手动设置
<<script>

  function Person () { }

  Person.prototype = {
    constructor:Person,
    name: '张三',
    age: 18,
    sayHi: unction () {
      console.log('哈喽')
    }
  }

  var person1 = new Person()
  var person2 = new Person()

  console.log(person1.constructor == Person) // true
  console.log(person1.constructor == Object) //false

</script>
若是要访问对象中的属性,咱们要通过哪些机制呢?
<script>

  var obj = {
    a: 2
  }

  console.log(obj.a) // 2

</script>

总结:prototype 的机制

prototype机制就是存在于对象中的一个内部连接,它会引用其余对象。指针

这个连接的做用就是: 若是在对象上没有找到须要的属性或者方法,引擎就会在prototype关联的对象上进行查找。若是在后者的对象中没有找到这个属性和方法,引擎就会继续查找他的prototype,以此内推,若是没有找到,就会返回underfind。
这就是所谓的原型链。(有点像嵌套的做用域链)code


2、继承

构造函数就是初始化一个实例对象,对象的prototype属性是继承一个实例对象。对象

继承的方式:

1. 经过原型的方式继承

<script>
  function Bird(legNum, wingNum) {
    this.leg = legNum;
    this.wing = wingNum;
  }
  Bird.prototype.appearance = function () {
    console.log('鸟类都有漂亮的羽毛')
  }
  function Swan (beh,legNum,wingNum) {
    this.behaviour =  beh;
  }
  Swan.prototype = new Bird(2,2,);// 继承了Bird中的属性和方法,可是不能经过传参修改这些值

  Swan.prototype.story = function () {
    console.log('是由丑小鸭变成的');
  }
   // 白天鹅
  var whiteSwan = new Swan('会游泳')
  console.log(whiteSwan)
  whiteSwan.appearance() // 鸟类都有漂亮的羽毛
  whiteSwan.story() // 是由丑小鸭变成的
</script>
  • 优势:全部的属性和方法都可以进行继承
  • 缺点:若是继承了属性,属性值在后期没法修改

2. 使用call()方法调用实现继承

<script>
  function Person (name, age) {
  this.name = name;
  this.age = age;
  }
  Person.prototype.behaviour = function () {
    console.log('你们好,我是一类人')
  }


  function Man(name, age, gender) {
    Person.call(this, name ,age);
    this.gender = gender;
  }
  //能够建立多个实例对象
  var man1 = new Man('张三', 18, '男')
  var man2 = new Man('李四', 20, '女')
  //可是 不能调用原型中的属性和方法
  console.log(man1)
  console.log(man2)
  man1.behaviour()//会报错,这种方法继承不到Person函数中原型中的属性方法
</script>

call(this, 参数1 , 参数2...)继承

  • 使用call方法调用中的参数this 把this指向了调用者
  • 优势:能够继承全部在构造函数体中书写的属性,而且能够进行传参
  • 缺点: 没法继承原型中的属性和方法

3. 组合方式继承(使用call和原型的方式组合继承)

  • call方法:继承构造函数体中的属性,并能够传参修改
  • 原型方式:能够继承原型链中的属性ip

  • 看实例

<script>
 // 组合继承
 function Person (name, age) {
    this.name = name;
    this.age = age;
  }
  //Person的原型
  Person.prototype.behaviour = function () {
    console.log('你们好,我是一类人')
  }

  //console.log(Person())//underfined

  //Man 的构造函数
  function Man(name, age, gender) {
    //call调用的方法进行继承,这个方法改变了Man这个构造函数内部的指向(即constructor指针)
    Person.call(this, name ,age);//第二次调用Person
    this.gender = gender;
  }
  //这里的经过new建立了一个实例对象,并把这个实例对象赋值给了Man的原型对象, 因此改变了 Man原型对象的内部指针(constrouctor)
  //本来Man 的原型对象中的constructor指向Man这个函数的,可是如今被改变成指向Person这个函数了

  Man.prototype =  new Person() //第一次调用Person
  //Man 原型对象中的方法
  Man.prototype.action = function () {
    console.log('吃饭、睡觉、打豆豆')
  }
  //能够建立多个实例对象
  var man1 = new Man('张三', 18, '男')
  var man2 = new Man('李四', 20, '女')
  console.log(man1)
  man1.behaviour()
  man1.action()
</script>
  • 优势:全部的属性和方法都可以被继承,而且全部的属性都可自由传参。
  • 缺点:每调用一次Man构造函数时,就会调用两次Person函数

4. 拷贝继承方法 (将原对象进行遍历,把它的属性和方法赋值给新的对象)

  • 看代码
<script>
//构造函数
  function Person (name, age) {
    this.name = name;
    this.age = age;
  }
  Person.prototype.behaviour = function () {
    console.log('你们好,我是一类人')
  }

  function Man (name, age, gender) {
    this.gender = gender
    var person = new Person(name,age)
    // 在Man函数内部对Person进行遍历, 把People具备的属性赋值给Man
    for (var k in person) {
      this[k] = person[k]
    }
  }
  Man.prototype.action = function () {
    console.log('吃饭、睡觉、打豆豆')
  }
  //建立实例对象man
  var man = new Man('张三', 18, '男')
  var man2 = new Man('李四', 20, '女')
  console.log(man.name)
  console.log(man.age)
  console.log(man)
  console.log(man2)
  man.behaviour()

</script>
  • 优势:能够传参,能够继承到原型中属性和方法

    5. this的方式(这种方式与call的方式相似)

<<script>
   //构造函数
  function Person (name, age) {
    this.name = name
    this.age = age
  }
  Person.prototype.behaviour = function () {
    console.log('你们好,我是一类人')
  }

  function Man (name, age, gender) {
  //在Man中添加一个属性people,把People这个函数体赋值给Man的属性people,而后再进行调用
    this.people = Person
    //进行调用
    this.people(name, age)

    this.gender = gender
  }
  Man.prototype = function () {
    console.log('吃饭、睡觉、打豆豆')
  }
  //实例对象
  var man = new Man('张三', 18 , '男')

  console.log(man)
  man.behaviour()// 报错  不能继承到Person原型中的属性方法
  </script>
  • 优势: 能够传参
  • 缺点:原型内的方法没法继承,而且还多了一个属性people
相关文章
相关标签/搜索