zoukankan      html  css  js  c++  java
  • 原型链

    引入从Object和Function开始

    Object和Function都作为JS的自带函数,Object继承自己,Funtion继承自己,Object和Function互相是继承对方,也就是说Object和Function都既是函数也是对象。

    1
    2
    console.log(Function instanceof Object); // true
    console.log(Object instanceof Function); // true

    Object 是 Function的实例,而Function是它自己的实例

    1
    2
    console.log(Function.prototype); // ƒ () { [native code] }
    console.log(Object.prototype); // Object

    普通对象和函数对象

    JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象,Object 、Function 是 JS 自带的函数对象。下面举例说明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    var o1 = {}; 
    var o2 =new Object();
    var o3 = new f1();

    function f1(){};
    var f2 = function(){};
    var f3 = new Function('str','console.log(str)');

    console.log(typeof Object); //function
    console.log(typeof Function); //function

    console.log(typeof f1); //function
    console.log(typeof f2); //function
    console.log(typeof f3); //function

    console.log(typeof o1); //object
    console.log(typeof o2); //object
    console.log(typeof o3); //object

    在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 New Function()创建的。

    函数原型:

    在理解原型之前有两句很重要的话:

    1、每一个函数对象都有一个prototype属性,但是普通对象是没有的;
    prototype下面又有个construetor,指向这个函数。
    2、每个对象都有一个名为proto的内部属性,指向它所对应的构造函数的原型对象,原型链基于proto;

    prototype属性

    每个函数都有prototype属性,默认指向一个Object空对象(称为:原型对象)

    1
    2
    3
    function Foo() {
    }
    console.log(Foo.prototype) //constructor __proto__

    函数原型链
    这里为什么要说是空对象,明明看到有constructor、__proto__两个属性,其实是这个Object对象中没有我们所需要的属性,当然可以去向原型中添加我们需要属性或者方法。

    尝试给原型对象添加属性(一般都是方法)

    1
    2
    3
    4
    Foo.prototype.method=function () {
    console.log("method()")
    }
    console.log(Foo.prototype)

    此时在原型中可以看到method属性已经添加到Foo()中去了。
    函数原型链
    现在我们通过创建实例去访问我们刚才添加的方法

    1
    2
    var fun=new Foo()
    fun.method() // 可以看到返回的是method()

    可以看到构造函数跟原型对象是相互引用的关系。

    这里需要区分显示原型和隐式原型

    每个函数function都有一个prototype,即显示原型(属性)
    每一个实例对象都有一个__proto__ 称为隐式原型(属性)
    我们继续之前的构造函数:

    1
    2
    3
    4
    5
    var fun=new Foo() 
    console.log(fun.__proto__)
    //对象的隐式原型的值为其对应构造函数的显示原型的值
    console.log(Foo.prototype===fun.__proto__)//true
    fun.method() // 可以看到返回的是method()

    可以看到对象的__proto__属性在创建对象时是自动添加的,默认值为构造函数的prototype属性值。

    constructor(构造函数)

    在原型对象中有一个属性constructor,当我们自定义构造函数之后,其原型对象只会默认取得constructor值,可以通过该属性判断出实例是由哪个构造函数创建的。

    1
    console.log(fun.prototype.constructor===Foo)  //true

    那么构造函数的原型对象是由什么来创建的呢?

    我们去构造函数中寻找:

    1
    Foo.prototype.__proto__.constructor // ƒ Object() { [native code] }

    这样一来可以看到构造函数原型链的其他方法,原来是从Object 上继承来的。
    这里的Object本来就存在,此时我们可以追溯到它的原型链。

    原型链

    原型链(本质上就隐式原型链,是用来查找对象的。)
    函数原型链
    在创建函数之前,已经就有了一个Object函数对象,js在加载引擎的时候首先会把这个内置的函数加载进来,然后在去执行我们的一些方法,访问一个对象的属性时,先从自身属性中查找,找到返回,如果没有,再沿着__proto__这条链上查找,找到返回,如果最终没找到,返回undefined。

    注意事项:

    1. 函数的显示原型指向的对象默认是Object实例对象(但是Object不满足)

      1
      2
      3
      console.log(Fn.prototype instanceof Object)  //true
      console.log(Object.prototype instanceof Object) //false
      console.log(Function.prototype instanceof Object) //true
    2. 所有函数都是Function的实例

      1
      console.log(Function.__proto__===Function.prototype)  //true
    3. Object的原型对象是原型链的尽头

      1
      console.log(Object.prototype.__proto__) //null
    4. (1)读取对象的属性值时,会自动到原型链中查找
      (2)设置对象的属性时,不会查找原型链,如果当前对象中没有此属性,直击添加属性并设置其值
      (3)方法一定定义在原型中,属性一般通过构造函数定义在对象本身上,

      1
      2
      3
      4
      5
      6
      7
      8
      9
      function Fn() {
      }

      Fn.prototype.a = 'xxx';
      var fn1 = new Fn()
      console.log(fn1.a, fn1)//xxx
      var fn2 = new Fn()
      fn2.a = 'yy'
      console.log(fn2.a, fn2) //yy

    原型链属性问题

    一般情况下,我们会将属性直接添加在函数中,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    function Person(name, age) {
    this.name = name;
    this.age = age
    }

    Person.prototype.setName=function (name) {
    this.name = name
    }

    var p1 = new Person('tom', 12)
    p1.setName('bob')
    console.log(p1)


    var p2 = new Person('errol', 12)
    p2.setName('charlie')
    console.log(p2)

    方法问题

    可以看实例对象的隐式原型等于构造函数的显示原型,它们都构造函数都是指向的是Person,所以它们的proto都是相等的。

  • 相关阅读:
    iOS -- @try
    javaScript学习
    iOS -- js与原生交互
    iOS -- WKWebView
    iOS -- UIWindow的使用
    iOS -- app生命周期中代理方法的应用场景
    iOS -- keyChain
    UISegmentedControl
    明天你好
    编程:是一门艺术(转)
  • 原文地址:https://www.cnblogs.com/weigaojie/p/10546557.html
Copyright © 2011-2022 走看看