JavaScript的面向对象
创建对象
ES5没有正式支持面向对象,而是利用原型式进行继承。ES6引入类,是对ES5的类和原型继承进行封装的语法糖。
工厂模式
是指一个接收固定参数的函数,用new Object()的形式,用参数创建对象及其属性和方法。
function create(name,age,job){
let o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
console.log(this.name);
};
return o;
}
let person1 = create("alex",20,"SE");
能够创建多个类似的对象,但是没办法确定对象的类型,它只是Object类型。
构造函数模式
原生构造函数:Object Array,通过自定义构造函数,为自己的对象类型定义属性和方法。
方法特点:
- 没有显示创建对象
- 属性和方法赋值给了this
- 没有return
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
console.log(this.name);
};
return o;
}
let person1 = new Person("alex",20,"SE"); //传统调用方法,新建Person对象
let o = new Object();
Person.call(o,"alex",20,"SE"); //在另一个对象的作用域中调用,以o作为构造函数的this值,属性和方法添加到对象o中
对象特点:
- 实例能够被标识成特定类型了(相对于工厂模式的一大进步)
- 对象的类型判断为Person和Object都可以(自定义对象继承自Object)
console.log(person1 instanceof Person) //true
console.log(person1 instanceof Object) //true
- 对象的constructor属性指向构造函数
console.log(person1.constructor == Person) //true
构造函数的缺点
构造函数定义的方法会在每个实例上都创建一遍。所以每个实例的同一个函数都不是一个实例。
原型模式
解决构造函数模式创建函数实例的缺点,利用函数的prototype(原型),共享属性和方法。
方法特点
- 将构造函数中的值或方法直接赋值给原型
function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 20;
Person.prototype.job = "SE";
Person.prototype.sayName = function(){console.log(this.name);};
let person1 = new Person(); //新建Person对象
person1.sayName(); //"Nicholas"
对象特点
- 每次通过构造函数创建实例的时候,实例内都有_proto_属性可以访问该实例的原型(只限Firfox、Safari、Chrome)
- 构造函数通过prototype属性指向原型,原型通过constructor属性指向构造函数
- 有几个方法建立实例和原型的关系
- isPrototypeOf()
- getPrototypeOf()
属性调用
1 属性查找及覆盖
- 按照属性或方法的名字进行查找,先查找实例本身
- 若实例本身没有,则查找其原型
- 若原型没有,则查找原型的原型,以此类推
因此如果想覆盖原型的属性,那么就在实例中添加一个同名的属性。
2 属性删除
若在实例中或者原型中添加了同名的属性,但是想删除了,那么需要用到delete操作符
delete person1.name;
3 查看属性是否为自己实例的属性
可以用hasOwnProperty()方法看属性是否是实例本身的,是则返回true
person1.hasOwnProperty("name"); //true or false
4 in 操作符
in操作符会在可以通过该对象访问指定属性的时候,返回true,无论是通过对象实例还是对象原型。
console.log("name" in person1) //ture
所以,如果hasOwnProperty返回false in操作符返回true,属性就是在原型上。
继承
原型链
当实例1的原型是原型2的实例,那么就会构成一个 实例1-->原型1(实例2)-->原型2的一个原型链。
介绍原型链有助于理解继承过程,后面会直接介绍继承的方法
如图所示:

确定原型实例关系的方法
- instanceof
- isPrototypeOf()
如果原型出现在这个实例的原型链中,那么就会返回true
方法覆盖和新增
继承了父类之后,经常要新增方法或者覆盖父类的方法,那就要等原型赋值之后,在对原型新增方法或者覆盖方法。
function SuperType(){
this.property=true;
};
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subProperty = false;
}
SubType.prototype = new SuperType();
//新方法
SubType.prototype.getSubValue = function(){
return this.subproperty;
}
//修改旧方法
SubType.prototype.getSuperValue = function(){
return false;
}
注:以对象字面量方式创建原型的方法的时候,相当于重写原型,破坏原来的原型链。
SubType.prototype = new SuperType();
//这样添加新方法,导致原型被重写,上一句无效
SubType.prototype = {
getSubValue(){
return this.subProperty;
}
get SuperValue(){
return this.superProperty;
}
}
原型链继承的问题
原型包含引用值时,不能够实现每个实例封装的特性。所以一般属性值会写在构造函数中,方法写在原型内。
1 但是在原型链中,父原型的实例变成了子实例的原型,属性放在构造函数里也会出现问题了。
2 子类型在实例化的时候,不能给父类型的构造函数传递参数。
所以原型链不会单独进行使用

浙公网安备 33010602011771号