JavaScript学习笔记 .7——原型机制prototype(2)

150 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

上节我们得知:任何对象(包括函数)都有一个__proto__属性指向原型,而函数还有一个特别的__prototype__属性,其本身是一个实例对象。我们深入探究一下。

函数的prototype属性

function A(){};
var B=function(){};

每个函数都有一个 实例对象prototype 作为该函数的属性:

A.prototype:{
  constructor: ƒ A()
  __proto__: Object.prototype
}
B.prototype:{
  constructor: ƒ ()//B的构造器是匿名的
  __proto__: Object.prototype
}

prototype实例对象必定拥有成员:

  • constructor,指向函数本身:
    A.prototype.constructor:
    ƒ A(){
    }
    
  • 一个__proto__属性,指向的是Object函数的prototype属性,意思是A函数的prototype的原型是Object函数的prototype
    Object.prototype:{
      constructor: ƒ Object()
      toString: ƒ toString()
      valueOf: ƒ valueOf()
      __defineGetter__: ƒ __defineGetter__()
      __proto__: (...)
      ...
    }
    

Objectprototype就没有原型了,它的__proto__属性为null,到底了。


事情逐渐好玩了起来!为什么每个函数都要有一个prototype属性?它们是用来干什么的?

我们使用new来用函数创建实例试一试。

实例对象的原型

  • 使用new运算符创建实例a时,a的原型指向了构造函数的prototype
function A(){
    this.member1='abc';
}
var a = new A();
a:
{
    member1:'abc',
    __proto__:{
      constructor: ƒ A()
      __proto__: Object.prototype
    }//这不就是构造函数的prototype属性吗!
}

也就是说,a这个实例,现在自己有一个member1成员,和一个原型。并且,实际上,a要是想调用原型中的成员,可以跨过__proto__直接调用!

a.constructor:
ƒ A(){
    this.member1='abc';
}

这个其实就是JS继承机制的原理。他究竟是怎么运作的?这里埋个伏笔。

另外:

  • 使用Object.create()基于实例a创建实例b后,b的原型指向了a
a.member1 = 123;
var b = Object.create(a);
b.__proto__: a

我拿我一开始在第一节举得衣服的例子继续解释:
也就是说,使用create方法,能给a加件衣服,令加了件衣服的ab,但是使用b也可以调用a的成员,b并不是从a拷贝构造出来的(忘掉C++)。


那么知道了这些,我将在下节中给大家讲述JS真正有意思的机制——原型链 。大家不要错过~