美文网首页Web前端之路让前端飞
JavaScript原型对象和原型链

JavaScript原型对象和原型链

作者: 卓三阳 | 来源:发表于2017-11-08 21:55 被阅读77次

    理解JS原型链是一件比较令人头疼的使。要彻底搞清楚原型链,我们先来搞清楚对象。
    我们可以把对象分为普通对象和函数对象。
    普通对象:有_ proto _属性(指向其原型链),没有prototype属性。
    函数对象:通过 new Function() 创建的对象都是函数对象;拥有 _ proto _、prototype属性(指向原型对象);

    对于新手,看完上面的介绍可能会有一点模糊,我们这里总结为一句话:_ proto _是每个对象都有的属性,prototype是函数对象才有的属性。关于_ proto _和prototype的区别我们下面将会介绍。

    1._ proto _和prototype的区别

    _ proto _(隐式原型)

    JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个内置属性,但是大多数浏览器都支持通过_ proto _来访问。 _ proto _指向创建这个对象的函数(constructor)的原型对象 。

    prototype(显式原型)

    每创建一个函数都会有一个prototype属性(自动),这个属性是一个指针,指向一个对象,这个对象就是原型对象。原型对象是包含特定类型的所有实例共享的属性和方法。

    大家可能还是没有搞懂,没关系,我从网上找了一幅图,对于大家理解很有帮助。


    原型链.jpg

    这里我们看到原型对象都有一个constructor

    在 Javascript 语言中,constructor 属性是专门为 function 而设计的,它存在于每一个 function 的prototype 属性中。这个 constructor 保存了指向 function 的一个引用。

    当我们定义一个函数

    function test(){
    
    }
    

    JavaScript 内部会执行如下几个动作
    (1) 为该函数添加一个原型(即 prototype)属性
    (2) 为 prototype 对象额外添加一个 constructor 属性,并且该属性保存指向函数test的一个引用

    当我们把函数 test 作为自定义构造函数来创建对象的时候,对象实例内部会自动保存一个指向其构造函数(test)的 prototype 对象的一个属性_ proto _,所以我们在每一个对象实例中就可以访问构造函数的 prototype 所有拥有的全部属性和方法,就好像它们是实例自己的一样。当然该实例也有一个 constructor属性了(从 prototype 那里获得的),每一个对象实例都可以通过 constrcutor 对象访问它的构造函数,请看下面代码:

    var t= new test();
    alert(t.constructor === test); // true
    alert(t.constructor === test.prototype.constructor);//true
    

    constructor 的出现原本就是用来进行对象类型判断的,但是 constructor 属性易变,不可信赖。我们有一种更加安全可靠的判定方法:instanceof 操作符。

    2.原型链

    由于_ proto _ 是任何对象都有的属性,而js中万物皆对象,所以会形成一条 _ proto_连接起来的链条,递归访问到_ proto _最终值为null。当js引擎查找对象的属性时,先查找对象本身是否存在该属性,如果不存在,会在原型链上查找。

    综合上面所述,我个人的理解如下:

    • 作用
      _ proto_ :构成原型链,用于实现基于原型的继承
      prototype: 用来实现基于原型的继承与属性的共享,可以让所有实例对象共享它所包含的属性和方法

    • 两者之间关系
      _ proto_ 指向创建这个对象的函数(constructor)的prototype
      即_ proto _ ===constructor.prototype

    • 应用
      给原型对象增加方法,属性,就是让对象拥有公用的方法,属性。

    //给数组原型增加一个打乱数组的函数
    Array.prototype.shuffle=function(){
    var value = this.valueOf(),len = this.length,temp,key;
    while(len--){
    //随机生成数组的下标
    key = Math.floor(Math.random()*len);
    //temp为中间交换变量
    temp = value[key];
    value[key] = value[len];
    value[len] = temp;
    }
    return value;
    }
    var arr1 = [0,1,2,3,4,5,6,7,8,9];
    var arr2 = ['a','b','c','d','e','f'];    
    alert(JSON.stringify(arr1.shuffle()));
    alert(JSON.stringify(arr2.shuffle()));
    

    我们知道 JS 内置了一些方法供我们使用,比如:
    对象可以用 constructor/toString()/valueOf() 等方法;
    数组可以用 map()/filter()/reducer() 等方法;
    数字可用用 parseInt()/parseFloat()等方法;
    其原因就是这些对象继承了其构造函数的原型对象的结果。

    相关文章

      网友评论

        本文标题:JavaScript原型对象和原型链

        本文链接:https://www.haomeiwen.com/subject/mhvymxtx.html