一个后端眼中的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对象的原型链。

相关文章
相关标签/搜索