1、面向对象的三大特征:封装、继承、多态。
封装:就是将方法封装在对象中,只给出接口就可以调用,利于维护,避免全局对象污染,
继承:混入式继承(mix-in),for(var i in),将一个对象继承给例外一个对象。
原型继承:利用原型对象中的成员可以被和其相关的对象共享这一特性。
多态:父类引用指向子类的对象(javascript中用不到)
2、创建对象的四种方式
1)、使用字面量创建对象: var obj = {value:1,name:'hyl'},缺点:用一个创建一个,造成资源浪费
2)、使用内置的构造函数创建对象:var obj = new Object();创建了一个空的对象,然后添加成员,obj.name = '1',
缺点:创建的是一个空的对象,还要将对象添加属性,造成代码重复。
3)、封装简单的工厂函数(不推荐使用)
function createObj(name,age){
let obj = {} 或者 obj = new Object();
obj.name = name;
obj.age = age;
return obj;
}
4)、自定义构造函数
function 构造函数名{
this.name = name;
....
}
0.构造函数名首字母需要大写
1.构造函数一般和new关键字一起使用
2.构造函数的返回值默认为新创建的对象,如果手动返回基本数据类型,则不影响返回值,如果返回的是对象(除了null),则新建出来的对象不会返回
取而代之的是return 后面的对象。
构造函数(constructor)的执行步骤:
1.使用new关键字来创建一个对象。
2.调用构造函数,将new创建出来的对象赋值给构造函数内的this.
3.使用this给新创建出来的对象赋值
4.默认返回新创建出来的对象
3、原型
构造函数存在的问题:
构造函数中的方法,每创建一个对象的时候,该对象都会重新的创建一次这个方法,每个独享独占一个方法,
但是该方法的内容完全相同,所以造成资源浪费。
1.解决方法1
将构造函数的方法,进行提取,放在构造函数的外面,在构造函数内部进行引用赋值。
那么创建出来的对象,都会指向构造函数外面的这个函数,达到共享的效果。
问题:全局变量越来越多,造成全局变量污染,代码结构混乱,不容易维护。
2.解决办法2
使用原型
4、原型是什么?
在构造函数创建出来的时候,系统默认会创建一个关联的对象,这个对象就是原型,原型对象默认为空对象
默认的原型对象中会有一个属性 constructor指向该构造函数。
5、原型的作用
原型对象中的成员,可以被使用和它关联的构造函数创建出来的所有对象共享
6、原型对象的使用:
1.使用动态属性特性,为原型添加成员变量。
2.直接替换原型对象。
注意事项:直接替换原型对象,会导致替换之前创建的对象的原型和替换之后创建的对象的原型不一致。
7、原型的使用注意事项
1.使用对象访问属性的时候,会去现在的对象中查找,如果找到了就直接使用,如果未找到,就去原型中找
2.使用对象设置属性的时候,只会在对象的本身进行查找,不会去原型中查找,如果对象本身中没有这个属性,则给该对象新增一个属性
如果对象中有这个属性,修改这个属性。
3.如果在原型对象中有引用类型的属性,那么使用对象进行修改该属性内容,则其他所有跟这个原型对象相关的对象都会受到影响,
Person.prototype.car = {}
var p = new Person();
p.car = {}; //这是修改属性。
p.car.brand = '' //这是修改属性的内容
let a = p.car //查找,如果自身对象没有则在原型对象中查找,然后a.brand
4.一般情况下不会将属性添加到原型对象中
只会讲需要共享的方法添加到原型对象中
8、__proto__
1、这个属性不是标准属性,所以存在通用性问题。
2.一般不推荐使用
3.调试的时候可以使用
4.这个属性是原型中的属性。
9、替换原型的时候注意事项
在新替换的原型中,没有constructor属性,会影响三角结构关系的合理性。
so,在新替换的原型中,手动添加constructor属性,以保证合理性,赋值为关联的构造函数。
Person.prototype = {
constructor: Person
}