zoukankan      html  css  js  c++  java
  • this的指向及原型和原型链 【作为构造函数被new调用】

    this在函数中的指向场景有4种:

    1. 作为构造函数被new调用

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset="utf-8">
     5         <title></title>
     6     </head>
     7     <body>
     8         <script>
     9             console.log(this)
    10             function Person () {
    11                 console.log(this)
    12             }
    13             var person = new Person();
    14         </script>
    15     </body>
    16 </html>

    在代码里面首先是先输出此时的this指向,然后再实例化一个对象并在构造函数里面输出this的指向,此时输出结果是:

     一开始默认我们的this指向的是window,但是当我们用new调用构造函数后,this的指向就变成了这个新对象,并且里面还有个默认的属性__proto__,实际上当我们在使用new调用构造函数时,会执行以下的操作:

    1.创建一个新对象

    2.构造函数的propotype指向当前我们这个新对象的__proto__

      首先,需要先来了解一下什么是原型,原型(__proto__)是一个对象,其它的对象可以通过原型来实现属性的继承,并且大多数的对象的原型都是__proto__

      例子:我们分别定义一个数组,一个对象和一个函数

    1     var arr = ['1','2']
    2     console.log(arr)
    3     var obj = { name: '小红'}
    4     console.log(obj)
    5     function fn () {}
    6     console.log(fn)

      输出结果:

      

       可以看到输出的arr和obj都有一个__proto__(原型对象),而我们的定义的方法并没有原型对象。我们再将arr里面的原型对象展开:

      

       可以看到这个对象里面的方法都是我们数组所包含的方法,但是我们的arr可以继承到__proto__(原型对象)里面的属性和方法,也就是我们经常这样来访问:arr.length(), 而funtion的原型是prototype,这是函数才有的属性,我们每个对象有的属性是__proto__,__proto__不是一个标准的名字,它的原名是 [ [ prototype ] ],只是脚本中并没有访问 [ [ prototype ] ]的方法,而在部分浏览器中才能支持这个属性。

      在__proto__里面有个contructor构造器(是个函数),我们的arr是什么样子全靠这个构造器,这个函数里面有prototype,而它里面的所有又和我们proto里面是一样的。看下面两个截图:

    左边的是arr的原型,右边是arr原型里面的展开,可以看到我们构造器里面的prototype里面的东西和左边proto展开的东西是一模一样的!

    这可以说明一个点就是,大多情况下,__proto__可以理解为其构造器(是个函数)的原型(函数的原型prototype), 也就是说可以这样来看__proto__ === construter.prototype

     

       再来看下原型的指向,它取决于对象创建时的实现方式:

      ① 字面量创建对象,也就是我们平时经常用的创建方式,var xxx = { ...... } , 此时它的原型就是__proto__,它等于其构造器的原型。

      

      ② 构造器创建对象(构造函数),var X = function () {}  var x = new X() 这就是一个new出来的对象,此时它的指向会不一样,我们X的原型还是prototype(因为构造函数也是函数,只是多了一个new),而我们x的原型,虽然输出的结果多了个A,但是它的原型依旧是其构造器的原型,即x.__proto__ === X.prototype  也等于 x.__proto__ === x.constructor.prototype 只是x的构造器现在是我们自定义的X,但是并没有什么大变化

       ③通过Object.create 方式来创建对象(有点有趣的变化)

       这儿展开后我们的b的__proto__的指向发生了变化,不再是其构造器的原型了,

       但是变成了这个,也就是我们创建其的对象a

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

      原型基本就讲到这边,然后是原型链的讲解,先看下下面的代码和输出:

    1 var A = function() {}
    2 var a = new A()
    3 console.log(a.__proto__)
    4 console.log(a.__proto__.__proto__)
    5 console.log(a.__proto__.__proto__.__proto__)

      好吧第一个应该都知道a的原型是等于其构造器的原型的 a.__proto__ === a.constructor.prototype === A.prototype,

      而第二项也就是求A.prototype的原型,由于我们也可以将其看做一个对象,那么这个对象的原型依旧是其构造器的原型,它的构造器是Object() {....省略里面的属性和方法..} 那么控制台来输出看下是不是,以下两句是相等的,都会返回true,你们可以自己试一下

     

       而第三项就是输出Object.prototype的原型了,但是Object已经是最底层的了,所以它没有原型,会输出null

      这样就是我们所说的原型链了,一个对象的原型等于其构造器的原型,而其构造器的原型又等于其构造器的原型的原型,一直到最后为null,在js中万物都是对象,所以会新成一条由__proto__构成的链条,递归访问__proto__必须有个出口,且数值为null,当js引擎查找对象的属性的时候,是先查找对象本身是否存在该属性,如果不存在,则沿着原型链不断地进行查找,有就使用没有就为空,它不会查找自身的prototye,下面是个原型链查找的例子:

      

    1 var arr = ['1','2','3']
    2 console.log(arr.unshift())

    这边我们调用了unshift方法,其实是用的原型链上的Array对象里面的unshift方法,我们来是试下随便定义一个方法比如说,arr.showArray(),

    此时控制台会报错

     这是因为整条原型链上都找不到这个方法来调用,但是我们可以为它的原型链上加上这个方法,再来调用:

     此刻再调用的话就能够访问到了

    3.将新对象赋值给当前的this

    4.执行构造函数(为这个新对象添加属性,继承其构造函数的原型上的所有属性和方法)

    5.如果构造函数没有其它的返回对象,则默认返回这个新对象,否则则会被忽略

  • 相关阅读:
    P5956[POI2017]Podzielno【数学】
    P6672[清华集训2016]你的生命已如风中残烛【结论】
    P5825排列计数【EGF,NTT】
    P3971[TJOI2014]Alice and Bob【贪心】
    P3244[HNOI2015]落忆枫音【dp】
    jquery 选中单选按钮的值
    jquery ajax 详解
    Common Lisp中的car和cdr
    publishing(android)
    Preparing for Release(发布前的准备)
  • 原文地址:https://www.cnblogs.com/xzsblog/p/13096156.html
Copyright © 2011-2022 走看看