JavaScript中构造函数和原型的深度细节分析

在ES6之前,对象并不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和他们的特性.

创建对象的三种方式:1.对象的字面量创建

 var obj1 = {}

2.new Object() 创建

var obj2 = new Object()

3.自定义构造函数创建

function Fun(name,age) {
                             this.name = name;
                             this.age = age;
                             this.play = function() {
                                 console.log('我想要去旅游')
                             }
                         }
//创建张三对象 
var zs = new Fun('张三',18)

关于构造函数:

构造函数是一种特殊的函数,需要与new一起使用才有意义,把对象中的一些公共的属性和方法抽取出来,封装到一个构造函数里面,其首字母要大写.

构造函数在new时做的事情:首先在内存中创建一个空对象,this指向这个空的对象,构造函数中的属性和方法添加给这个空对象,返回这个新对象(所以构造函数里面不需要return).

构造函数实例成员:

实例成员就是在构造函数内部通过this添加的属性和方法,实例成员只能通过实例化的对象来访问

构造函数静态成员:

静态成员只能通过构造函数来访问,是直接加载构造函数身上的

构造函数的缺点:

在new构造函数的时候,构造函数内的简单数据类型可以直接复用,复杂数据类型会另外开辟一个地址空间,进行存储数据,加入new1000下构造函数,就会特别浪费内存.

构造函数原型对象prototype:

             js规定,每一个构造函数都有一个原型对象prototype,这个prototype对象中的属性和方法都归属于该构造函数.所以如果把构造函数的方法定义在原型对象prototype身上,就会解决构造函数的缺点(浪费内存),(假如new1000次构造函数,调用方法play(),那么总共就开辟了一个内存空间)

Fun.prototype.play = function() {}
              var zs = new Fun()
              var ls = new Fun()
              console.log(zs.play === ls.play)  //true

对象原型__proto__:

            每个对象身上都有一个__proto__属性(我们也称之为__proto__原型),这个属性指向构造函数的prototype原型对象,这也就说明了为什么对象可以访问构造函数prototype原型对象身上的属性和方法.

function Person() {}
            Person.prototype.play = function() {console.log('速度上号!')}
            var zs = new Person()
            console.log(zs.__proto__ === Person.prototype) //true

__proto__对象原型的意义就是为对象查找机制提供一条线路,它只是内部指向原型对象prototype,开发中并不使用

constructor构造函数:

            对象原型(__proto__)和构造函数原型对象(prototype)身上都有一个constructor构造函数,因为它指向构造函数本身,也就告诉我们这个对象是由哪个构造函数创建出来的

function Person() {}
            Person.prototype.play = function() {console.log('速度上号!')}
            var zs = new Person()
            console.log(zs.__proto__.constructor)  //ƒ Person() { }
            console.log(Person.prototype.constructor)  //ƒ Person() { }

如果我们修改了原型对象,直接给原型对象进行赋值(Person.peototype = {}),那么就必须手动添加constructor指回原来的构造函数

function Person() { }
            Person.prototype.play = function () { console.log('速度上号!') }
            Person.prototype = {
                constructor: Person,
                watch: function () {
                   console.log('我要看电影');
                 }
            }
            var zs = new Person()
           console.log(zs.__proto__.constructor)   //ƒ Person() { }
           console.log(Person.prototype.constructor)  //ƒ Person() { }

构造函数、原型(__proto__)、原型对象(prototype)三者之间的关系总结:

            构造函数new出来对象实例,对象实例身上有__proto__原型指向构造函数的原型对象(prototype),prototype身上有constructor构造函数指向构造函数,因为实例.__proto__ ===实例.prototype ,所以实例.__proto__.constructor => 构造函数

原型链:

            只要是对象里面都有一个原型(__proto__),原型对象(prototype)也是对象,那么它身上也有原型(__proto__),指向Object原型对象,Object原型对象的constructor指向构造函数function Object(){},Object原型对象身上也有__proto__指向null,这就是整个原型链

 js的查找机制:

            1.当访问一个对象的属性或者方法时,首先查找对象自身有没有该属性

            2.如果没有就查找它的原型(实例对象的__proto__指向的原型对象)

            3.如果还没有就查找原型对象身上的__proto__(找到Object的原型对象)

            4.以此类推一直找到null为止

原型对象this指向问题:

            1. 在构造函数中,里面this指向的是对象实例

            2. 在原型对象函数里面的this指向也是对象实例

典型原型对象应用:

            扩展内置对象的方法:在原型对象身上添加方法,那么在对象实例上也可以使用该方法:

function Person() {}
            Person.prototype.play = function() {
                console.log('玩联盟')
            }
            var zs = new Person()
            zs.play() //玩联盟

call方法的作用:

            语法:

            call(m1,m2,m3.....) 第一个m1是改变后的this指向的对象,m2、m3...是传入的参数

            用法:

              1.调用函数

function fn() {console.log('打篮球')}
              fn.call() // 打篮球

2.改变this指向

function fn(x,y) {
                  console.log(this)
                  console.log(x+y)
              }
              let zs = {
                  name:'hiphop先生'
              }
              fn.call(zs,10,8) //{name: 'hiphop先生'} 18

利用父构造函数继承属性

function Father(uname,uage) {
                 // 第三步:这里的this改变为了Son,所以在Son这个对象实例上添加了uname和age属性
                 this.uname = uname;
                 this.uage = uage
             }
             function Son(uname,uage) {
                 // 第二步: 这里的this指向的是son,进入Father构造函数
                 Father.call(this,uname,uage)
             }
             // 第一步: new Son 创建Son的实例对象
             let son = new Son('hiphop先生',18)
             console.log(son)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hiphop先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值