面向对象:是一种处理问题的思路,是对传统面向过程编程的一种补充和完善;
核心是类和对象的抽象封装和创建,通过创建的各种对象之间互相协作(互相调用函数)完成一个功能的完整流程;
通过面向对象的三大特征封装、继承、多态,来提高程序的健壮性、代码的复用性和功能的强大的扩展性。
1.原生JS中,通过函数来模拟构造函数
构造函数:专门用于被创建对象的函数,函数本身定义一个自定义数据类型,内部通过this来定义各种类型的属性和行为。
function Person(name, age) {
this.name = name;
this.age = age;
this.run = function() { console.log(“锻炼身体”); }
}
构造函数,和new关键字结合起来创建对象
var _obj = new Person(“tom”, 48);
通过对象的引用变量,可以调用对象的属性和行为
console.log(_obj.name);//调用对象的属性
_obj.run()// 调用对象的函数
2.
对象的属性和方法
面向对象处理的核心是类和对象
对象具有属性和方法操作,通常情况下,每个独立的对象的属性值不一定相同,但是同一个类型的对象的行为大致一致。
传统函数存在的问题:
(1)通过构造函数创建的对象,每个对象的数据都是独立的。
(2)构造函数中定义的对象的行为,构成了闭包函数,闭包函数一旦出现,对象的销毁就会变得非常困难。
(3)构造函数创建对象时,每个对象都独立拥有构造函数中定义的方法,这样就会造成有多少个对象就会有多少个重复的对象的方法产生。造成系统资源不必要的损耗。
解决 方案:通过构造函数的原型对象 prototype 来定义公共方法进行处理。3.构造函数的原型prototype
每个构造函数都会有一个原型对象prototype
prototype:原型对象,用于给构造函数添加对象公共使用的属性和方法,优化程序!
添加公共属性:
Person.prototype.species = “人类”;
添加公共函数:
Person.prototype.play = function() {console.log(“游戏中”);}
通过Person这个构造函数创建的对象,都默认拥有species属性和play()函数操作
原生JS中的String、Array等内置对象,就是通过这样的方法进行方法扩展的!
4.面向对象的封装*在JS中,对于面向对象的争议已经存在很长的时间,不可否认的是面向对象确实是适合项目复杂度较高的情况, 更加有利于项目的高效开发和扩展。
*所以原生JS中通过构造函数进行面向对象的模拟实现,但是在ES6中JS已经启用了关键字class以及和面向对象相 关的一系列的使用方式。
*目前在原生JS中对于对象的封装遵循以下的方式:
通过分析之后抽取出来的构造函数中,只定义属性
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
通过分析之后抽取出来的函数操作,尽量都使用构造函数的prototype来进行定义
Person.prototype.eat = function() { // TODO }
Person.prototype.sleep = function() { // TODO }
Person.prototype.play = function() { // TODO }
5.
构造函数继承之apply/call
1).通过apply/call方法实现构造函数的继承
2).apply和call方法的核心,是通过参数来修改当前对象中的this指向
3).Animal(thisArg, arguments)在调用的时候,Animal中的this会被thisArg取代,从而让thisArg指向 Animal中的数据,实现了继承关系
但是通过apply/call实现的继承,不能继承父类prototype声明的属性或者方法
var Animal = function(type, color) {
this.type = type;
this.color = color;
}
var Cat = function(name, age) {
// Animal.apply(this,[type, color]);
Animal.call(this, type, color);
this.name = name;
this.age = age;
}
6.原型继承之prototype
通过另一种继承方式,通过空对象prototype原型链进行继承
function _extends(Child, Parent) {
var F = function() {}
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.super = Parent.prototype;
}
封装好继承函数之后,直接进行使用——这也是项目中经常使用的方式!
var Animal = function () {};
var Cat = function() {};
_extends(Cat, Animal);// 实现Cat继承Animal的功能
7.直接继承protype
通过指定类型和被继承类型的prototype进行绑定来实现继承。
通过Prototype原型进行继承,这样的方式是在第二种方式基础上进行的优化。
Animal = function(){}
Animal.prototype.species = “动物”
var Cat = function(name, color) {
this.name = name;
this.color = color;
}
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat = new Cat(“tom”, “orange”);
8.通过空对象进行继承
第三种方式实现了继承,但是继承者和被继承者之间出现了prototype原型共同指向的问题,这里通过一个中间的空对象进行处理,提升代码质量。
var Animal = function() {}
Animal.prototype.species = “动物”;
var Cat = function(name, age) {
this.name = name;
this.age = age;
}
var F = function(){};
F.prototype = Animal.prototype;
Cat.prototype = new F();
Cat.prototype.constructor = Cat;
##### 实现了Cat和Animal之间的继承关系
通常在项目应用的时候,将继承关系封装成函数方便调用.
function extends (Child, Parent) {
var F = function() {};//空对象
F.prototype = Parent.prototype;// 类型prototype关联
Child.prototype.constructor = Child;// 重新设置
Child.super = Parent.prototype;// 打开父对象的访问途径
}
以上乃是我的片面之解,希望可以帮到大家。