javascript 之 原型链(推导过程)

前言:在学这个的时候,听课,画图,查资料,但是越听越糊涂,主要是之前学的没有总结.没有对每个小知识点进行归纳总结.

在了解什么是原型链前,出一个题目,后面会根据这道题来说明什么是原型链.

 

学习建议:无论学什么知识点:语言的严谨很重要,否则概念混乱就会导致看不懂

function F() {
        Object.prototype.a = function () {
          console.log("a()");
        };
        Function.prototype.b = function () {
          console.log("b()");
        };
      }
请问以下分别为什么值.答案在文章最后揭晓.
     var f = new F();
      f.a(); //
      f.b(); //
      F.a(); //
      F.b(); //
 

 

疑问回答:

1/"函数"和"方法"有区别吗?
function a(){} //这叫函数 var obj={ name:"张三", getName:function(){ //这叫方法 } }

总结:在对象内部的函数叫方法,所以可以不用纠结 叫"函数"还是"方法",统一称为"函数"没错,称为方法也没错,但是还是要严谨一点.

2/什么时候是对象,什么时候是属性,什么时候是函数?
分析:主要看在什么位置.
除了基本数据类型(string,number,boolean,undefined,null),其他的Object, Function(一种特别的对象) Array都是对象
var a={ //a是对象
  name:"张三", //name是a的属性
getName:{ //这里的getName 可以说是a的属性,也可以说是a的方法,也可以说是a的函数,也叫对象
   return name;
}
}
3/实例是函数吗?
案例:
let F=function();
F.prototype.getName=function(){}
let f=new F();
typeof f //'object'
typeof F //'function'
答:实例是通过构造函数创建出来的对象,所以 实例是对象,而对象不一定是函数. 函数一定是对象.
具体分析:
1\首先我们知道f实例化F后,F.prototype成为了f的对象成员,所以f._proto_=F.prototype
2\定义:每个函数都有一个prototype.
但是实例没有prototype,所以实例不是函数.
3\F是Function的一个实例,而Function是一个函数,它的实例F也是一个函数 请结合第4点和第六点来看 更重要的是第七点

4/
对象和原型链 这个太重要了|||太重要了|||太重要了|||
 先了解: Object和Function的关系
先有Object.prototype,
然后构造出
Function.prototype
再构造出
Object和Function

(1)Object对象是由Function函数的原型创建的
Object._proto_ === Function.prototype

(2)Object的原型对象指向空
Object.prototype._proto_===null

(3)Function对象是由他自己本身创建的
Function._proto_ === Function.prototype

(4)其他的普通对象最终指向的都是Object
Function.prototype._proto_ === Object.prototype

5.针对第4点,想知道prototype是怎么解释的
  1\在JavaScript中,prototype对象是实现面向对象的一个重要机制。
2\每个函数就是一个对象(Function),函数对象都有一个子对象 prototype对象,类是以函数的形式来定义的。prototype表示该函数的原型,也表示一个类的成员的集合。
3\在通过new创建一个类(构造函数)的实例对象的时,prototype 对象的成员都成为实例化对象的成员.(注:请在console中输出第3点的F.prototype)

6.
js的内置函数
Object,Number,Boolean, String,Array ,RegExp, Date,Function,Error,Math,Json等都是内置函数,其中Math,Json是以对象形式存在,无需new便可使用
原型是Function.prototype:
Object,Number,Boolean, String,Array ,RegExp, Date,Function
原型是Object.prototype: Math,Json.


第七点:为什么var fn=new Function(),function Fn=new Function(){} 有prototype属性呢? 很重要!很重要!很重要!!!
原理:
function Function() Function也是一个函数对象,也有__proto__属性,既然是函数,那么它一定是被Function创建,所以Function是被自身创建的,所以它的__proto__指向了自身的Prototype:

   

这个问题的由来:
 function A(){} 
 var a=new A(){} 

注意哦:
  function b=new Function(){}
  funbtion c=new b()
以上两种是一样的,都被实例化了,所以A,b都是构造函数

在后续的结论中:普通对象的原型指向的是Object.prototype
分析:按照上面的 a,c都是实例对象,而普通对象都没有prototype,只有_proto_
问题来了:A 是Function的实例,那为什么A拥有prototype呢?
我的理解: Function 和Object都是Function.prototype创建的,参考上面的原理,Function 相当于是 function Function得到的
同理:function F 不就相当于 function Function. 所以: 我们平时写的函数其实都是 Funnction自身创建的.这也就说明了为什么上述问题的原因

    第五点:参考:https://baike.baidu.com/item/prototype/14335187?fr=aladdin    :标题:js的prototype

    第四点参考:https://www.cnblogs.com/panrui1994/p/9396935.html                标题JS:对象与原型

                       https://zhuanlan.zhihu.com/p/66446619                                      标题:Object和Function的鸡与蛋的思考

    第三点参考:https://blog.csdn.net/qq_36711388/article/details/90346459     标题:实例化的对象没有prototype属性

   第三点参考:https://www.cn  blogs.com/jtnote/p/5980000.html                         标题:函数的各种写法

     

 

 

一.什么是构造函数?

  1\构造函数的函数名首字母大写,用来与普通函数区分

  2\构造函数通过 new关键字来调用

  3\构造函数中的this指向整个构造函数,而普通函数中的this指向window(此处可忽略,后面会补充)

 思考:

function a(){}   //只有这一行时,a是普通函数
var a1=new a();  //添加这一句代码后,此时a就是构造函数 
结论:只有当使用new关键字,或者是大写时,才能确认是构造函数.

 

二. 原型

 现象:

function F(){}
function a(){}
这两个函数都有prototype属性 和 _proto_属性

var f=new F()
var a1 =new a();
这两个实例只有_proto_属性 没有 prototype属性

 

 重点: 原型分为显式原型(prototype) 和 隐式原型(_proto_).

 (一):显式原型(prototype)

    特点:

   1.每个函数function都有一个prototype

       分析:实例可以是函数,

   2.在定义函数时自动添加的默认值,prototype指向一个空的Object  (看分析,还是有问题,需要理解)

      如何分析:(请参考"疑问回答"第四点,解释:prototype是对象,对象都有一个隐式原型_proto_,于是这个隐式原型指向为空.

                      于是想当然以为let f=functon(){} ,这也是定义函数啊,那f.prototype._proto_肯定也是空,结果不是为null. 唯一得到的准确结果是
                      Object.prototype._proto_    ) 

   3.prototype有一个属性constructor(函数指针), 指向函数对象(后面会讲到constructor的知识)

    4.用来查找对象的属性(方法也是属性的一种)

     

var F=function(){}

 

(二):隐式原型(_proto_)

    特点:

    1.每个实例对象都有一个_proto_

        这句变更为:每个对象都存在着一个隐藏的属性"_proto_"

    2.所有函数的_proto_都是一样的,因为函数都是new Function()构造器产生的.

    3.对象(函数)的隐式原型 等价 对应构造函数的显式原型 即: 

let F=function(){}
let f=new F();
f._proto_ = F.prototype

     4.原型链是沿着_proto_查找的

 (三):扩展:

      在ES6之前,程序员可以直接操作prototype,但是不能操作_proto_的

 

答案:

  理解一下:概念 (注意:请将所有标红的地方看一遍)
 f.a() f是F的实例,所以f._proto_ === F.prototype ,然后只能找到 F.prototype._proto_===Object.prototype ,这里有一个操作,无论输入啥,都没有找到其他任何对象===Object.prototype   结论:普通对象的原型都指向Object.prototype(原型)
 f.b() 找不到.  f是对象,所以f._proto_ ====F.prototype
 F.a() F是函数,它对应的构造函数是Function的prototype,那么F._proto_===Function.prototype
      然后Function.prototype 是由 Object.prototype创建的,所以Function.prototype._proto_===Object.prototype ,所以能找到,所以能够找到
 F.b() F是函数,它对应的构造函数是Function的prototype 所以能够找到

 

 

//2021年 11月 5日,又有了新的感悟

提要:

1/每个实例都只有隐式原型

2/普通对象的原型都指向Object.prototype

 

posted @ 2019-08-12 11:38  zmztyas  阅读(206)  评论(0编辑  收藏  举报