原型 && 原型链

作者: 晚月川 | 来源:发表于2020-03-25 22:03 被阅读0次

原型 && 原型链

  • 每一个类(函数)都天生具备一个属性:prototype(原型),prototype的属性值是一个对象(浏览器默认会给其开辟一个堆内存)=>“原型对象上所存储的属性和方法,就是供当前类实例所调用的公有的属性和方法”
    • 普通函数
    • 类也是函数类型的值
  • 在类的prototype原型对象中,默认存在一个内置的属性:constructor(构造函数),属性值就是当前类(函数)本身,所以我们也把类称为构造函数
  • 每一个对象都天生具备一个属性:__proto__(原型链),属性值是当前实例(对象)所属类的prototype原型
    • 对象数据类型
      • 普通对象
      • 数组对象
      • 正则对象
      • ……
    • 实例也是对象类型值(除基本值外)
    • 类的prototype原型属性值也是对象
    • 函数也具备对象的特征(它有一重身份就是对象类型)
    • ……
      =>所有的对象数据类型值,都是内置类Object的一个实例
  1. arr1.length 或者 arr1[0] =>获取当前实例的私有属性值
  2. arr1.push()
    • 首先找自己的私有属性,私有属性有,调取的就是私有属性;如果没有,默认基于__proto__原型链属性,找所属类prototype原型上的公共属性和方法;如果还没有则基于原型prototype中的__proto__继续向上查找,一直找到Object.prototype为止
  3. arr.__proto__.push
    • 直接找所属类原型上的push方法,类似于Array.prototype.push这样找arr1.__proto__.push === arr2.push === Array.prototype.push

原型链查找机制:基于实例__proto__找所属类的prototype
=>实例的私有属性方法
=>实例的公有属性和方法

push是arr1实例的“公有属性方法” pushArray.prototype的私有属性
hasOwnProperty是arr1实例的“公有属性方法”
对象的私有属性:存储在自己的堆中,无需基于__proto__查找
对象的公有属性:自己堆中没有,需要基于proto找prototype上的

Array.prototype.hasOwnProperty('hasOwnProperty'); //=> false
Object.prototype.hasOwnProperty('hasOwnProperty'); //=> ture

所有对象都是Object的实例:只要原型链最后都能找到Object.prototype,那么都是对象类的一个实例(也就是对象),例如:数组是Array的一个实例,但是最后原型链也找到了Object.prototype,所以数组也是对象类的一个实例(也是一个对象)

document -> HTMLDocument.prototype -> Document.prototype -> Node.prototype -> EventTarget.prototype -> Object.prototype
每个元素对象 最后都能找到 Object.prototype,所以它们也是对象类的实例,也是一个对象
元素集合 -> HTMLCollection.prtotype -> Object.prototype

只要在当前实例原型链上的属性和方法 实例都可以调用
JS中的所有值,最后基于原型链,都能找到Object.protitype原型,也就是都是对象类的实例,也就是都是对象 =>(万物皆对象)

  • 给类的原型上扩展属性或者方法(供其实例调取使用的公有属性方法)
    • Fn.prototype.xxx = xxx;
    • Object.prototype.xxx = xxx; 内置类原型上扩展方法
    • f1.proto.xxx = xxx; 这样也可以,因为基于实例的proto找到的就是所属类的原型,也相当于给原型上扩展属性方法(只不过这种方式我们基本不用,因为在IE浏览器中,为了防止原型链的恶意篡改,是禁止我们自己操作proto属性的;IE中不让用proto
  • 关于构造函数中相关的this问题
    • 基于new执行,构造函数,函数体中的this是当前类的一个实例
    • 给实力扩展的私有或者公有方法,这些方法中的this完全看前面是否有“点”来决定
/*  向类的原型上扩展属性方法
    Fn.prototype.xxx = xxx; 向默认的堆内存中增加属性方法
    =>如果需要设置很多属性方法,操作起来比较麻烦(小技巧:给Fn.prototype设置别名) */
let prop = Fn.prototype;
prot.A = 100;
prot.B = 200; 
prot.C = 300;
// 这类方式的特点都是向默认开辟的堆内存中扩展属性和方法,默认开辟的堆内存中存在constructor这个属性
// 重定向Fn的原型指向
// =>自己开辟的堆内存中是没有constructor这个属性的,所以真实项目中,为了保证结构的严谨性,我们需要手动设置constructor
// =>如果在重定向之前,我们向默认开辟的堆内存中设置了一些属性方法,重定向后,之前设置的属性方法都丢失了(没用了)
Fn.prototype = {
    constructor:Fn;
    xxx:xxx
}


JS中有很多内置类,而且在内置类的原型上有很多内置的属性和方法
Array.prototype:数组作为Array的实例,就可以调取原型上的公共属性方法,完成数组的相关操作 => arr.push():arr基于proto原型链的查找机制,找到Array.prototype上的push方法,然后把push方法执行,push方法执行:
=> 方法中的this是arr这个数组的实例
=> 作用向arr(也就是this)的末尾追加新的值
=> 返回结果是新增后数组的长度

// 向内置类原型扩展方法:
// Array.prototype.xxx = xxx;
// =>这种方法存在风险:我们自己设置的属性名可能会把内置的属性给覆盖掉
// =>一般我们自己在内置类原型上扩展的方法,设置的属性名做好加上前缀
Array.prototype.push = function () {
    console.log('自己的push');
};
let arr = [10,20];
arr.push(100);
// 浏览器为了保护内置类原型上的方法,不允许我们重新定向内置类原型的指向(严格模式下会报错)
Array.prototype = {
    AA:100
};
/* 
 * 模拟内置的push方法
 *  在类的原型上编写的方法,让方法执行,我们一般都这样操作:实例.方法(),所以方法中的this一般都是我们要操作的这个实例,我们基于this操作就是操作这个实例
 */
Array.prototype.push = function puah(value) {
    // this:要操作的数组实例
    this[this.length] = value;
    return this.length;
};
let arr = [10,20];
console.log(arr.push(100),arr);

相关文章

  • JavaScript 原型、原型链与原型继承

    原型,原型链与原型继承 用自己的方式理解原型,原型链和原型继承 javascript——原型与原型链 JavaSc...

  • 原型、原型链

    (什么是原型、原型链?有什么作用) JavaScirpt深入之从原型到原型链 图解 Javascript 原型链 ...

  • 关于原型原型链的理解

    什么是原型? 什么是原型链? 为什么需要原型,和原型链?

  • 廖雪峰JS小记

    (function(){})() 原型,原型链 浅谈Js原型的理解JS 原型与原型链终极详解 对象 对象:一种无序...

  • 原型链&查找规则&作用域链

    原型链(隐式原型链) 属性的查找规则(原型链的查找规则) 作用域链

  • 【原型和原型链】什么是原型和原型链

    【原型和原型链】什么是原型和原型链https://blog.csdn.net/xiaoermingn/articl...

  • js原型链

    目录 1.对象的原型和原型链1.1什么是原型1.2查看原型1.3对象的原型链 2.使用构造函数2.1 函数的原型链...

  • 原型链实现继承

    原型链 原型链示意图 使用原型链实现继承 这是怎么回事呢? 原型链在哪? 听我细细道来~ 首先 Teacher 实...

  • js中的实现继承的几种方式

    大纲:原型链借用构造函数组合继承原型式继承寄生式继承寄生组合式继承 1、原型链: 什么是原型链? 原型链的基本思想...

  • 2019-01-28

    原型与原型链

网友评论

    本文标题:原型 && 原型链

    本文链接:https://www.haomeiwen.com/subject/pydfuhtx.html