美文网首页
JS三座大山之原型和原型链

JS三座大山之原型和原型链

作者: 我向你奔 | 来源:发表于2018-02-10 00:34 被阅读91次

    构造函数

    提到原型就不得不说一下构造函数,我们先来看一个简单的构造函数的例子:

    function  Foo (name,age) {
        this.name = name;
        this.age = age;
        //return  this;
    }
    var f = new Foo ("zhangsan",20);
    var f1 = new Foo ("lisi",21);          //创建多个对象
    

    需要说明的是:① 构造函数需以大写字母开头,这样提高了代码的易读性;② return this 那句可有可无,因为它是默认存在的。
    在上面的例子中,我们首先创建了一个空对象,再让this指向这个对象,然后执行代码,即给this.name赋值,最后返回this,并将值赋给f和f1。这其实也是new一个对象的过程。
    在这里我们稍稍拓展一下构造函数的知识:
    ① 所有的引用类型都有构造函数
    var a = {}其实是var a = new object()的语法糖
    var b = []其实是var b = new Array()的语法糖
    function Foo() {....}其实是var Foo = new Function()的语法糖
    在实际写代码中,我们更推荐使用前者的写法
    ② 可以使用instanceof判断一个函数是否是一个变量的构造函数,例如

    var a = new Array()
    alert (a instanceof Array)    // true
    

    同时alert (a instanceof Object)也会返回true,这是因为Array是object的子类。再如

    function Test () {}
    var a = new Test()
    alert (a instanceof Test)      // true 
    

    什么是原型呢?

    原型就是一个普通的对象,每个对象都有一个原型(Object除外),原型能存储我们的方法,构造函数创建出来的实例对象能够引用原型中的方法。

    Javascript中所有的对象都是Object的实例,并继承Object.prototype的属性和方法,有些属性是隐藏的。换句话说,在对象创建时会存在预定义的属性,其中有一个属性就是原型对象。
    下面,我们来说说原型规则:
    ① 所有的引用类型(数组,对象,函数)都具有对象特性,即可自由扩展属性(除了“null”)

    var obj = {};
    obj.a = 100;
    var arr = [];
    arr.a = 100;
    function fn1 () {}
    fn1.a = 100;
    

    ② 所有的引用类型(数组,对象,函数)都有一个_proto_(隐式原型)属性,属性值也是一个普通的对象

    console.log(obj.__proto__);
    console.log(arr.__proto__);
    console.log(fn1.__proto__);
    

    ③ 所有的函数,都有 一个prototype(显式原型)属性,属性值也是一个普通的对象

    console.log(fn1.prototype);
    

    ④ 所有引用类型(数组,对象,函数)的_proto_属性值指向它的构造函数的prototype属性值

    console.log(obj.__proto__ === Object.prototype);        
    console.log(arr.__proto__ === Array.prototype);   
    console.log(fn1.__proto__ === Function.prototype);    
    

    ⑤ 当试图得到一个对象的属性时,如果这个对象本身没有这个属性,那么就会去它的_proto_(即构造函数的prototype)中寻找

    //构造函数
    function Foo(name) {
        this.name = name;
    }
    Foo.prototype.alertName = function () {
        alert(this.name);
    }
    //创建实例
    var f = new Foo("xiaohui");
    f.printName = function () {
        console.log(this.name);
    }
    //测试
    f.printName();
    f.alertName();
    

    就刚才的例子,如果想要循环得到对象本身的属性可以通过for in 实现

    var item;
    for (item in f) {
        //高级浏览器已经在for in中屏蔽了来自原型的属性
        //但是还是加上判断,保证程序的健壮性
        if (f.hasOwnProperty(item)) {
            console.log (item);
        }
    } 
    

    如果现在我想要得到f.toString(),我们会发现f和Foo都没有这个方法,于是就去f._proto._proto(Foo.prototype._proto)中寻找,此时找到并调用。

    QQ图片20180209232906.jpg
    如图,我们要找f的一个属性时首先会在f._proto
    中寻找,因为f._proto的属性值是一个对象,所以也有_proto属性,如果没找到,就会去f._proto._proto中找,同理,如果还没找到就继续向上,直到结果为null为止。这个由_proto串起来的直到Object.prototype._proto为null的链就是原型链。

    以前一般使用对象的 _proto_属性,ES6推出后,推荐用Object.getPrototypeOf()方法来获取对象的原型 :给定对象的原型。如果没有继承属性,则返回null。

    相关文章

      网友评论

          本文标题:JS三座大山之原型和原型链

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