Live2d Test Env

【JavaScript高级02】JavaScript第一大神兽:原型和原型链

1,函数中的prototype属性

每个函数都会有一个属性prototy,该属性默认指向一个空Object对象,而这个空的Object对象被称之为原型对象。

 <script > 
    console.log(typeof Date.prototype);
</script>

打印结果:

会发现,Date的prototype中定义了很多的空方法,用于表示Date的结构,该Object并不是一个空的,使用es定义的,这也说明了,在默认情况指向一个空的原型对象。该情况如下所示:

<script > 
    function fun(){}
    console.log(fun.prototype,typeof fun.prototype);
</script>

打印结果为:

会发现,在这个fun函数中的Object原型对象中,只有两个属性,该两个属性为系统定义的,之后并无其他属性。可以看做是一个空的Object对象。该原型对象有一个属性constructor,指向它的函数对象。还有一个属性叫做__proto__,这个属性后面细说。向看看原型对象的的constructor属性是否指向函数对象。

<script > 
  function fun(){}
  console.log(fun.prototype.constructor===fun,Date.prototype.constructor===Date);
</script>

打印结果为:

结果都为true,表示是对的。

综合上述可以得出:一个函数都会有一个prototype对象,该对象默认指向一个空Object对象,称其为原型对象。在系统(js)定义的函数中,指向的原型对象不是空的,而是定义了很多的空方法,表示该函数的结构。在原型对象中有个属性为constructor,该属性指向其函数,示例图如下所示。

我们可以在原型对象中添加属性,一般情况我们只添加方法(变量也可以添加)。

<script > 
    function Fun(){}
   fun.prototype.text=function(){
    console.log("ha")
  }
   var f=new Fun()
   f.text()
</script>

2,显示原型属性和隐示原型属性

先给出定义:

每个函数function都有一个prototype,即显式原型属性。
每个实例对象都有一个__proto__,可称为隐式原型属性。

显式原型属性和隐式原型属性的关系为:对象的隐式原型的值为其对应构造函数的显式原型的值。

显式原型属性就不说了,上面讲的和详细了,那就讲讲隐式原型属性吧。

__proto__隐式原型属性实在对象被创建时才被添加,其值为其对应构造函数的显式原型的值。其指向和显式原型属性一样。默认指向一个空Object对象。

 <script > 
   function Fun(){}
   var f=new Fun();//隐含了this.__proto__=Fun.prototype
   console.log(f.__proto__===Fun.prototype)
</script>

打印结果为true。在来一段代码,以此代码来画出内存示意图:

<script > 
   function Fun(){}
   Fun.prototype.text=function(){

   }//隐含this.prototype={}
   console.log(Fun.prototype)
   var f=new Fun();//隐含this.__proto__=Fun.prototype
 console.log(f.__proto__===Fun.prototype)
   console.log(f.__proto__)
  f.text()
</script>

内存示意图:

3,原型链

先来一段代码:

  function Fn() {
    this.test1 = function () {
      console.log('test1()')
    }
  }
  console.log(Fn.prototype)
  Fn.prototype.test2 = function () {
    console.log('test2()')
  }
  var fn = new Fn()
  fn.test1()
  fn.test2()
  console.log(fn.toString())
  console.log(fn.test3)

运行结果为:

 

前面的输出结果在意料之中,我们在函数和原型中添加了方法,在调用之后,输出了test1()和test2()。当时函数中没有toString和test3,但是调用的时候,确输出了不同的结果,一个是输出[object Object],另一个输出undefined,是什么导致这个结果?这个就得引出一个知识点:原型链。

代码的内存示例图:

第一步:首先,Fn保存了Fn函数对象的地址值,Fn函数对象在堆内存中有块内存空间,Fn指向该内存空间。Fn函数对象有个属性prototype(显示原型),该属性指向一个原型对象(空Object对象)。

第二步:有个全局作用域对象Object在页面加载的时候也会被创建,指向Object的函数对象,Object的显式原型属性会指向其原型对象。

第三步:由于Object的原型对象的存在,空Object对象的隐式原型属性会指向Object的原型对象(对象的隐式原型的值为其对应构造函数的显式原型的值)。Object的原型对象会有个隐式原型属性,其值为null,表示原型链的尽头。

第四步:创建fn实例 对象,会在内存中开辟一个内存空间用来存放Fn的实例对象,函数的实例对象会有个隐式原型属性指向其构造函数的原型对象(对象的隐式原型的值为其对应构造函数的显式原型的值)。

第五步:添加函数,Fn添加函数是在其原型中添加,fn则是在实例函数中添加,查找是,查找test1会沿着内存为0x567这条查找,在其函数实例总找到并打印。查找test2时,会沿着内存为0x123这条找,最终在其原型对象中找到。查找toString时,在原型对象找不到,回到Object的原型对象查找,找到后打印。查找test3时,在原型链的尽头都没有,会放反回一个undefined。

总结为:

访问一个对象的属性时,先在自身属性中查找,找到返回,如果没有, 再沿着__proto__这条链向上查找, 找到返回,如果最终没找到, 返回undefined。可以看出,整条链是沿着隐式原型属性查找,所以也被称之为 隐式原型链。

注意:

a,函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)

 console.log(Fn.prototype instanceof Object) // true
  console.log(Object.prototype instanceof Object) // false
  console.log(Function.prototype instanceof Object) // true

b, 所有函数都是Function的实例(包含Function)

console.log(Function.__proto__===Function.prototype)

c, Object的原型对象是原型链尽头

console.log(Object.prototype.__proto__) // null

4,原型链的属性问题

读取对象的属性值时: 会自动到原型链中查找。
设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值。
方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上。

无论对象创建多少次,其实例对象的隐式原型属性都不变。

function Fn() {}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a, fn1)
var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a, fn2.a, fn2)
Person.prototype.setName = function (name) {
    this.name = name
  }
  var p1 = new Person('Tom', 12)
  p1.setName('Bob')
  console.log(p1)

  var p2 = new Person('Jack', 12)
  p2.setName('Cat')
  console.log(p2)
  console.log(p1.__proto__===p2.__proto__) // true

5,instanceof的实现原理:利用原型链

 表达式: A instanceof B
如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false。其中A是一个实例对象,B是一个构造函数对象。

 /*
  案例1
   */
  function Foo() {  }
  var f1 = new Foo()
  console.log(f1 instanceof Foo) // true
  console.log(f1 instanceof Object) // true

  /*
  案例2
   */
  console.log(Object instanceof Function) // true
  console.log(Object instanceof Object) // true
  console.log(Function instanceof Function) // true
  console.log(Function instanceof Object) // true

  function Foo() {}
  console.log(Object instanceof  Foo) // false

 

 

posted @ 2020-09-09 17:12  waywardcode  阅读(62)  评论(0)    收藏  举报