JS创造对象的多种方式(Object类、字面量、工厂函数、构造函数、构造函数的性能优化)

对象有属性和行为,对于属性,我们传入进去;对于行为,我们传入方法进去。创建对象的方式有以下三种。

**

1. 方式一(通过Object类创建)

**

let obj = new Object();
obj.name = "ccc";    //添加属性
obj.age = 23;
obj.say = function(){    //添加方法(这里称为方法,而不是函数。因为函数是可以直接调用的,而方法必须通过对象来调用)
	console.log("hi");
}
console.log(obj);
console.log(obj.name);
console.log(obj.age);

结果为

obj打印输出的就是它自己拥有的属性和方法,我们也能通过__proto__看见它的原型

这里打印属性很容易理解,我们再看看方法

obj.say();
console.log(obj.say);
console.log(obj.say());

第一句含义:执行对象的方法,所以会输出 hi
第二句含义:打印这个方法,并不是执行。所以输出的是这个函数
第三句含义:执行对象的方法(会输出hi),并输出它的返回值(由于这里没有写return xxx,所以返回值为undefined)。
如下所示
在这里插入图片描述
为证明第三句的说法,我们在对象里添加方法的返回值

 obj.say = function(){    
        console.log("hi");
        return "mytest";
    }
console.log(obj.say());    

此时输出为
在这里插入图片描述
所以我们的说法是正确的

2. 方式二(通过字面量的方式创建)

let obj = {};

3. 方式三

属性和值之间用冒号分开,属性和属性之间用逗号分开。

let obj = {
	name: "ccc",
	age: 12,
	say: function(){
		console.log("hi");
	}
}

4. 工厂函数

工厂函数顾名思义,一种批量制造对象的函数。
实际上就是把创建对象的步骤封装在一个函数里,并且返回。

 function getPerson(myName, myAge){
        let obj = new Object();
        obj.name = myName;
        obj.age = myAge;
        obj.say = function (){
            console.log("hi");
        }
        return obj;   // 返回创建的这个对象
    }
 let obj1 = getPerson("ccc", 23);
 let obj2 = getPerson("hhh", 24);

通过这种方式,可以减少重复的代码,但是也有缺点:不同对象使用相同的方法却占着多个内存。我们继续测试证明。

console.log(obj1.name);
console.log(obj1.age);
obj1.say();
console.log(obj2.name);
console.log(obj2.age);
obj2.say();

输出结果为
在这里插入图片描述
判断方法是否相等

console.log(obj1.say() == obj2.say());
console.log(obj1.say() === obj2.say());

结果为
在这里插入图片描述
咦?为什么会是true?这里笔者犯了一个常见的错误,obj1.say()是执行这个方法输出"hi",obj2.say()也是执行这个方法输出"hi",那结果必然是相等的。
真正的判断方法是否相等应该如下所示。

console.log(obj1.say == obj2.say);
console.log(obj1.say === obj2.say);

在这里插入图片描述
可以看到,这两个输出一样的方法是不一样的,因为会开辟不同的内存空间存储这个方法。我们继续打印出这两个方法到底是什么样子的。

console.log(obj1.say);
console.log(obj2.say);

在这里插入图片描述
可以看到长得是一样的,但是存放地址不一样,就不相等哦!

5. 构造函数

构造函数是工厂函数的简写方式。构造函数一般首字母需要大写,且用关键字new构造实例对象

function Person(myName, myAge){
	this.name = myName;
	this.age = myAge;
	this.say = fucntion(){
		console.log("hi");
	}
}
let obj1 = new Person("ccc", 23);
let obj2 = new Person("hhh", 24);
let obj3 = Person("ttt", 12);
console.log(obj1);
console.log(obj2);
console.log(obj3);

结果为
在这里插入图片描述
这是因为在new Person的时候,系统会自动添加如下代码

function Person(myName, myAge){
            let obj = new Object();   //系统自动添加
            let this = obj;           //系统自动添加
            obj.name = myName;
            obj.age = myAge;
            obj.say = function (){
                console.log("hello");
            }
            return this;            //系统自动添加
        }

因为创建了一个对象并返回,所以obj1,obj2是有值的,而obj3只是简单的调用函数,所以没有返回值。
继续探寻this的使用方法

function Person(myName, myAge){
        this.name = myName;
        this.age = myAge;
        this.say = function (){
            console.log(this.name, this.age);
            return "mysay";
        }
    }
let obj1 = new Person("ccc", 23);
console.log(obj1);
console.log(obj1.name);
console.log(obj1.age);
obj1.say();
console.log(obj1.say());

结果为
在这里插入图片描述
方法say中的this是:谁调用的这个say,那么this就是指的谁。这里是obj1调用的,于是obj1.say()得到的就是obj1.name和obj1.age的值。

6. 构造函数的性能优化(利用原型对象)

前面我们已经提到,对于同一个构造函数的相同方法,不同的对象会开辟不同的内存空间,但是明明是一样的方法,我们为什么要开辟不同的内存空间来占内存呢?所以我们要使用一种最好的性能优化方法——将共享方法放在构造函数的原型对象里
如下所示

function Person(myName, myAge){
        this.name = myName;
        this.age = myAge;
    }
Person.prototype = {
       say:function (){
           console.log("hi");
       }
}
let obj1 = new Person("ccc", 23);
let obj2 = new Person("hhh");

输出结果为
在这里插入图片描述
可以看到两个对象obj1和obj2都可以使用say方法,当它们找不到方法时,就会通过原型链去寻找方法,他们寻找的都是Person构造函数的原型对象的方法,所以这这两个对象的方法都是一样的。
特别注意的是,对于obj2对象创建的时候,我并没有给age传入参数,也可创建实例对象,它的值为undefined。同样的,不给name传入值也是可以的,也都会找到say方法。
如果有原型链不清楚的可以看我的这篇博客

7.拓展

思考如下代码的结果

function Person(myName, myAge){
        this.name = myName;
        this.age = myAge;
        this.say = function (){
            console.log("persay");
        }
    }
 Person.prototype = {
        say:function (){
            console.log("hi");
        }
    }

let obj1 = new Person("ccc", 23);
let obj2 = new Person();
let obj3 = Person();
obj1.say = function (){
   console.log("objsay");
 }
console.log(obj1);
console.log(obj2);
console.log(obj3);
obj1.say();
obj2.say();
obj3.say();

对于第一个obj1.say方法,它自己重新更改过自己的行为,所以打印行为时,既不从构造函数里寻找,也不从构造寒素的原型对象里寻找,而是它自己修改的。
对于第二个obj2.say方法,自己没有重新更改方法,于是先从构造函数里寻找,发现有,那就用构造函数里的。
对于第三个obj,这是重点,因为创造这个对象的方法直接是Person(),所以是没有我们前面讲到的步骤let obj = new Object(); let this = obj; return this; 所以并没有返回值赋值给obj,于是obj的值是undefined,想要打印出undefined的say方法,那必然是会出错的。
结果如我们所说
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值