__proto__与prototype的区别

首先我们需要明白,__proto__属性是对象独有的,而prototype是函数独有的属性。而在js里万物皆为对象,包括function,所以function也具有__proto__属性。

为了方便理解,我们举一个例子(使用构造函数的方法创建一个数组)

此时可以看到,在a的属性里,有一个名为__proto__的属性。我们访问这个属性:

 

得到的是属于数组的一些方法,也就是说,__proto__这个属性指向的是对象的构造函数。当我们展开看,又会发现:

 

 返回结果里还有着一个__proto__属性,而这次指向的构造函数是object()

其实,__proto__的作用简单来说就是继承。

在上述这个过程中,我们其实看到了一条原型链。a--Array()--Object()

 

接着我们访问a的一个属性:

 

 a的构造函数是数组,但数组的方法里没有valueOf属性,那为什么a.valueOf不会报错呢?

是__proto__帮我们解决了问题。__proto__的作用就是指向它的原型对象,也就是通俗来说的父对象。当我们访问一个对象的属性时,对象内没有这个属性,那么就会访问__proto__指向的父对象,若父对象也没有则会继续向上查找,直到顶端null。这就是原型链。

 

搞清了__proto__,那么prototype是什么呢?

上面已经说到,prototype是函数特有的属性。它是从函数指向一个对象,它的涵义是函数的原型对象。也就是这个函数所创建出来的实例的原型对象。

为了方便理解我们同样定义一个函数:

 

 我们将foo作为构造函数创建一个新的函数。

 

 

重头戏来了:

 

 我们就知道这两个属性的相似之处,那么prototype的作用是什么呢?

它的作用就是包含可以由特定类型的所有实例共享的属性和方法,也就是让该函数所实例化的对象们都可以找到公用的属性和方法。任何函数在创建的时候,其实会默认同时创建该函数的prototype对象。

也就是说,prototype属性给所有实例化出来的函数对象提供了可以公共访问的属性和方法。举一个最直观的例子。

 

 我们给foo函数内部定义一个属性,而我们再用f1访问此属性时:

 

 

 f1是以foo为构造函数创建出来的实例,所以f1理所当然的可以访问foo函数通过prototype属性共享的属性和方法。

 

这就是在我们学习数据结构时的封装方法。理解了这两个属性的作用我们可以轻易的理解框架的基础原理。

 

弄懂了这两个属性,我们再说说上述中频频出现的构造函数。

什么是构造函数呢?

其实任何函数都可以当作构造函数,当把一个函数当作构造函数时,它的调用方法和作用便与普通函数不同了。

普通函数只需在标识符后加()即可调用,但调用构造函数需要在前面加上new操作符。

创建构造函数时一般首字母大写以示区分。

构造函数的执行流程:

在堆内存里创建一个新的对象、将新建的对象设置为函数内的this、逐个执行函数中的代码、将新建的对象作为返回值。

但从constructor这个属性来讲,只有prototype对象才有这个属性,但通过上述我们可以得知,通过构造函数实例化出来的对象可以从父元素继承属性和方法。所以

 

------------恢复内容开始------------

首先我们需要明白,__proto__属性是对象独有的,而prototype是函数独有的属性。而在js里万物皆为对象,包括function,所以function也具有__proto__属性。

为了方便理解,我们举一个例子(使用构造函数的方法创建一个数组)

此时可以看到,在a的属性里,有一个名为__proto__的属性。我们访问这个属性:

 

得到的是属于数组的一些方法,也就是说,__proto__这个属性指向的是对象的构造函数。当我们展开看,又会发现:

 

 返回结果里还有着一个__proto__属性,而这次指向的构造函数是object()

其实,__proto__的作用简单来说就是继承。

在上述这个过程中,我们其实看到了一条原型链。a--Array()--Object()

 

接着我们访问a的一个属性:

 

 a的构造函数是数组,但数组的方法里没有valueOf属性,那为什么a.valueOf不会报错呢?

是__proto__帮我们解决了问题。__proto__的作用就是指向它的原型对象,也就是通俗来说的父对象。当我们访问一个对象的属性时,对象内没有这个属性,那么就会访问__proto__指向的父对象,若父对象也没有则会继续向上查找,直到顶端null。这就是原型链。

 

搞清了__proto__,那么prototype是什么呢?

上面已经说到,prototype是函数特有的属性。它是从函数指向一个对象,它的涵义是函数的原型对象。也就是这个函数所创建出来的实例的原型对象。

为了方便理解我们同样定义一个函数:

 

 我们将foo作为构造函数创建一个新的函数。

 

 

重头戏来了:

 

 我们就知道这两个属性的相似之处,那么prototype的作用是什么呢?

它的作用就是包含可以由特定类型的所有实例共享的属性和方法,也就是让该函数所实例化的对象们都可以找到公用的属性和方法。任何函数在创建的时候,其实会默认同时创建该函数的prototype对象。

也就是说,prototype属性给所有实例化出来的函数对象提供了可以公共访问的属性和方法。举一个最直观的例子。

 

 我们给foo函数内部定义一个属性,而我们再用f1访问此属性时:

 

 

 f1是以foo为构造函数创建出来的实例,所以f1理所当然的可以访问foo函数通过prototype属性共享的属性和方法。

 

这就是在我们学习数据结构时的封装方法。理解了这两个属性的作用我们可以轻易的理解框架的基础原理。

 

弄懂了这两个属性,我们再说说上述中频频出现的构造函数。

什么是构造函数呢?

其实任何函数都可以当作构造函数,当把一个函数当作构造函数时,它的调用方法和作用便与普通函数不同了。

普通函数只需在标识符后加()即可调用,但调用构造函数需要在前面加上new操作符。

创建构造函数时一般首字母大写以示区分。

构造函数的执行流程:

在堆内存里创建一个新的对象、将新建的对象设置为函数内的this、逐个执行函数中的代码、将新建的对象作为返回值。

但从constructor这个属性来讲,只有prototype对象才有这个属性,但通过上述我们可以得知,通过构造函数实例化出来的对象可以从父元素继承属性和方法。所以不严格来讲,基本所有的对象都具有constructor属性。

函数在创建时,JS会为该函数创建一个对应的prototype对象,而这个prototype对象的constructor属性又指向该函数,即Foo.prototype.constructor === Foo

posted @ 2020-11-15 14:09  Treee  阅读(1470)  评论(0)    收藏  举报