JS构造函数

Posted JackAfan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS构造函数相关的知识,希望对你有一定的参考价值。

构造函数

{
    /* 
        工厂函数通过new运算符改造成了 构造函数;
        构造函数:
            1.首字母大写; 为了让普通函数和构造函数的区分
            2.this指向实例化对象
    */
    function Person(name,age){
        this.num = 0;
        this.name = name;
        this.age = age;
        this.hobby = function(){
            console.log("喜欢篮球");
        };
    }

    // 调用构造函数:
    // new : 实例化;
    let zhangsan = new Person("张三",20);

    {
        // 静态属性和方法;(属于类本身) -> 静态成员
        // 假如需要统计一下这个构造函数有多少个实例化对象:
        let zhangsan = new Person("张三",20);
        // zhangsan.num ++;
        // console.log(zhangsan.num);//1
        let lisi = new Person("李四",21);
        // lisi.num ++;
        // console.log(lisi.num);//1
        // 可以看到上面有两个实例化对象了,但结果依然还是1;
        // 所以这个属性就要放到构造函数中当属性;
        Person.num = 0;
        Person.fn = function (){
            console.log("fn");
        };
        Person.num ++;
        Person.num ++;
        console.log(Person.num);//2
    }

}

 构造函数性能问题

{
    // 构造函数性能
    function Person(name){
        this.name = name;
        this.age = 20;
        this.hobby = function(){
            console.log("喜欢篮球")
        }
    }

    let zhangsan = new Person("张三");
    let lisi = new Person("李四");

    console.log(lisi.hobby === zhangsan.hobby);//false -> 对象的比较:不仅要值一样,地址也需要一样
    // 在这里可以看到有两个实例化对象,他们在内存里分别保存了同样的内容,占据了一些内存;
}

原型

{
    // 原型
    function Person(name){
        this.name = name;
        this.age = 20;
        // this.hobby = function(){
        //     console.log("喜欢篮球")
        // }
    }

    let zhangsan = new Person("张三");
    let lisi = new Person("李四");
    
    // 什么是原型呢:每一个构造函数,在实例化的过程中,它都会有两个部分构成:1.构造函数(本身);2.公共空间(原型);
    Person.prototype.hobby = function(){//方法可以放到原型上面
        console.log("喜欢篮球");
    }

    console.log(lisi.hobby === zhangsan.hobby);//true -> 方法放到原型上面之后,不管是实例化多少个对象,他们的方法都是同一个方法,而不是在内存里面新开辟的地址,所以这样就更节约性能
    // 原型:1.this指向还是实例化对象 2.每一次声明构造函数的时候prototype都是自动有的

    /* 
        构造函数有两部分:1.本身;2.原型
        实例化对象也是有两部分:1.自身属性和方法(也就是构造函数里面的属性和方法); 2.自己的原型(__proto__)
    */
    console.log(zhangsan.__proto__ === Person.prototype);//他们两个是同样一个东西,只是表示形式不一样而已~

    // 原型的固有属性;
    console.log(Person.prototype.constructor === Person);//指向构造函数
    console.log(zhangsan.constructor === Person);//true -> 可以用来判断实例化对象是哪个构造函数

    // 原型prototype注意点:
    // 可以追加方法,不要进行覆盖,即使覆盖了,也要把constructor指向构造函数;
    Person.prototype = {
        hobby(){
            console.log("喜欢篮球")
        },
        constructor:Person
    }

    // prototype的constructor的情况:可以判断是否是 数组,对象等系统对象;
    let arr = [1,2,3];
    console.log(arr.constructor === Array);//true
    let str = "123324";
    console.log(str.constructor === String);//true
}

构造函数,原型,实例化 三者关系:

// 构造函数,原型,实例化 三者关系:
let temp;
let temp1;
function Person(name){
    this.name = name;
    this.age = 20;
    temp = this;
}

Person.prototype.fn = function(){//原型可以加方法
    console.log("fn");
    temp1 = this;
}

let zhangsan = new Person("张三");//构造函数可以通过new得到对象
// 这时候: 实例化对象的属性和方法来自构造函数的属性和方法;
console.log(zhangsan);
// this指向实例化:
console.log(zhangsan === temp);//true
// prototype 指向实例化对象
zhangsan.fn();
console.log(zhangsan === temp1);//true
// constructor指向构造函数
console.log(Person.prototype.constructor === Person);//true

工厂函数与构造函数的对比:

{
    // 工厂函数与构造函数的对比:
    {
        function Person(name){
            let obj = {};
            obj.name = name;
            obj.age = 20;
            obj.fu = function(){
                console.log("fn");
            }
            return obj;
        }
        let zhangsan = Person("张三");
    }
    {
        function Person(name){
            this.name = name;
            this.age = 20;
        }
        Person.prototype.fn = function(){
            console.log("fn");
        }
        let zhangsan = new Person();
    }
    /* 
        为什么构造函数比构造函数 使用多:
            1.方法在公共空间里面(prototype)
            2.创建的对象的指向问题 : 构造函数有constructor
    */
}

原型链

{
    // 原型链
    function Foo(name){
        this.name = name;
        this.age = 20;
        // this.test = "你好";
    }
    
    //原型: 也是对象 所以也就有__proto__,__proto__也是对象所以也还有原型... 
    Foo.prototype.fn = function(){
        console.log("fn");
    }
    // Foo.prototype.test = "原型_你好";

    let newFoo = new Foo("张三");

    let obj = new Object();//所有的对象都是来自于 Object;
    Object.prototype.test = "系统原型_你好";
    // 所以最终的结果是;
    console.log(Object.prototype.__proto__);
    // 那原型链有啥用: 查找规则: 如果构造函数没有,就去原型,一步一步往原型链查找!||假如都有就是 就近原则
    console.log(newFoo.test)
}

以上是关于JS构造函数的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段

防止 Proguard 删除片段的空构造函数

无法解析片段中的 ViewModelProvider 构造?

为啥要避免片段中的非默认构造函数?

片段真的需要一个空的构造函数吗?

这个嵌套类构造函数片段可以应用于泛型类吗?