• prototype原型链详解


    原型链

    • 创建 (声明) 对象有几种方法
    • 原型、构造函数、实例、原型链
    • instanceof 的原理
    • new 运算符

    一. 创建对象有几种方法

    1.字面量

    var test2 = {x:123,y:345};
    console.log(test2);//{x:123,y:345};
    console.log(test2.x);//123
    console.log(test2.__proto__.x);//undefined
    console.log(test2.__proto__.x === test2.x);//false
    

    2.构造函数new

    // 方法1 #通过new Object声明的一个对象
    var test1 = new Object({x:123,y:345});
    console.log(test1);//{x:123,y:345}
    console.log(test1.x);//123
    console.log(test1.__proto__.x);//undefined
    console.log(test1.__proto__.x === test1.x);//false
    
    // 方法2  #使用显式构造函数创建对象
    var M = function(name){ this.name = name;};
    var o3 = new M('o3');  //M {name: "o3"}
    

    new的作用: 1.创了一个新对象; 2.this指向构造函数; 3.构造函数有返回,会替换new出来的对象,如果没有就是new出来的对象

    3.内置方法

    Obejct.create(obj,descriptor),obj是对象,describe描述符属性(可选),创建一个具有指定原型且可选择性地包含指定属性的对象。

    let p = {x:123,y:345};
    let test = Object.create(p);
    console.log(test);//{}
    console.log(test.x);//123
    console.log(test.__proto__.x);//3
    console.log(test.__proto__.x === test.x);//true
    console.log(test.__proto__ === p)  // true
    

    Object.create方法是把参数中这个对象作为一个新对象的原型对象赋给test的,test本身不具备这个属性的,通过原型链来连接这个原型对象的。(所以test对象本身没有name这个属性,只能通过原型链来找name属性。

    三种方法的优缺点

    1. 功能:都能实现对象的声明,并能够赋值和取值
    2. 继承性:内置方法创建的对象继承到__proto__属性上
    3. 隐藏属性:三种声明方法会默认为内部的每个成员(属性或方法)生成一些隐藏属性,这些隐藏属性是可以读取和可配置的,属性分类见下面:
    4. 属性读取:Object.getOwnPropertyDescriptor()或getOwnPropertyDescriptors()
    5. 属性设置:Object.definePropertype或Object.defineProperties

    二. 原型链的关系

    下图仔细观察原型、构造函数、对象实例、原型链之间的关系。

    原型链的关系

    1.对象实例

    ​ 只要是对象就是一个实例;回顾上面的创建对象的几种方式,任何一个实例对象都有一个隐式原型__proto__对象。

    2.构造函数

    凡是通过关键字new来操作后边的函数,这个函数就是构造函数;准确的说任何一个函数只要被new使用了,后面这个函数就可以被叫做构造函数。

    构造函数可以使用new运算符来生成一个实例;

    3.原型对象

    任何一个函数都有一个prototype属性,他是函数所独有的,这个prototype指的就是显式原型对象;

    任何一个实例对象都有一个__proto__对象。他是对象所独有的,这个__proto__指的就是隐式原型对象;

    __proto__ 是原型链查询中实际用到的,它总是指向 prototype

    prototype 是函数所独有的,在定义构造函数时自动创建,它总是被__proto__所指。

    4.原型链

    每个对象都可以有一个原型_proto_,这个原型还可以有它自己的原型,以此类推,形成一个原型链。查找特定属性的时候,我们先去这个对象里去找,如果没有的话就去它的原型对象里面去,如果还是没有的话再去向原型对象的原型对象里去寻找知道终点null...... 这个操作被委托在整个原型链上,这个就是我们说的原型链了

    原型链是通过什么来实现这个往上找的过程呢?
    通过prototype这个原型和__proto__属性来完成原型链的查找的;

    img

    let obj1 = {name:'lucas'};   
    obj1.__proto__ === Object.prototype  // true
    obj1.__proto__.__proto__  			// null  #这是原型链顶端了
    Object.prototype.__proto__  		// null #这是原型链顶端了
    
    function Person(){}
    Person.prototype.__proto__.__proto__  // null #这是原型链顶端了
    
    let person = new Person();
    person.__proto__.__proto__.__proto__  // null #这是原型链顶端了
    person.__proto__  === Person.prototype  // true
    
    function M (name) { 
        this.name = name; 
    }//person是构造函数
    
    var o3 = new M('o3') // personTwo是实例
    

    原型关系详解

    原型对象都有一个默认的constructor属性指向构造函数

    三. instanceof 原理

    instanceof主要用于判断某个实例是否属于某个类型,也可用于判断某个实例是否是其父类型或者祖先类型的实例。

    instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false。

    实例对象上有__proto__这个属性,实例对象的这个属性引用是它构造函数的原型对象(也就是找到的这个构造函数);
    构造函数有prototype这个属性,这个属性引用的原型对象,在往下走,实例对象的__proto__这个属性,其实是引用这个原型对象。
    

    instanceof原理图

    模拟开发instanceof

    function instanceof(left, right) {
        const rightVal = right.prototype
        const leftVal = left.__proto__
        // 若找不到就到一直循环到父类型或祖类型
        while(true) {
            if (leftVal === null) {
                return false
            }
            if (leftVal === rightVal) {
                return true
            }
            leftVal = leftVal.__proto__ // 获取祖类型的__proto__
        }
    }
    

    四. new 运算符

    new运算符

    var new2 = function(func){
    
        //1.创建一个空对象,这个对象要继承这个构造函数的原型对象(空对象要关联构造函数的原型对象;)
        let o = Object.create(func.prototype);
        
        //2.执行构造函数
        let k = func.call(o);//call用来转移上下文(this),把这个上下文转成o对象
        
        //3.判断构造函数的运行结果是不是对象类型
        if(typeof k ==='object'){
            return k;
        }else{
            return o;
        }
     };
    
  • 相关阅读:
    UDP通信网络编程
    多线程:购票小案例
    多线程:线程池异步计算,2个线程,1个计算10的阶乘,一个计算20的阶乘并返回
    Kong入门指南
    5分钟完成App后端API开发
    Docker安装Kong
    React Native如何用调用RestFul API
    Flutter如何用调用RestFul API
    如何用Flutter调用生成的RestFul API
    自动化API之一 生成开源ERP Odoo App 的RestFul API
  • 原文地址:https://www.cnblogs.com/jing-tian/p/12244374.html
Copyright © 2020-2023  润新知