JS原型和原型链

##创建对象 使用Object构造函数或者对象字面量可以创建单个对象,但面对创建多个对象的时候,代码无法复用,这显然不是我们所期望的,为了解决此问题,人们发明了以下几种创建对象的方式 ####工厂模式

  function createPerson(name, age) {
    var o = {};
    o.name = name;
    o.age = age;
    o.sayName = function() {
      console.log(this.name);
    }
    return o;
  }
  var person1 = createPerson('Tom', 27);
  person1.sayName();
  var person2 = createPerson('Jack', 28);
  person2.sayName();

使用工厂模式创建对象存在一个问题,就是无法识别对象。这才有了后面的构造函数模式 ####构造函数模式

  function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function() {
      console.log(this.name);
    }
  }
  var person1 = new Person('Tom', 27);
  person1.sayName();
  var person2 = new Person('Jack', 28);
  person2.sayName();

  console.log(person1.constructor == Person);
  console.log(person1 instanceof Person);

  console.log(person1.sayName == person2.sayName);

创建Person实例会经历4个步骤

  1. 创建一个新对象
  2. 将构造函数(Person)的作用域赋值给新对象
  3. 执行构造函数代码
  4. 返回新对象

使用这种方式能通过constructor 或者instanceof 来识别对象类型,但还存在一个问题,就是构造函数中的方法sayName()会在每次创建新实例时构建一次,也就是方法没办法复用。使用原型模式可以解决这个问题 ####原型模式 每个函数创建时都有一个prototype属性,指向一个原型对象,这个原型对象包含所有实例共享的属性和方法。

  function Person() {

  }
  Person.prototype.name = 'Tom';
  Person.prototype.age = 27;
  Person.prototype.sayName = function() {
    console.log(this.name);
  }
  person1 = new Person();
  person1.sayName();
  person2 = new Person();
  
  console.log(person1.sayName == person2.sayName);

还可以以自变量定义的形式定义Person.prototype,写法更为简洁

  function Person() {

  }
  Person.prototype = {
    name: 'Tom',
    age: 27,
    sayName: function() {
      console.log(this.name);
    }
  };
  person1 = new Person();
  person1.sayName();
  person2 = new Person();

  console.log(person1.sayName == person2.sayName);

原型搜索机制:访问Person1的属性,首先从实例本身开始搜索,如果实例有该属性,则返回,如果没有,则继续搜索指针指向的原型对象,如果在原型对象中找到,返回属性值

原型模式也存在一定问题。默认情况下,所有实例的属性都是相同的,但这只是带来一些不便,最大的问题是属性的共享导致的,如果属性是引用类型,那么操作person1的属性会影响到person2的属性。 ####组合使用构造函数模式和原型模式 构造函数模式适合定义私有的属性,而原型模式适合定义共有的属性和方法。组合使用能发挥各自的长处,这种模式也是应用最为广泛的

  function Person(name, age) {
    this.name = name;
    this.age = age;
  }
  Person.prototype.sayName = function() {
    console.log(this.name);
  }
  person1 = new Person('Tom', 27);
  person1.sayName();
  person2 = new Person('Jack', 28);
  person2.sayName();
  console.log(person1.sayName == person2.sayName);

##继承 javascript中实现继承主要就是通过原形链来实现的。什么是原型链呢? ####原型链 了解原型链之前,我们先来回顾下构造函数、原型和实例之间的关系:每个构造函数在创建之初会有一个prototype(原型)属性,这个原型属性是一个指向构造函数的原型对象的指针,原型对象包含一个指向构造函数的指针constructor。然后调用构造函数创建一个实例,这个实例的内部又会包含一个指针(__proto__),这个指针指向构造函数的原型对象。上述中创建person1实例,在控制台可以看到如下信息。 输入图片说明

假设有两个构造函数A()和B(),让B的原型对象等于A的实例,那么B的原型对象会包含一个指针(__proto__)指向A的原型对象,如果再有一个构造函数C(),让C的原型对象等于B的实例,如此层层递进,就构成了原型和实例之间的链条,也就是所谓的原型链

  function Super() {
    this.superproperty = true;
  }
  Super.prototype.getSuperValue = function() {
    console.log(this.superproperty);
  }
  function Sub() {
    this.subproperty = false;
  }
  // 继承Super
  Sub.prototype = new Super();
  Sub.prototype.getSubValue = function() {
    console.log(this.subproperty);
  }
  var instance = new Sub();
  instance.getSuperValue();

结合上文提到的原型搜索机制,访问instance.getSuperValue(),先搜索实例Sub,然后实例没有会去搜索Sub.prototype,仍然没有找到,会再去Super.prototype中查找,这才找到getSuperValue方法。在找不到属性或者方法的情况下,搜索过程会沿着原型链一环一环前进,直到末端才会停下。 ####原型链的问题 原型链很强大,可以实现javascript的继承,但它存在一些问题,就如同上文中使用原型模式创建对象遇到的问题一样。

  1. 省略了为构造函数传递参数这一环节,导致所有Sub实例初始的属性都一样
  2. 如果属性是引用类型,那么所有的Sub实例会共享属性 ####借用构造函数
  function Super(name) {
    this.name = name;
  }

  function Sub() {
    // 继承Sup并且传递参数
    Super.call(this, 'Tom');
    // 实例属性
    this.age = 27;
  }
  var instance = new Sub();
  console.log(instance.name, instance.age);

在sub的构造函数中调用sup的构造函数,这样每个sub的实例就会拥有sup的属性。但是借用构造函数有一个问题,在使用构造函数创建对象也遇到过:不论是在sub中定义的函数还是sup中定义的函数无法复用。 ###组合继承 将原型链和借用构造函数结合使用,发挥各自的长处,成为javascript中最常见的继承模式

  function Super(name) {
    this.name = name;
  }

  function Sub(name, age) {
    // 继承Sup属性
    Super.call(this, name);

    this.age = age;
  }
  Sub.prototype = new Super();
  Sub.prototype.sayName = function() {
    console.log(this.age);
  }
  var instance = new Sub('Tom', 27);
  instance.sayName();

转载于:https://my.oschina.net/u/3643736/blog/1519557

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值