• 解析对象原型链


    1.你了解对象吗?

    本文结合基本javascript的权威书籍中的内容,根据自己的理解,通过相关示例向大家展示了对象,原型及原型链的基本内容,希望大家能够喜欢,如有不足,也希望提出建议,大家共同进步。

    虽然说在javascript中所有一切都是对象,这不假,但是对象和对象还是不一样的,产生对象的方法有这几种。

    1)直接通过new Object生成“名正言顺”的对象实例。这个对象实例将继承所有来自Object 对象的属性和方法,其中Object.prototype是最顶端的原型对象。

    2)通过编写构造函数,然后再new一个自定义函数。​这个也不难理解,系统给的毕竟有些属性和方法不是符合程序员的心意,所以会自定义一个函数,其声明方法就和声明一个函数一样。

    function Foo(){

    this.i =0;

    }//这个函数现在可以称作构造函数了吗?其实不然,判断是构造函数还是普通函数,不能只看函数名的首字母是否大写,而是要看调用的时候,是那种方式调用,如果是以new的方式,那才是构造函数,这样才可以拿着这个构造函数愉快的创建以它为模板的对象实例。方法和用new Object一样,var foo = new Foo();

    这样一个构造函数就变成了对象模板。

    这就是那句老话,js里所有都是对象,函数是对象,对象是对象,而js又是函数编程,基本脱离不了函数(对象)。

    ​有了这个基础,我们再来看看js这个活雷锋帮我们内置了什么功能强大的东东吧!

    js有很多内置构造函数,他将常用的方法属性封装好放入构造函数里,这个构造函数都是可以直接调用,例如Math,他是一个包含很多数学方法的构造函数,使用的时候可以Math.ceil(6.3)//向上取整​,

    var tt = new Date();//取当前系统时间。原生函数的行为是ECMAScript标准规定的(函数对象的[[Construct]]),由JS引擎负责实现标准。同一原生的构造函数,是否通过 new关键字调用可能具有不同的行为(如Date、String、Boolean、Number函数),也可能具有相同行为(如Object、 RegExp、Array)。有的原生构造函数必须使用new关键字(如Promise、Proxy、Set、Map、ArrayBuffer),也有的 一定不能使用new关键字(如Symbol)

    2.原型的理解

    ​首先,最重要的就是要知道,原型也是一个对象,因为在JS中万物皆对象。很多人对这句话不是很能理解,我是这样的理解的,在JS中任何方法的原型都最终都可以指向对象的原型,这也是很重要的原型链的问题说到原型,我们要扯一下为什么要有原型这个东西,俗话说的好,所有的事物不会凭空产生。原型诞生的​意义就是可以实现代码复用。

    我们平时生成的对象基本都是通过构造函数实现的,既然是通过构造函数实现,那么就​

    function Fn(){

    this.i=0;

    this.n=1;

    this.a=function(){

    return 15;

    }​

    }​

    var fn1 = new Fn();

    var fn2 = new Fn();

    好,我们已经通过Fn() 这个构造函数生成了两个对象实例,不用猜每个对象实例中都有一套构造函数里的内容,如果fn1 不需要这些属性呢?这是什么?浪费内存啊,这是在作死啊!

    我们每new一个Fn就相当于说你在内存中又开辟了一块地方存储了Fn里的所有属性和方法。所以呢,原型应运而生。

    原型出现的目的就是把需要共享的​​属性方法放到一个对象里,这个对象就是原型(对象)。

    既然我们知道了原型的来历和本质,我们再来探究一下原型和构造器的联系。​

    我们通过prototype属性可以为任意一个构造函数添加原型属性和方法:

    ​function Foo2(){

         this.i = 1;

    }

    Foo2.prototype.m = 0;​//prototype属性就是一个可以让构造函数往原型中添加属性方法的方法。

    var foo2 = new Foo2();​

    这样就把m属性加入到构造函数Foo2的原型中去。

    m并没有在Foo中定义,但是通过new关键字生成的foo2仍然可以访问m,充分说明有一个机制让实例去在构造函数之外继续搜索m这个变量,而这个函数 之外的区域就是原型对象。机制:当实例想要访问一个变量的时候,他会首先搜索本身是否有,没有就去搜索他的原型对象,如果还没有呢?继续向上,搜索原型链的 上游,直到找到原型链的最顶端,如果还没有,就返回undefined

    这个图就充分说明了变量的搜索机制。

    3.ECMAscript中的内置构造函数的本质是什么?

    ​内置的构造函数例如(Array Date String等等),他其实和普通的构造函数一样,也是内部通过function Array(){}生成的。那他本质上也是一个函数。

    4.原型链是什么?

     对于那些熟悉基于类的面向对象语言(Java 或者 C++)的开发者来说,JavaScript 的语法是比较怪异的,这是由于 JavaScript 是一门动态语言,而且它没有类的概念( ES6 新增了class 关键字,但只是语法糖,JavaScript 仍旧是基于原型)。

    涉及到继承这一块,Javascript 只有一种结构,那就是:对象。在 javaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向),组成这条链的最后一环。这种一级一级的链结构就称为原型链(prototype chain)

    5.构造函数和原型的关系?

    构造函数里有一个属性prototype,这个属性里面存储着它原型对象的指针。这样构造函数就能找到原型对象。​反过来,原型对象也有一个属性,constructor。这个属性指向构造函数的指针。这样就可以互相“认识”。

    6.通过构造函数生成的实例对象与原型的关系?

    在JS中任何方法(函数)都有一个__proto__属性,它指向构造它的函数的原型对象,也就是:实例.__proto__===function.prototype。

    7.__proto__是什么?​

    ​在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此,它们都会具有对象共有的特点。即:对象具有属性__proto__,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。__proto__和prototype之间的关系或区别是什么,如下图所示?

    (Function)方法这个特殊的对象,除了和其他对象一样有上述_proto_属性之外,还有自己特有的属性——原型属性(prototype), 这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做 constructor,这个属性包含了一个指针,指回原构造函数。 
    下面是另一种写法

    上图中的知识点:

    1.构造函数Foo()构造函数的原型属性Foo.prototype指向了原型对象,在原型对象里有共有的方法,所有构造函数声明的实例(这里是f1,f2)都可以共享这个方法。

    2.原型对象Foo.prototypeFoo.prototype保存着实例共享的方法,有一个指针constructor指回构造函数。

    3.实例f1和f2是Foo这个对象的两个实例,这两个对象也有属性__proto__,指向构造函数的原型对象, 这样子就可以像上面1所说的访问原型对象的所有方法啦。另外:构造函数Foo()除了是方法,也是对象,它也有__proto__属性,指向谁呢?指向它的构造函数的原型对象。函数的构造函数不就是Function吗,因此这里的__proto__指向了Function.prototype。其实除 了Foo(),Function(), Object()也是一样的道理。原型对象也是对象,它的__proto__属性,又指向谁呢?同理,指向它的构造函数的原型对象。最终都指向Object.prototype也是原型链的最顶端.最后,Object.prototype的__proto__属性指向null。

    总结:

    1.对象都有属性__proto__,指向该对象的构造函数的原型对象。

    2.方法(函数)除了有属性__proto__,还有属性prototype,prototype指向该方法(函数)的原型对象。

    3.任何原型对象都有个constructors属性,constructor指向该方法(函数)本身。

    4.基本类型所拥有的属性和方法,都是继承自Date、String、Boolean、Number函数,它们又继承自Function。

    5.__proto__是站在对象的角度讨论原型对象。

    6.prototype是站在构造函数的角度讨论原型属性,或构造函数创建的对象的原型对象。​

  • 相关阅读:
    Google V8编程详解(四)Context
    Google V8编程详解附录
    Google V8编程详解(三)Handle & HandleScope
    Google V8编程详解(二)HelloWorld
    Google V8编程详解(一)V8的编译安装(Ubuntu)
    Google V8编程详解(序)Cloud App
    makefile:2: *** 遗漏分隔符 。 停止
    HTTP协议各个参数详解
    java&android知识点汇总整理(不定期更新)
    错误一览表
  • 原文地址:https://www.cnblogs.com/lbweb/p/5914225.html
Copyright © 2020-2023  润新知