一定可以看懂的原型和原型链

预备知识:

  1. 每个函数对象在定义的时候都会自动生成一个prototype属性(显式原型),保存的是一个空Object对象的地址值。即函数对象的prototype属性指向一个空Object对象。
  2. 每个实例对象在创建的时候都会自动生成一个__proto__属性(隐式原型),保存的值和prototype值相同,即实例对象的__proto__和函数对象的prototype都指向同一个空Object对象
    var Fun = function(){
        this.test1 = function(){
        console.log("test1");
        };
    };//内含语句:this.prototype = {};
    
    var fun = new Fun();//内含语句:this.__proto__ = Fun.prototype;
    

     

原型

由上面的描述,我们来分析上面的代码:

1.函数定义时,在栈内存中开辟一块内存,变量名为Fun,Fun保存着函数对象在堆内存的地址。

2.堆内存的函数对象自动生成一个prototype属性,指向一个Object空对象。

3.当实例化Fun函数时,在栈内存中开辟一块内存,变量名fn,存放实例对象在堆内存中的地址。

4.实例对象fun自动生成__proto__属性,同样指向空Object对象。

5.通过显示原型给空Object对象添加方法:Fun.prototype.test = function(){alert("test")};

即:实例对象的隐式原型指向构造函数对象的显式原型

如下图所示:

 

原型链

我们知道,JS内置Object构造函数,那么Object构造函数是否也有prototype属性呢?答案是肯定的。我们可以输出它的原型对象看一看:

由图可知Object函数的原型对象中有许多内置函数。

当我们定义一个函数时,同时也实例化了一个Object空对象,那么这个Object空对象也是一个实例对象,自然也有__proto__属性,它的__proto__和它的构造函数(也就是Object函数)的prototype指向同一个对象,也就是Object原型对象。

所以说,通过空Object对象的__proto__属性,我们就将自定义的函数和内置的Object函数联系起来了,通过隐式原型(__proto__)我们构造出了一条原型链。

        function Fun(){
            this.test1 = function(){
                console.log('test1');
            }
        }
        Fun.prototype.test2 = function(){
            console.log("test2");
        }
        var fun = new Fun();
        
        fun.test1();
        fun.test2();
        console.log(fun.toString());
        fun.test3()
        console.log(Object.prototype);
        

首先,定义Fun函数,函数内定义了一个test1属性,属性值是一个函数。再通过显式原型为Fun的Object空对象中添加test2函数。toString()函数是Object函数的原型函数的内置函数。

fun.test1():

实例化Fun后,调用实例对象的test1属性,加括号test1()则调用test1函数,输出test1

fun.test2():

fun调用test2函数,但是fun实例对象中并没有test2函数,于是沿着fun的__proto__属性向上寻找,在Object空对象中找到test2函数,调用执行

fun.toString()

fun调用toString函数,fun实例中没有这个函数,沿着fun的__proto__来到Object空对象,还是没有,沿着Object空对象的__proto__属性来到Object原型对象,找到toString函数,调用执行

fun.test3():

首先我们来思考一个问题,Object原型对象,也是一个实例对象,那么它也应该具有__proto__属性,那么它的__proto__属性指向哪里呢?不妨输出试试看:

可以看到指向null,那么至此原型链走到了末尾,如果到这里还找不到要的属性,那么就是真的找不到了

fun调用test3函数,fun实例中没有这个函数,沿着fun的__proto__来到Object空对象,还是没有,沿着Object空对象的__proto__属性来到Object原型对象,还是找不到,沿着Object原型对象的__proto__来到null,说明没有test3这个函数,报错:Uncaught TypeError: fun.test3 is not a function

上面的过程可以用下图辅助理解:

附:

1.自定义函数,也是Function()的一个实例 function fun = function(){};等价于 var fun = new Function(); fun = function(){};

2.所以自定义的函数也有__proto__属性,指向Function的显式原型,即:Fun.__proto__=Function.prototype.所有自定义函数的__proto__都相等

3.再往前追溯,内置函数Object,一开始也是function Object()这样定义的,所以说Object函数也是Function的实例,Object.__proto__ = Function.prototype;

综上所述,原型链从实例函数对象触发,到Object原型对象停止,形成了自定义函数和内置函数的联系,又因为是通过__proto__这一隐式原型实现的,所以原型链又称为隐式原型链。

以上就是我个人对原型和原型链的理解,如果有不对的地方还请大家指出~

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值