JS 原型

原型连示意图 

分析

首先,要明确几个点:
1.在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此,它们都会具有对象共有的特点。
即:对象具有属性__proto__,可称为隐式原型一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。

2.方法(Function)
方法这个特殊的对象,除了和其他对象一样有上述_proto_属性之外,还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。

好啦,知道了这两个基本点,我们来看看上面这副图。(建议把图另存下来,边看边对比思考)
1.构造函数Foo()
构造函数的原型属性Foo.prototype指向了原型对象,在原型对象里有共有的方法,所有构造函数声明的实例(这里是f1,f2)都可以共享这个方法。

2.原型对象Foo.prototype
Foo.prototype保存着实例共享的方法,有一个指针constructor指回构造函数。

3.实例
f1和f2是Foo这个对象的两个实例,这两个对象也有属性__proto__,指向构造函数的原型对象,这样子就可以像上面1所说的访问原型对象的所有方法啦。

另外:
构造函数Foo()除了是方法,也是对象啊,它也有__proto__属性,指向谁呢?
指向它的构造函数的原型对象呗。函数的构造函数不就是Function嘛,因此这里的__proto__指向了Function.prototype。
其实除了Foo(),Function(), Object()也是一样的道理。

原型对象也是对象啊,它的__proto__属性,又指向谁呢?
同理,指向它的构造函数的原型对象呗。这里是Object.prototype.

最后,Object.prototype的__proto__属性指向null。

 总结
1.对象有属性__proto__,指向该对象的构造函数的原型对象。
2.方法除了有属性__proto__,还有属性prototype,prototype指向该方法的原型对象。

测试

 //测试1 如下的输出结果 
 function A () {

  }
  A.prototype.n = 1

  var b = new A()

  A.prototype = {
    n: 2,
    m: 3
  }

  var c = new A()
  console.log(b.n, b.m, c.n, c.m)

  

 

  //测试2
  function F (){}
  Object.prototype.a = function(){
    console.log('a()')
  }
  Function.prototype.b = function(){
    console.log('b()')
  }
  
  var f = new F()
  f.a()
  f.b()
  F.a()
  F.b()

答案

测试1:1,undefined,2,3

测试2: a(),报错,a(),b()


原型链继承

function dog (name,type){
    this.name = name
    this.type = type
}

var xiaohei = new dog('xiaohei','taidi')

console.log(xiaohei .toString())

// 我们并未在dog 中定义toString 方法 但是任然可以调用 因为在原型链上我们在Object原型对象中
// 找到了toString 方法。dog的原型对象是一个空Object对象 且有个属性隐式的原型属性__proto__
// 它指向了其构造函数的显示原型对象 其中定义了toString方法。所以因为原型对象是Object对象 所以
// 可以调用同String  当我们将父类型的实列对象赋值给子类型的原型 就可以实现‘对象继承’

 套路如下:

   关键 子类型的原型为父类型的一个实例对象

  1. 定义父类型构造函数
  2. 给父类型的原型添加方法
  3. 定义子类型的构造函数
  4. 创建父类型的对象赋值给子类型的原型
  5. 将子类型原型的构造属性设置为子类型
  6. 给子类型原型添加方法
  7. 创建子类型的对象: 可以调用父类型的方法
  //父类型
  function Supper() {
    this.supProp = 'Supper property'
  }
  Supper.prototype.showSupperProp = function () {
    console.log(this.supProp)
  }

  //子类型
  function Sub() {
    this.subProp = 'Sub property'
  }

  // 子类型的原型为父类型的一个实例对象
  Sub.prototype = new Supper()
  // 让子类型的原型的constructor指向子类型
  Sub.prototype.constructor = Sub
  Sub.prototype.showSubProp = function () {
    console.log(this.subProp)
  }

  var sub = new Sub()
  sub.showSupperProp()
  // sub.toString()
  sub.showSubProp()

  console.log(sub)  // Sub

 

 sub的原型对象为supper的对象时,查找constructor构造器方法时,依照原型发先sub的构造方法变成了function Supper() 

所以我们需要修正一下其构造方法Sub.prototype.constructor = Sub

 这样对于父类的方法我们就可以直接调用了,那么我要‘继承父类的属性’呢?

借用构造函数继承(假的)

关键    在子类型构造函数中通用call()调用父类型构造函数 

  1. 定义父类型构造函数
  2. 定义子类型构造函数
  3. 在子类型构造函数中调用父类型构造
  function Person(name, age) {
    this.name = name
    this.age = age
  }
  function Student(name, age, price) {
    Person.call(this, name, age)  // 相当于: this.Person(name, age)
    /*this.name = name
    this.age = age*/
    this.price = price
  }

  var s = new Student('Tom', 20, 14000)
  console.log(s.name, s.age, s.price)

 总结继承

  1. 利用原型链实现对父类型对象的方法继承
  2. 利用super()借用父类型构建函数初始化相同属性
  function Person(name, age) {
    this.name = name
    this.age = age
  }
  Person.prototype.setName = function (name) {
    this.name = name
  }

  function Student(name, age, price) {
    Person.call(this, name, age)  // 为了得到属性
    this.price = price
  }
  Student.prototype = new Person() // 为了能看到父类型的方法
  Student.prototype.constructor = Student //修正constructor属性
  Student.prototype.setPrice = function (price) {
    this.price = price
  }

  var s = new Student('Tom', 24, 15000)
  s.setName('Bob')
  s.setPrice(16000)
  console.log(s.name, s.age, s.price)

能力有限,经验不足,有问题和不足之处,请给予批评指正

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值