js用new实例化对象与直接调用的this的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js用new实例化对象与直接调用的this的区别相关的知识,希望对你有一定的参考价值。

参考技术A function Fun(argument1,argument2)
return this;

//直接调用
var f1 = Fun(); // window
//实例化对象
var f2 = new Fun(); // Fun

f1 只是调用 Fun函数,而 f2是实例化对象 Fun。两个的this指向的不是同个地方。调用函数的this指向的是window,实例化对象的this指向的是对象本身。

(构造函数的命名通常使用驼峰命名法,首字母大写,以此和普通的函数区分开来,这是一种习惯用法。)

测试例子:

如上,f只是调用fun1,输出的第一个this是指向window的。fun2也只是调用,所以this也是指向windowde。a是实例化的对象,this指向的是fun3实例化后的对象。

如果做下面调整。

如上,fun1跟fun3是被实例化,this指向对象本身,fun2只是调用,this指向window。

那给this的属性赋值会有什么样的结果呢?

调用函数里面的this属性赋值都是给window赋值的。

如果 fun1()改成 var a = new fun1(); 呢?

大家仔细看看输出的结果。

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用new实例化对象与直接调用的this的区别的主要内容,如果未能解决你的问题,请参考以下文章

js中new的本质

JS使用new操作符创建对象的方法分析

Java基础(42):Java中主类中定义方法加static和不加static的区别(前者可以省略类名直接在祝方法调用,后者必须先实例化后用实例调用)

javascript中的new有啥用

JS中用new创建对象与不用new创建对象区别:

如图java代码里面,不需要用new关键字实例化类就可以直接使用类里面的对象吗?