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)
<think>好的,我现在需要解释一下在JavaScript中如何使用构造函数来初始化静态函数。这个问题看起来有点挑战性,因为JavaScript本身并没有像其他面向对象语言那样的显式静态方法。不过,用户可能指的是在构造函数中定义属于类本身的函数,也就是静态方法。 首先,我得回忆一下JavaScript构造函数的基本概念。构造函数通常用于创建对象实例,而静态方法是属于构造函数本身的,而不是实例。例如,像Array.isArray这样的方法就是静态方法,直接通过构造函数调用,而不是实例。 接下来,我需要确定如何正确地在构造函数中定义静态方法。通常,静态方法是直接添加到构造函数对象上的,而不是在构造函数内部使用this,因为this在构造函数中指向的是新创建的实例。所以,正确的做法可能是在构造函数外部,通过直接给构造函数对象添加属性来定义静态方法。例如: function MyClass() { // 构造函数逻辑 } MyClass.staticMethod = function() { // 静态方法逻辑 }; 不过,用户的问题提到的是在构造函数内部初始化静态函数。这似乎不太常见,因为每次实例化对象时,构造函数都会被调用,如果在构造函数内部添加静态方法,可能会导致重复定义或者覆盖原有的静态方法。例如: function MyClass() { MyClass.staticMethod = function() { console.log('This is a static method'); }; } 每次创建实例时,都会重新定义staticMethod,这可能不是用户想要的效果。这样的做法会导致每次实例化都重新赋值静态方法,可能存在性能问题或意外覆盖的问题。 但用户可能想知道的是如何在构造函数内部进行静态方法的初始化,也许是为了动态生成静态方法,或者在特定条件下修改它们。这时候需要解释可能的用法和潜在的问题。 另外,可能用户对ES6的class语法更熟悉,所以在解释时也可以对比一下。在ES6中,静态方法是通过static关键字定义的: class MyClass { static staticMethod() { // 静态方法逻辑 } } 但这也属于在类定义时直接添加静态方法,而不是在构造函数内部初始化。 总结来说,用户的问题可能是在构造函数内部定义静态方法,但这通常不是一个好的实践,因为每次实例化都会重新定义静态方法。正确的做法是在构造函数外部直接给构造函数对象添加方法,或者在ES6中使用static关键字。因此,在回答时需要指出这一点,并给出正确的示例,同时说明在构造函数内部定义的潜在问题。</think>在 JavaScript 中,构造函数可以通过以下方式初始化静态函数(类级别函数): ### 核心概念 静态函数是直接绑定到构造函数本身的函数(而非实例),通过构造函数名称直接调用: ```javascript function Person(name) { this.name = name // 实例属性 } // 定义静态函数(直接绑定到构造函数) Person.createAnonymous = function() { return new Person('Anonymous') } // 调用静态函数 const anon = Person.createAnonymous() ``` ### 构造函数内初始化静态函数的注意事项 1. **常规做法(推荐)** 静态函数通常在构造函数外单独定义: ```javascript function MyClass() { /* 实例初始化 */ } // 推荐的定义方式(避免重复定义) MyClass.staticMethod = function() { console.log('Static method called') } ``` 2. **构造函数内部定义(特殊场景)** 虽然可以,但会产生重复定义问题: ```javascript function MyClass() { // 每次实例化都会重新赋值(可能产生副作用) MyClass.staticMethod = function() { console.log('Reinitialized static method') } } const obj1 = new MyClass() MyClass.staticMethod() // 输出 "Reinitialized..." const obj2 = new MyClass() // 再次覆盖静态方法 ``` ### 最佳实践建议 - **静态函数应保持稳定**:避免在构造函数内修改静态方法 - **使用 ES6 class 语法**(更清晰): ```javascript class Person { static createAnonymous() { return new Person('Anonymous') } constructor(name) { this.name = name } } ``` ### 应用场景示例 ```javascript class DatabaseConnection { static #instance // 静态私有变量 static getInstance() { if (!this.#instance) { this.#instance = new DatabaseConnection() } return this.#instance } } // 单例模式调用 const db = DatabaseConnection.getInstance() ``` 关键要点:静态函数应通过构造函数对象直接访问,主要用于工具方法、单例模式等场景,与具体实例无关的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值