在学习了面向对象,我们了解了面向对象的三大特性:封装、继承、多态。下面我们需要了解对象的创建方式:
1 字面量创建方式
对象有很多描述方式,比如键值对(key--value)的集合、字典、工具包。对象的本质是对变量和函数进行封装,将变量封装成属性,函数封装为方法;这里我们就是采用字典的方式来创建对象,将属性和方法名作为key
1.1 创建一个书对象
var book = { name:"js入门教学", price:"¥34", author:"刘忻欢", showName: function () { console.log(this.name); } } /*调用对象 */ console.log(book.name);
特点:字面量创建方式比较简单,把方法和属性写在{}中,但是当需要创建多个同类型的对象的时候,代码的重复性就比较高,它不适用于批量的创建同类型的对象。
1.2 创建多个书对象
var book1 = { name:"js入门教学", price:"¥34", author:"刘忻欢", showName: function () { console.log(this.name); } } var book2 = { name:"html+css深入浅出", price:"¥50", author:"张某某", showName: function () { console.log("jjjj"); } }
2 内置构造函数创建方式
js内置构造函数有:Object Function Date String Number Array .....
创建方式分为两步:
/*首先 创建一个空对象*/ var obj = new Object(); /*其次 设置属性|方法*/ obj.name="内置构造函数创建对象"; obj.ways = function () { console.log("2步"); }
特点:利用内置构造函数创建对象和字面量方式创建一样,需要创建多个同类型的对象时,会出现大量重复的代码。
3 简单工厂函数创建对象方式
3.1 创建书的工厂函数
function createBook(name,author,price){ /*创建一个空对象*/ var book = new Object(); book.name = name; book.author = author; book.price = price; book.log = function () { console.log("eee"); } return book; }
3.2 创建多个书对象
var book1 =new createBook("三毛流浪记","张乐平","南方出版社"); // 打印书名 console.log(book1.name); var book2 = new createBook("阿衰","猫小乐","云南出版集团公司"); // 打印book2对象 console.log(book2);
特点:① 利用工厂函数创建对象,只要通过 new 函数() 就可以创建出不同的对象 。
② 但是有多个工厂函数,且属性和方法相同时,创建出来的对象就无法识别对象的类型,因为创建对象都是使用Object的原生构造函数来完成的。
3.3 多个工厂函数
function createPerson(name,age,eating){ var person = new Object(); person.name = name; person.age = age; person.eat = function () { console.log(eating); } return person; } function createDog(name,age,eating){ var dog = new Object(); dog.name = name; dog.age = age; dog.eat = function () { console.log(eating); } return dog; }
构造了创建人和狗的两个方法,他们的属性和方法一样
var person1 = new createPerson("小明","23","吃米饭"); var dog1 = new createDog("小小明","2","狗粮"); console.log(person1); console.log(dog1);
打印结果:
问题:我们没办法区分哪个对象是 createPerson方法创建 ,哪个是createDog 方法创建
总结:为什么将这种方式叫做工厂呢,因为它的模式和工厂十分相似。工厂的特点:批量生产(原料 --- 加工 --- 产品)
4 自定义构造函数创建对象方式
什么是构造函数:① 构造函数和普通函数本质上没有区别
② 构造函数通常首字母大写(这是为了 人为的区分)
③ 在调用时,构造函数必须要和 new关键字 结合
4.1 构造函数的核心过程
① 提供一个构造函数
② 在构造函数内部通过 this 设置属性和方法
③ 通过 new 函数() 创建对象
/*1 提供一个构造函数*/ function Person(){ /* 2 在函数内部通过 this 设置属性和方法*/ this.name = "张三"; this.age = 23; this.sex ="男"; } /*3 通过 new 函数() 来创建对象*/ var zhangsan =new Person(); console.log(zhangsan);
自定义构造函数创建对象需要我们完成的核心过程就这三步,但是其内部默认完成的工作其实复杂的多:
内部实现细节:
① 默认在内部会创建一个空的对象 var o = new Object();
② 默认会把新创建的对象赋值给 this this = o;
③ 默认会设置新创建的对象的原型对象为当前的原型对象 o.prototype = Person.prototype;
④ 默认会设置新创建对象的构造器属性为当前构造器属性 o.constructor = Person
⑤ 通过 this设置属性和方法(这是我们自己完成的操作)
⑥ 默认会返回新创建的对象 return o;
注意点:
Ⅰ.如果我们没写 return ,那么默认返回新创建的对象
Ⅱ. 如果我们写了 return:
ⅰ.如果返回的是值类型(null | undefined | "string" | number...),那么我们自己写的 return 语句会被忽略,返回的仍然是新创建的对象;
ⅱ. 如果返回的是引用类型,那么就会直接返回 我们写的 renturn 后面的对象,而内部默认创建的 return 会被忽略。
4.2 对注意点的验证
当返回数值类型:
/*1 提供一个构造函数*/ function Person(){ /* 2 在函数内部通过 this 设置属性和方法*/ this.name = "张三"; this.age = 23; this.sex ="男"; return "zzzzz; } /*3 通过 new 函数() 来创建对象*/ var zhangsan =new Person(); console.log(zhangsan);
输出结果:
当返回引用类型:
/*1 提供一个构造函数*/ function Person(){ /* 2 在函数内部通过 this 设置属性和方法*/ this.name = "张三"; this.age = 23; this.sex ="男"; return Array("zhang",1,3,6); } /*3 通过 new 函数() 来创建对象*/ var zhangsan =new Person(); console.log(zhangsan);
输出结果:
4.3 利用自定义构造函数创建不同类型的对象
function Person(name,age,eating){ this.name = name; this.age = age; this.eat = function(){ console.log(eating); } } function Dog(name,age,eating){ this.name = name; this.age = age; this.eat = function(){ console.log(eating); } } var person1 =new Person("张撒",23,"食物"); var dog1 =new Dog("阿黄",2,"狗粮"); console.log(person1); console.log(dog1); /* 采用类型判断*/ console.log(person1 instanceof Person); console.log(dog1 instanceof Dog);
输出结果:
注意点:所有的对象都是Object类型,因此所有对象 obj1 instanceof Object 的返回值都是true.
总结:
自定义构造函数创建对象能够区分对象的类型
4.3 构造函数创建对象的问题
function Person(name,age,sex){ this.name = name; this.age = age; this.sex =sex; this.showName = function () { console.log(this.name); } } var person1 = new Person("zhangsan",23,"男"); var person2 = new Person("zhangsan",22,"女"); console.log(person1.showName ==person2.showName); //false person1.showName = function () { console.log("123"); } person1.showName(); //123 person2.showName(); //zhangsan
对代码创建对象结构分析如下:
总结:由输出结果以及结构分析,可以看出person1.showName 与 person2.showName 是不同的,他们各占一个内存空间,这样当要创建大量的对象的时候,就会创建出大量同样的 方法,这样会浪费性能空间,那么如何让不同的对象共享同一个方法呢?下一章我将为大家分析 采用原型对象解决方法共享问题。
eating