JS原型和原型链详解

87 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天

1.构造函数,实例化函数,prototype,proto,constructor,原型对象,Object顶层对象---解析

1.1.构造函数:构造函数与普通函数唯一的区别就是调用方式不同.除此之外,构造函数也是函数.并没有把某个函数定义为构造函数的特殊语法.任何函数只要使用new操作符调用就是构造函数,而不使用new操作符调用的函数就是普通函数.

function person(name,age,sex,old){
     this.name=name;
     this.age=age;
     this.sex=sex;
}

1.2.实例化函数:

//Qin就是实例化对象
var Qin=new person("qinhongyu",21,"男","老");

1.3.prototype属性:

原型:在JavaScript中,每创建一个函数对象,都会天生自带一个prototype属性,这个属性指向函数的原型对象,它默认指向object空对象(Object空对象,没有完美自己创建的属性),称为原型对象。

1.4.原型对象:

原型对象,也就是(构造函数.prototype),  原型对象含有一个constructor属性和__proto__属性,constructor属性(指向的就是当前原型对象的构造函数),__proto__属性指向Object顶层对象(指向其原型链的上一级对象)

1.5.constructor(构造者):

原型对象的构造者即为构造函数

1.6. _ _ proto _ _

指向其原型链上的上一级对象;

比如实例化对象person,其原型链的上一级对象为Person.prototype(person的原型对象)

2.1.原型链核心概念

原型链: 当试图调用或想得到一个对象实例中的属性 或 方法时,如果这个对象本身不存在这个属性 或 方法 也就是说构造函数中没有定义你想要的属性或方法,那么就会通过构造函数的prototype属性到原型中去 寻找这个属性 或者 方法 (也就是它的构造函数的’prototype’属性会到原型对象中去寻找)  ,  如果有就返回,如果没有就会到顶层的Object去找 , 如果有就返回, 如果还是找不到就返回undefined!

原型链流程图

一个函数的原型链
function a(){}
a.prototype  ==>a的原型对象
a.prototype.__proto__  ==> Object的原型对象(Object的顶层对象)
a.prototype.__proto__.__proto__   ==> null

console.log(a.prototype)

所有的函数的原型对象就是Function的实例,所以有prototype

2.2.构造函数、实例化对象、原型对象的基本关系图分析

3.prototype原型

3.1.能够引用prototype的东西绝对是函数,prototype是属于函数的一个属性,

prototype是函数的一个属性,本质是函数的原型对象。

3.2.原型知识点

为了节省内存,我们把对象的方法都放在原型里面。为什么呢?

因为改写对象下面公用的方法或者属性、让公用的方法或者属性在内存中只存在一份

在我们通过new实例化对象的时候,在内存中,会自动拷贝构造函数中的所有属性和方法,用来给实例对象赋值,而不管我们实例化多少次,原型里面的属性和方法只生成一次,所以会节省内存。

3.3.原型对象定义属性或方法优先级比构造函数定义的属性或方法低

  • 读取对象的属性值时,会自动到原型链中查找
  • 设置对象的属性值时,不会查找原型链,如果当前对象中没有,则直接添加此属性并设置其值
  • 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
 function fun(){
        
    }
    fun.prototype.a="xxx"
    var fn1=new fun()
    fn1.a="yyy"
    console.log(fn1);

4.instanceof详解

  • instanceof是如何判断的?
    • 表达式 A(实例对象) instanceof B(构造函数)
    • 其实就是判断B的原型对象在不在A的隐式原型链
    • 如果B函数的显式原型对象在A对象的原型链上,则返回true,否则返回false
  • Function是通过new自己产生的实例
 function foo(){}
    var f1=new foo();
    console.log(f1 instanceof foo);  //true
    console.log(f1 instanceof Object);  //true

console.log(Object instanceof Function);
console.log(Object instanceof Object);
console.log(Function instanceof Function);
console.log(Function instanceof Object);

function Foo(){}
console.log(Object instanceof Foo);

输出为:

true

true

true

true

false

最后一个为false的原因

5.1.面试题

function A(){

    }
    A.prototype.n=1
    var b=new A()
    
    A.prototype={
        n:2,
        m:3
    }

    var c=new A()
    console.log(b.n);  //1
    console.log(b.m);  //undefined
    console.log(c.n);  //2
    console.log(c.m);  //3

一开始b和A存储的都是指向同一个原型对象的地址值,

后面A的原型对象赋值成了一个新的对象,A存储的地址值发生改变,但是b的地址值没变

5.2.面试题2

function F(){}
    Object.prototype.a=function(){
        console.log("a")
    }
    Function.prototype.b=function(){
        console.log("b")
    }
    var f=new F()
    f.a()  //a
    f.b()  //报错
    F.a()   //如果f.b()注释,下面分别输出 a和b
    F.b()