一個後端眼中的js對象和原型鏈

js對象

js中的類型有:後端

number,string,boolean,object,undefined,function

因此對象能夠這麼分類:函數

  1. 函數對象(function)
  2. 其餘對象

因此函數對象能夠大聲唱咱們不同,既然不同確定得有一點不同的煙火,函數對象的不同在什麼地方呢? 每個函數對象都有一個prototype屬性(Function.prototype除外)this

做爲一個傻傻的後端的我一直覺得每個對象都有一個prototype屬性。每個對象都有的是一個叫作__proto__的隱藏屬性,它指向的就是對象所對應的函數對象的prototype(也就是傳說中的原型對象)prototype

後面咱們再舉例子來講明原型對象,咱們先看一下那些是函數對象,方便理解。code

那些是函數對象

function FN() {}
    var FA = function() {}
    var FF = new Function('arg1', 'arg2', 'console.log(arg1 + arg2)');

    FF('a','b');
    console.log('typeof Object:' + typeof Object); //function
    console.log('typeof Object.prototype:' + typeof Object.prototype); //object
    console.log('typeof Function:' + typeof Function); //function
    console.log('typeof Function.prototype:' + typeof Function.prototype); //function
    console.log('typeof FN:' + typeof FN); //function
    console.log('typeof FA:' + typeof FA); //function
    console.log('typeof FF:' + typeof FF); //function

不那麼精確的總結一下就是:對象

  1. 帶function關鍵字的
  2. new Funtion出來的對象
  3. Funtion,Object,Function.prototype對象

這裏說一下Function.prototype,由於它又是一個不同的煙火。由於通常的函數對象的prototype都是普通對象,可是Function.prototype是一個函數對象,而且這個函數對象沒有prototype屬性。原型鏈

全部的函數對象的__proto__都指向的是Function.prototypeget

可使用:原型

console.log(Object.getOwnPropertyNames(Function.prototype))

打印一下Function.prototype的屬性,會發現都是一下公共函數。string

原型鏈

咱們把問題簡化來處理,看一個最多見的簡化的原型鏈:

function Person(name, age) {
        this.name = name;
        this.age = age;
        this.hobby = function() {
            return '實例對象hobby';
        }
    }
    Person.hobby = function() {
        return '函數對象hobby';
    }
    Person.prototype.hobby = function(){
        return 'prototype hobby';
    }
    var p1 = new Person("tim",20);
    var p2 = new Person("alice",20);
    console.log(p1.hobby === p2.hobby);//false
    console.log(p1.__proto__ == Person.prototype);//true
    console.log(p2.__proto__ == Person.prototype);//true
    console.log(p1.__proto__ == p2.__proto__);//true
    console.log(p1.__proto__.hobby == p2.__proto__.hobby);//true
    console.log(p1.hobby());//實例對象hobby
    console.log(Person.hobby());//函數對象hobby

從前面介紹的咱們知道Person是一個函數對象,既然是一個函數對象,那麼Person是有prototype屬性的,因此給Person的prototype的屬性添加一個hobby屬性也是合理的事情了。

Person是一個函數對象,那麼說Person是一個對象也是合理的了,給Person添加一個hobby屬性也是合理的了。

下面就要看一下關鍵的new關鍵字的行爲了,咱們知道Person是一個函數對象,new一個函數對象,基本上執行的就是屬性拷貝,而後把new出來的對象的__proto__指向函數對象的prototype的屬性。

因此上面的p1.hobby === p2.hobby是false是由於他們是2個對象中不一樣的屬性,是2個不一樣的引用。

而p1.proto.hobby == p2.proto.hobby是true是由於這2個都是Person.prototype對象上的屬性hobby是同一個引用。

js原型鏈查找方式就是在當前對象中查找這個屬性,若是沒有就在__proto__指向的對象中去查找,依次查找到Object.prototype結束,由於Object.prototype.proto == null

下面思考一個問題:若是把上面的:

Person.hobby = function() {
    return '函數對象hobby';
}

去掉會有問題嗎?

答案是會有問題,這個問題有點繞,可是記住咱們前面總結的,全部的函數對象的__proto__指向的都是Function.prototype

全部若是沒有上面的代碼Person.hobby()這個調用在Person函數對象中找不到hobby屬性,就會在Funtion.prototype對象中找,依次找到Object.prototype,顯然是找不到的。

注意原型鏈,不是在Person.prototype中查找,那不在Person對象的原型鏈。

相關文章
相關標籤/搜索