一、使用工厂方法创建对象
由于我们在开发中,很多时候,创建的对象,都具有共同的属性,比如:
var obj = {
name = "孙悟空";
age = 18;
gender = "男";
sayName = function(){
alert(this.name);
}
};
var obj1 = {
name = "猪八戒";
age = 18;
gender = "男";
sayName = function(){
alert(this.name);
}
};
obj与obj2就只有名字是不一样的,如果我们要创建很多这样的对象,这样一个一个创建十分的麻烦,于是就有了下面的使用工厂方法创建对象。
/** 使用工厂方法创建对象
* 通过该方法可以大批量的创建对象
*/
function createPerson(name, age, gender){
//创建一个新的对象
var obj = new Object();
//向对象中添加属性
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.sayName = function(){
alert(this.name);
};
//将新的对象返回
return obj;
}
// 创建三个不同的对象
var obj2 = createPerson("猪八戒",28,"男");
var obj3 = createPerson("白骨精",16,"女");
var obj4 = createPerson("蜘蛛精",18,"女");
console.log(obj2); //控制台输出{name="猪八戒", age=28, gender="男"}
obj2.sayName(); //alert弹窗输出猪八戒
二 、构造函数
使用工厂方法创建的对象,使用的构造函数都是Object
- 所以创建的对象都是Object这个类型,就导致我们无法区分出多种不同类型的对象
比如我们再创建一个狗的类型:
function createDog(name , age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sayHello = function(){
alert("汪汪~~");
};
return obj;
}
//创建一个狗的对象
var dog = createDog("旺财",3);
console.log(dog);
console.log(obj4); //发现这两个都是object类型,无法区分
此时就引入了构造函数
-
创建一个构造函数,专门用来创建Person对象的
- 构造函数就是一个普通的函数,创建方式和普通函数没有区别, 不同的是 构造函数习惯上首字母大写
- 构造函数和普通函数的区别就是调用方式的不同
- 普通函数是直接调用,而构造函数需要使用new关键字来调用
-
构造函数的执行流程:
- 立刻创建一个新的对象
- 将新建的对象,设置为函数中this,在构造函数中可以使用this来引用新建的对象
- 逐行执行函数中的代码
- 将新建的对象作为返回值返回
-
(※)this的指向情况更新(上一节课只讲了前两种):
- 当以函数的形式调用时,this是window
- 当以方法的形式调用时,谁调用方法this就是谁
- 当以构造函数的形式调用时,this就是新创建的那个对象
function Person(name , age , gender){
alert(this); //这里的this 就是用Person构造函数新建的对象per
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function(){
alert(this.name);
};
}
var per = new Person("孙悟空",18,"男");
var per2 = new Person("玉兔精",16,"女");
var per3 = new Person("奔波霸",38,"男");
看到这里会觉得,构造函数和工厂方法创建对象很相似,但真的一样吗?
console.log(per);
console.log(per2);
console.log(per3);
输出结果如下:
我们再创建一个简单的Dog的构造函数,并进行实例化。
function Dog(){
}
var dog = new Dog();
console.log(dog);
所以我们可以知道:
- 使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类。
- 我们将通过一个构造函数创建的对象称为是该类的实例。
JS关键字——instanceof用法
Person和Dog是两个不同的类,那么它们是否有本质上的不同呢?
- 使用instanceof可以检查一个对象是否是一个类的实例
- 语法:
- 对象 instanceof 构造函数
- 如果是,则返回true,否则返回false
console.log(per instanceof Person); //true
console.log(dog instanceof Person); //false
但所有的对象都是Object的后代,所以任何对象和Object左instanceof检查时都会返回true
console.log(per instanceof Object); //true
console.log(dog instanceof Object); //true
三 、构造函数改进
在之前的Person构造函数中,
//创建一个Person构造函数
function Person(name , age , gender){
alert(this); //这里的this 就是用Person构造函数新建的对象per
this.name = name;
this.age = age;
this.gender = gender;
// 构造函数内部创建sayName方法
this.sayName = function(){
alert(this.name);
};
}
- 在Person构造函数中,为每一个对象都添加了一个sayName方法,目前我们的方法是在构造函数内部创建的
- 也就是构造函数每执行一次就会创建一个新的sayName方法,也就是所有实例的sayName都是唯一的。
- 如果所有方法都这样写在构造函数内部,就会导致了构造函数执行一次就会创建一个新的方法,执行10000次就会创建10000个新的方法,而10000个方法都是一摸一样的。这是完全没有必要,完全可以使所有的对象共享同一个方法。
改进后:将sayName方法在全局作用域中定义
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
//向对象中添加一个方法
this.sayName = fun;
}
//将sayName方法在全局作用域中定义
function fun(){
alert("Hello大家好,我是:"+this.name);
};
//创建一个Person的实例
var per = new Person("孙悟空",18,"男");
var per2 = new Person("猪八戒",28,"男");
per.sayName();
per2.sayName(); //per和per2其实调的是同一个函数
console.log(per.sayName == per2.sayName); // true
但是将函数定义在全局作用域,污染了全局作用域的命名空间(比如有另一个函数不小心也叫了fun这个名字)
而且定义在全局作用域中也很不安全(比如共同开发时,都在全局作用域里定义函数和变量,很容易重复,覆盖)
所以尽量不要在全局作用域中写东西。
于是引入了原型