在此由于篇幅较长,请大家不要分断阅读,思路是连在一块的,写在一起是为了便于大家思考。
普通函数
1.首先我们创建一个对象 简单的方法就是
var obj = {
name: '李华',
age: '13',
sayName: function() {
alert(this.name);
}
}
当我们需要创建多个对象的时候,也许我们会直接复制粘贴,但是如果有很多个,那么复制粘贴无意义显得很low,在此我们知道函数可以将很多像似的操作封装成一个函数,这里创建对象也是
function createPerson(name, age, sex) {
var obj = new Object() //创建一对象
obj.name = name;
obj.age = age;
obj.sex = sex;
obj.sayName = function() {
alert(this.name);
};
// 用函数创建对象肯定是为了后面的操作,我们需要用return将对象返回给我们
return obj
}
var obj1 = createPerson('ayu', '21', '男');
obj1.sayName() //ayu
console.log(obj1); //Object
在此呢我们利用工厂函数创建了一个用来创建对象的函数,我们只需要在里面传入参数就可以快速创建对象并且拿到里面的值来进行操作,说它是工厂函数,因为无论我们创建任意类型的对象,显示都是object,比如创建人的对象和动物的对象,我们区分不了完全区分不了,即使我们是用2个函数来创建的
总结 :使用工厂函数创建对象,使用的构造函数都是object,所以创建的对象类型都是object类型,导致我们无法区分出多种不同类型的对象,这种方法我们用的不多,有很大的局限性
由此我们需要当我们利用函数来创建对象的时候能够区分对象类型的不同
由此引入构造函数
构造函数与普通函数的区别就是调用方式的不同,作用也不同
普通函数直接调用
构造函数需要使用new关键字调用,构造函数用来新创建 实例对象 , 且不需要用return返回对象
四.构造函数的执行流程
1.立刻在堆内存中创建一个新的对象 //对象在外部可以实时引用,类似于全局变量 2.将新建的对象设置为函数中的this //this对象为构造函数本身,this后可以添加成员变量 3.逐个/逐行执行函数中的代码 4.将新建的对象作为返回值 //return this self
当我们使用同一个构造函数创建对象时,我们称它们为一类对象,也将构造函数称之为一个类,就避免了开头我们利用工厂函数创建对象而无法区分不同类的对象
我们将由一个 构建函数创建的对象,称之为该类的实例
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var per = new Person('孙悟空', '22', '男');
console.log(per);
function Dog() {
}
var dog = new Dog();
console.log(dog);
instanceof
检查一个对象是否为一个类的实例(就是看由构造函数创建的对象是否属于构造函数,是返回true,反则返回false
在此处我们引入下一个值得我们思考的点 -构造函数公共属性的书写位置
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sayName = function() {
console.log(this.name);
}
}
var per1 = new Person('孙悟空', '22', '男')
var per2 = new Person('沙和尚', '12', '男')
console.log(per1.sayName == per2.sayName); //false
我们可以看到当我们想创建同一类对象的时候,利用构造函数可以简单的帮我们实现,但是他们调用的方法不同,因为构造函数的this指向的就是构造函数创建的对象本身,而对象的方法也指向对象的本身,如果此时我们需要创建10000个对象,我们前面3个属性都可以简单重复调用一个函数从而得到,但是他们的方法我们却创建了10000个,在此就觉得很麻烦,我们需要看看能不能想利用函数的思想将这个方法也封装到一个函数
由此可以推出下例
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sayName = fun
}
function fun() {
console.log(this.name);
}
var per1 = new Person('孙悟空', '22', '男')
var per2 = new Person('沙和尚', '12', '男')
console.log(per1.sayName == per2.sayName); //true
这里我们将方法写在全局作用域中定义,确实可以提高效率, 但也有不足
不足 :将函数定义在全局作用域中,污染了全局作用域的命名空间,其他函数不能用这个类名,
而且定义在全局作用域中也不安全,别人开发的使用fun会将我们定义的fun覆盖
在此处我们引入下一个值得我们思考的点 原型prototype的引入价值
我们创建的每一个函数(普通函数/构造函数)都会向函数中添加一个属性prototype,这个属性对应着每一个对象,这个对象我们称之为 原型对象
构造函数可以实例化对象
如果函数以普通函数来调用prototype没有任何作用
当函数以构造函数的形式来调用时,它创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过proto来访问
作用 :原型对象就像一个公共的区域,所有的同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到该对象中
当我们访问对象的一个属性或者方法时,它会现在对象自身中寻找,如果有则直接使用,如果没有则回去原型对象中寻找,原型对象中如果有,则直接调用
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.a = 123;
Person.prototype.sayHi = function() {
console.log('我是原型中的方法');
}
var p1 = new Person()
var p2 = new Person()
p1.a = '我是p1的a';
p1.sayHi = function() {
console.log('hello');
}
console.log(p1.a); //我是p1的a
p1.sayHi(); //hello
console.log(p2.a); //123
p2.sayHi(); //我是原型的方法
以后我们创建构造函数的时候,可以将对象共有的属性和方法,统一添加到构造函数的原型对象中,这样就不用分别为每一个对象添加,也不会影响全局作用域,就可以使每一个对象都具有这个属性和方法