JS中的构造函数

一、面向对象基本特征
  1. 封装:也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
  2. 继承:通过继承创建的新类称为“子类”或“派生类”。继承的过程,就是从一般到特殊的过程。
  3. 多态:对象的多功能,多方法,一个方法多种表现形式。
  4. Javascript是一种基于对象(object-based)的语言。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)—–es6以前是这样的。所以es5只有使用函数模拟的面向对象。
二、对象实例化方式
  1. 字面量模式

        var Car = {
            color: 'red',
            brand: '奔驰'
        }
        console.log(Car.color)
    
  2. 普通方式

        var Car = new Object()
        Car.name = '三蹦子'
        Car.color = 'blue'
        Car.tyre = function () {
            console.log('我有三个轮子')
        }
        console.log(Car)
        Car.tyre()
    
  3. 构造函数方式

        function Car(brand, color) {
            this.brand = brand
            this.color = color
            this.tyre = function () {
                console.log('我有三个轮子')
            }
        }
        var c1 = new Car('三蹦子', '蓝色')
        console.log(c1)
        c1.tyre()
    

    缺点:每个函数都会开辟一块新的内存,造成内存浪费

    解决方法:原型

三、构造函数注意事项
  1. 创造的Car可以称之为构造函数,也可以称之为类,构造函数就是类。

  2. c1,c2均为Car构造函数的实例对象。

  3. Car构造函数中的this指向Car的 实例对象即new Car()出来的对象

  4. 创建实例对象时必须带new

  5. 构造函数首字母大写,这是规范,请遵守它。如:Number() Array()

  6. constructor:这是实例对象都自动含有的属性,指向他们的构造函数

      console.log(c1.constructor === Car)//true
    
  7. 每定义一个函数,这个函数就带有一个prototype的属性,__proto__指向被实例化的构造函数的prototype,prototype默认带有constructor属性,constructor指向构造函数。

四、构造函数的问题

构造函数方法虽然好用,但是存在浪费内存的问题。对于每一个实例对象,tyre都是一样的内容,每一次生成一个实例,都必须 生成重复的内容,多占用内存。既不环保也缺乏效率。

    function Car(brand, color) {
        this.brand = brand
        this.color = color
        this.tyre = function () {
            console.log('我有三个轮子')
        }
    }
    var c1 = new Car('三蹦子', '蓝色')
    var c2 = new Car('电动三轮', '白色')
    console.log(c1.tyre === c2.tyre)//false
五、prototype原型

js中,每一个构造函数都又有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。实例化的__proto__指向构造函数的原型对象。

    function Car(brand, color) {
        this.brand = brand
        this.color = color
    }
    Car.prototype.tyre = function () {
        console.log('我有三个轮子')
    }
    var c1 = new Car('三蹦子', '蓝色')
    var c2 = new Car('电动三轮', '白色')
    console.log(c1.tyre === c2.tyre)//true
    console.log(c1.__proto__ === Car.prototype)//true

总结:

  1. 构造函数有一个原型对象,通过pototype获取
  2. 构造函数创建 实例对象后,每个对象都有一个私有的__proto__属性,指向构造函数的原型对象
六、对象与构造函数的关系

对象是由构造函数造出来的

  1. Object是Function 的一个实例。

    Object.constructor  == Function  //true
    
  2. 函数是Function 的实例,但不是Object 的实例。

    function fn(){}
    fn.constructor  == Function  //true
    fn.constructor  == Object    //false 
    
  3. {} 与 Object 的关系。

    var obj = {};
    obj.constructor  === Object   //true
    
七、静态成员和实例属性
  1. 实例成员:

    实例成员就是构造函数的内部成员,实例成员只能通过实例化的对象来访问。每个实例成员只跟每个对象实例有关,不同对象实例成员是没有任何关系的

        function Car(name, age) {
            this.name = name
            this.age = age
        }
        var c1 = new Car('花猫', 5)
        console.log(c1.name)//实例成员只能通过实例化对象访问
    
  2. 静态成员

    静态成员在构造函数本身上添加的成员,与具体对象无关。只属于类不属于实例化对象

    function foo(){
        this.show = function(){
            return this;
        }
    }
    
    foo.test = 123; //静态属性
    
    foo.say = function(){
        return this;
    }
    foo.say();
    
    var fn = new foo(); //实例化的新的对象,this指向这个新的对象,不能访问类的静态方法
    fn.say(); //Noname1.html:45 Uncaught TypeError: fn.say is not a function
    console.log(foo.say() == fn.say());
    
八、原型对象中this指向

构造函数中的this和原型对象的this,都指向我们new出来的实例对象

  • 在构造函数中,this指向的是构造函数的实例
  • 在构造函数的原型中,this同样指代的是构造函数的实例
function Car(bran) {
            this.brand = bran
            console.log(this);
        }
        Car.prototype.run=function(){
            console.log(this);
        }
        var c1 = new Car('五菱宏光')
        var c2 = new Car('长城皮卡')
        c1.run()
        c2.run()
九、继承call()方法
  • call可以调用函数
  • call可以修改this的指向,使用call()时,参数1是修改后的this指向,参数2,参数3。。。使用逗号隔开

调用函数

    function Car() {
        console.log(this)
    }
    Car.call()

改变this指向

    function Car() {
        console.log(this)
    }
    function Car2() {
        this.name = name
    }
    var c1 = new Car2()
    Car.call(c1)

改变this指向并传参

   function f1(name, age) {
        console.log(this)
        this.name = name
        this.age = age
        this.speak = function () {
            console.log('我叫'+this.name, '今年'+this.age)
        }
    }
    function Person() {
        this.name = name
    }
    var p1 = new Person()
    f1.call(p1, 'GRH', 21)
    p1.speak()
1、子构造函数继承父构造函数中的属性
    function Parent(name, age) {
        console.log(this)
        this.name = name
        this.age = age
    }
    function Chinese(name, age, hukou) {
        Parent.call(this, name, age)
        this.hukou = hukou
    }
    var f = new Parent('grh', 18)
    console.log(f)
    var f1 = new Chinese('grh', 18, '沧州')
    console.log(f1)
2、借用原型对象继承方法
    function Father(name, age) {
        this.name = name
        this.age = age
    }
    Father.prototype.speak = function () {
        console.log('哈哈哈')
    }
    function Son(name, age, score) {
        Father.call(this, name, age)
        this.score = score
    }
    Son.prototype = new Father()
    Son.prototype.constructor = Son
    Son.prototype.exam = function () {
        console.log('我的成绩不错')
    }
    var son = new Son('grh', 21, 100)
    console.log(son)
  • 23
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值