小工具知识网

当前位置: 首页 > 行业知识 > js - 原型链

行业知识

js - 原型链

2026-10-30 20:50:14 来源:互联网转载

js - 原型链

  • 1. js原型链
  • 2. js原型链的应用
    • 2.1 js原型链继承
    • 2.2 利用js原型判断对象类型
    • 2.3 new的过程中发生了什么 / 手写new

      1. js原型链

      原型链由三个部分组成:构造函数、实例、原型对象。

      构造函数:由大写字母开头的函数。在创建构造过程中,js会自动为它添加prototype属性,值为拥有constructor属性原型对象,constructor属性值为该构造函数。只有函数才有prototye属性。

      实例:由构造函数new(实例化)得到。

      原型对象:构造函数会在创建的过程中自动创建。

      举个例子:

      function Person(){} // 构造函数var person = new Person() // 实例对象

      关系图如下:

      探讨原型链的过程

      我们接触到的js复杂数据类型的构造函数都是function类型,因为复杂数据类型的构造函数都是new Function创建的。

      typeof 能检测:

      1.基本数据类型(除了null) 、

      2.function类型、

      3.对象(但是不能区分是什么对象,比如数组和对象分不清)

      //函数对象  function Func1(){};   //函数声明var Func2 = function(){};  // 函数表达式(右边是匿名函数)var Func3 = new Function("n1,n2","return n1+n2");  // 函数对象(不推荐)  console.log(typeof Func1);  //function  console.log(typeof Func2);  //function  console.log(typeof Func3);   //function  console.log(typeof Object);   //function  console.log(typeof Array);   //function  console.log(typeof String);   //function  console.log(typeof Date);   //function  console.log(typeof Function);   //function  

      A instanceof B 是探讨A的__proto__或是__proto__.proto__或是__proto.proto…是否等于B.prototype,如果是则返回true,否则返回false。

      Function instanceof Object //true Object instanceof Function // true // Function.__proto__.__proto__ === Object.prototype// Object.__proto__ === Function.prototype

      是不是感觉有些奇怪,因为Object是构造函数,继承了Function.prototype,Function也是对象,继承了Object.prototype。本质原因还是因为Function构造函数的构造函数是他本身,所以Function.__proto__也指向Function.prototype

      用原型链图表示:

      还有一个发现,就是原型链的尽头是null,就是说,当实例对象不停的.__proto__尽头是Object.prototype.proto(null)

      js内置对象包含Object、Function、Array、String、Boolean、Number、Date、RexExp。

      2. js原型链的应用

      2.1 js原型链继承

      原型链可以用比较小的内存来实现对象共享。只需在原型对象上添加方法(重写原型对象),子实例都可以引用。

      function Person() { } // 构造函数var person = new Person() // 实例对象Person.prototype.name = 'name';Person.prototype.get = () => {    console.log('get')};person.get() // 'get'console.log(person.name); // 'name'

      缺点:实例对原型上的引用类型值进行篡改。

      Person.prototype.arr = ['a','b'];person.arr.push('c');console.log(Person.prototype.arr); // ['a','b','c']

      2.2 利用js原型判断对象类型

      typeof A:

      只能判断除了null之外的基础数据类型。

      复杂数据类型+null都会判断为object,函数会判断为function。

      A instanceof B:

      表示A是否是B这个构造函数的实例对象,A.proto… === B.prototype则成立。

      不能判断基本数据类型。

      console.log('111' instanceof String) // falseconsole.log((new String('111')) instanceof String) // true

      A.constructor:

      利用原型链和原型,不能判断undefined和null。

      利用实例的自动查找原型对象上的constructor属性为构造函数。

      ‘1’.proto.constructor 为 ƒ String() { [native code] }

      console.log('1'.constructor);  // ƒ String() { [native code] }console.log((function a(){}).constructor); // ƒ Function() { [native code] }console.log(null/undefined.constructor);  // Uncaught TypeError: Cannot read properties of null (reading 'constructor')

      Object.prototype.toString.call ( A )

      可以检测所有数据类型。

      console.log(Object.prototype.toString.call(true)) // '[object Boolean]'console.log(Object.prototype.toString.call(undefined)) // '[object Undefined]'console.log(Object.prototype.toString.call(null)) // '[object Null]'console.log(Object.prototype.toString.call(Person)) // 自定义函数'[object Function]'

      2.3 new的过程中发生了什么 / 手写new

      new的过程中发生了什么

      先看两段代码帮助理解

      // 无returnfunction Person1(name, age) {    this.name = name;    this.age = age;}// 有return function Person2(name, age) {    this.name = name;    this.age = age;    // 试一试返回基本数据类型和引用数据类型的区别(如return null时候,结果跟Person1一样)    return { type: 'dog', owner: 'lihua' } }var func = () => { console.log('my name is lihua') }Person1.prototype.getName = func;Person2.prototype.getName = func;var person1 = new Person1('lihua', 18);var person2 = new Person2('lihua', 18);//{ name: 'lihua', age: 18 } , () => {..} , {getName: ƒ, constructor: ƒ} console.log(person1, person1.getName, person1.__proto__)//{ type: 'dog', owner: 'lihua' } , undefined , Object.prototypeconsole.log(person2, person2.getName, person2.__proto__)

      所以new的过程中发生了以下四个步骤:

      1. 创建一个空对象
      2. 将空对象的__proto__指向构造函数的prototype
      3. 执行构造函数,改变this指向为创建出来的空对象
      4. 如果构造函数有返回值,对构造函数的返回值做判断,返回值为引用类型时,返回该对象,返回值是基本数据类型时是创建出来的空对象。

      手写new

      根据以上,手写new如下:

      function myNew(constructor, ...args) {    var result = constructor(...args)    // return 基本数据类型时    if (typeof result !== 'object' || result === null) {        let obj = {}                                        //创建空对象        obj.__proto__ = constructor.prototype                // 空对象的__proto__指向构造函数的原型        constructor.apply(obj, args)                         //改变this指向        return obj    }    // return 引用数据类型时    return result}

      测试一下

      function Constructor(a, b) {    this.a = a;    this.b = b;    return a;}Constructor.prototype.getName = () => { return 'hihihi' }var test = myNew(Constructor, 1, 2)console.log(test, test.getName) // Constructor {a: 1, b: 2} () => { return 'hihihi' }

上一篇:公众号怎么放入服务器内?

下一篇:揭秘手机棋牌平台源码,轻松打造个性化私人棋牌室!