面向对象编程
面向对象的三大特征:继承,封装,多态
ES5的面向对象
ES5中用构造函数来模拟类的概念,可以根据传入的参数不同来定制具有不同属性或方法的实例,因此构造函数中存放的是私有的属性。
function Person(data){ //构造函数首字母大写
this.name = data.name;
this.age = data.age;
this.sex = data.sex;
}
var simple = new Person() //new执行后,会在构造函数内部隐式地声明一个对象,然后执行其他代码往该对象添加属性或方法,this也会指向这个对象,最后返回该实例对象(实例化)
而每个构造函数会存在一个原型的概念(一个对象),里面存放的是公有属性,为每一个由构造函数而构造出来的实例所共有。可由构造函数Person.prototype或实例obj.__proto__访问得到(Person.prototype === obj.__proto__)
Person.prototype = {
constructor: Person, //这个属性用于指向原型自己的构造函数,如果用赋值方式定义prototype请务必注意添加这一条,否则constructor会默认指向Object
eat:function(){
console.log('eating');
},
game:function(){
console.log('playing');
}
}
//在添加公共方法不多的情况下推荐使用这种方法添加
Person.prototype.learn = function(){
console.log('learn hard');
}
JavaScript中所有的对象都是它对应的构造函数创建出来的,由于所有的构造函数的原型都是对象,因此对象的构造函数是最顶层的,构成一个原型链的概念。即底层构造函数的实例会同时拥有对应构造函数原型的公有属性以及Object原型的公有属性,同时遵循就近原则,同名的属性会以最接近实例的构造函数的原型为准。
ES6的面向对象
ES6中由类进行定义,用class关键词来声明。
class Fn2{
constructor(data){ //私有属性写在constructor中
this.name = data.name;
}
//原型上的公有方法写在外面,仅限函数不能是属性值
add(){
console.log("add");
}
}
const obj2 = new Fn2();
继承
ES5的方法:
function Person(data){ //父类
this.name = data.name;
}
Person.prototype = {
constructor: Person,
eat:function(){
console.log('eat');
}
}
function Medi(){} //目的让儿子的原型成为父亲实例对象以继承父亲的公有属性,为了避免原型中掺杂父亲无益的私有属性,所以建立一个中介
Medi.prototype = Person.prototype;
function People(data){
Person.call(this,data); //继承父亲私有属性
}
People.prototype = new Medi(); //通过中介继承父亲公有属性
ES6的方法:
class Fn2{ //父类
constructor(data){
this.name = data.name;
}
add(){
console.log('es6');
}
}
class Fn1 extends Fn2{
constructor(data){
super(data); //这里必须在最前面执行,接受参数往子类的实例中添加父亲的私有属性然后返回,相当于es5中Fn2.call(this, data)
}
//儿子的原型方法
}
静态方法
构造函数调用的私有方法
ES5:
Person.getAge = function(){
console.log('static');
}
ES6:
class Fn2{
constructor(data){}
static getAge(){
console.log('static');
}
}
super 关键字
- super在作为函数使用时,只能在子类的构造函数里去使用,在别的地方调用一定报错
- super作为对象去使用
- 在子类的公共方法和构造函数中,指代父类的原型对象,不能打印出来
- 在子类的静态属性中,指代父类本身(构造函数)