javaScript-原型链

什么是原型

你没车,你爸有车,你借着开就是原型

有些对象可以没有原型

(Object.create(null,{}))
如上创建的方法都没有
据说Vue中创建对象都是这么创建的

原型链调用方式

  1. a.__ proto __(当函数当作对象调用时):自己用的
  2. b.prototype(函数实例化出来之后自动给新创建对象指定原型):用来给别人的只有函数有
    简而言之,第一个是自己本身的,第二个是当他作为构造函数时候用的
    向军大叔的图:
    在这里插入图片描述
    这里很重要所以自己跑一下demo
  let ABC = function () {
    console.log('我是abc');
  }
  ABC.prototype.name = function () {
    console.log('我是sunyf');
  }
  let def = new ABC;
  def.name();
  console.log(def);
  console.log(def.__proto__);
  console.log(ABC.prototype);
  console.dir(ABC.__proto__);

原型方法与对象方法优先级

就近原则,自己有就用自己的

自定义对象的原型设置

  1. Object.setPrototypeOf(孤儿, 领养者);//设置
  2. Object.getPrototypeOf(孤儿);//获取

原型中的constructor引用

  1. 原型:User.prototype.constructor == User
  2. 新增原型: User.prototype.name = function
  3. User.prototype.__proto__ == Object.prototype
    所以可以通过创建出来的对象找出创建它他的构造函数,从而创建更多的对象
  • 一个构造函数的prototype的constructor是他自己(因为它用来给别人构造时候应该调用生成它的方法)
  • 同样生成出来的新对象的constructor也是生成对象的构造函数
  • 大家的prototype都是一个当方面不断增加更新(这句不知道对不对)
  • 对象自己找原型用__proto__构造函数找用.prototype

一个Object一个世界

    function User(name) {
      this.name = name;
    }
    console.dir(User);
    console.dir(User.prototype);
    console.dir(User.prototype.__proto__);
    console.dir(User.prototype.constructor);
    let s = new User('sss');
    console.dir(s);
    console.dir(Object.getPrototypeOf(s).constructor==User);

原型链检测

  • instanceof
  • 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
console.log(a instanceof A)

查看a的原型链上是否有A

  • isPrototypeOf()
    方法用于测试一个对象是否存在于另一个对象的原型链上。
    console.log(b.isPrototypeOf(a));

属性检测

  • in
    检测当前对象中是否有该属性/是否在原型链上
name" in a
  • hasOwnProperty
    检测当前对象是否有该属性
a.hasOwnProperty(key)

使用call或apply借用原型链

apply:

  let ss = {
    data: [1, 2, 3, 34, 5, 7]
  };
  Object.setPrototypeOf(ss, {
    max() {
      return this.data.sort((a, b) => b - a)[0];
    }
  });
  console.log(ss.max());

  let xj = {
    lessons: { js: 87, php: 63, node: 99, linux: 88 },
    // getter
    get data() {
      return Object.values(this.lessons);
    }
  };
  console.log(ss.max.apply(xj));

借用方法优化

  let ss = {
    lessons: { js: 87, php: 63, node: 99, linux: 88 }
  };
  console.log(Math.max.apply(null, Object.values(ss.lessons)));

DOM元素的借用方法优化

  let btns = document.querySelectorAll("button");
  btns = [].filter.call(btns, item => {
    return item.hasAttribute("class");
  });
  console.log(btns);

合理的构造函数方法声明

  function User(name) {
    this.name = name;
  }
  User.prototype = {
    constructor: User,
    show() {
      console.log(this.name);
    },
    get() {
      console.log("get..");
    }
  };
  let lisi = new User("李四");
  let ss = new User("ss");
  lisi.show();
  ss.show();

为一个对象自定义原型

  1. Object.create(官方):无法获取只能定义
  let ss = Object.create(user, {
    name: {
      value: "sss"
    }
  });
  console.log(ss.show());
  1. __proto(非官方,浏览器厂商定义):可以定义以及获取
  let ss = { name: "ss" };
  ss.__proto__ = user;
  console.log(ss.__proto__);
  1. Object.setPrototypeOf(官方,设置)
  Object.setPrototypeOf(ss, user);
  1. Object.getPrototypeOf(官方,查询)
  console.log(Object.getPrototypeOf(ss));

__proto__底层为属性访问器

其实就是一个getter与setter只能接收对象为参数,无法接受字符串等

  let ss = {
    action: {},
    get proto() {
      return this.action;
    },
    set proto(obj) {
      if (obj instanceof Object) {
        this.action = obj;
      }
    }
  };
  ss.proto = { view: function() {} };
  ss.proto = "abc";
  console.log(ss.proto);

如果想设置:let ss = Object.create(null);即可

原型的继承,不是改变构造函数的原型

在这里插入图片描述

如下例子:如果这样继承,每个人都继承了user的prototype,导致再次添加方法会导致其他构造函数内部方法的混乱故错误

  function User() { }
  User.prototype.name = function () {
    console.log("user.name");
  };

  function Admin() { }
  Admin.prototype = User.prototype;
  Admin.prototype.role = function () {
    console.log("admin.role");
  };

  function Member() { }
  Member.prototype = User.prototype;
  Member.prototype.role = function () {
    console.log("member.role");
  };

  let a = new Admin();
  a.role();

继承是原型的继承

也就是说,是爸爸继承别人的爸爸变成爷爷
而不是换一个新爸爸
优点:
避免方法冗余,并且不会重名
如上代码可以改写为:

  function User() { }
  User.prototype.name = function () {
    console.log("user.name");
  };

  function Admin() { }

  // Admin.prototype.__proto__ = User.prototype;
  Admin.prototype = Object.create(User.prototype);
  Admin.prototype.role = function () {
    console.log("admin.role");
  };

  function Member() { }
  Member.prototype.__proto__ = User.prototype;
  Member.prototype.role = function () {
    console.log("member.role");
  };

ps:用Object.create时候要注意顺序

注意 在改变原型指向之后记得给一个constructor(注意设置不可遍历)

js多态

可优化代码,仅执行show方法

  function User() { }
  User.prototype.show = function () {
    console.log(this.description());
  };

  function Admin() { }
  // Admin.prototype = Object.create(User.prototype);
  Admin.prototype.showAdmin = function () {
    return "管理员在此";
  };

  function Member() { }
  // Member.prototype = Object.create(User.prototype);
  Member.prototype.showMember = function () {
    return "我是会员";
  };

  function Enterprise() { }
  // Enterprise.prototype = Object.create(User.prototype);
  Enterprise.prototype.showEnterprise = function () {
    return "企业帐户";
  };
  for (const obj of [new Admin(), new Member(), new Enterprise()]) {
    if (obj instanceof Admin) {
      console.log(obj.showAdmin());
    } else if (obj instanceof Member) {
      console.log(obj.showMember());
    } else if (obj instanceof Enterprise) {
      console.log(obj.showEnterprise());
    }
  }

对象工厂派生对象并实现继承

  function User(name, age) {
    this.name = name;
    this.age = age;
  }
  User.prototype.show = function () {
    console.log(this.name, this.age);
  };
  let obj = {};
  console.log(obj.__proto__ == Object.prototype);
  function admin(name, age) {
    const instance = Object.create(User.prototype);
    User.call(instance, name, age);
    instance.role = function () {
      console.log("role");
    };
    return instance;
  }
  let ss = admin("ss", 19);
  ss.show();
  ss.role();
  function member(name, age) {
    const instance = Object.create(User.prototype);
    User.call(instance, name, age);
    return instance;
  }

  let lisi = member("李四", 23);
  lisi.show();

多继承问题

js语言不支持多继承,只能让父级的原型继续继承所需要的原型

使用mixin实现多继承

每一个功能都设置成一个对象
由于prototype也是一个对象 往里面推就好(object.assign)

super关键字

super == this.proto(当前对象的原型而不是调用者的原型)
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值