- why 面向对象编程?面向美妞编程不行吗?
so 先看下面向对象基本特性(可以理解为“优势”或“碉爆了”的意思):
- 封装:把客观的事物封装成抽象的类,并且类的方法和属性只让可信的类或者对象操作,对不可信的则进行隐藏。
- 继承:通过继承创建的类称为“子类”或者“派生类”,继承的过程,是从一般到特殊的过程。
- 多态:对象多功能,多方法,一个方法的多种表现。
-
对象实例化方法
原始模式:这样的写法有两个缺点,一是如果多生成几个(100个!)实例,写起来就非常麻烦;二是实例与原型之间,没有任何办法,可以看出没有什么联系。
var Car = {
color: 'red',//车的颜色
wheel: 4,//车轮数量
}
var Car2 = {
color: 'blue',
wheel: 4,
}
alert(Car.color);//red
原始模式的改进:通过写一个函数,解决代码重复的问题。
function createCar(color,wheel) {
return {
color:color,
wheel:wheel
}
}
//然后生成实例对象,就等于是在调用函数:
var cat1 = createCar("红色","4");
var cat2 = createCar("蓝色","4");
alert(cat1.color);//红色
工厂模式:原料 > 加工 > 成品出厂
function createCar(weel,color){
//准备原料
var obj = new Object();
//加工
obj.weel = weel;
obj.color = color;
//成品出厂
return obj;
}
// 实例化
var n = createCar(3,'red');
var b = createCar(6,'黄');
console.log(n.color);
构造函数模式
为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。 所谓”构造函数”,其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。加new执行的函数构造内部变化:自动生成一个对象,this指向这个新创建的对象,函数自动返回这个新创建的对象
function CreateCar(weel,color){
//不用自己创建对象
this.weel = weel;
this.color = color;
//不用return返回
}
//实例化
var n = new CreateCar(6,'白里透红');
var b = new CreateCar(8,'五彩斑斓的黑');
构造函数注意事项:
- 此时CreateCar称之为构造函数,也可以称之类,构造函数就是类 。
- n,b均为CreateCar的实例对象。
- CreateCar构造函数中this指向CreateCar实例对象即 new CreateCar( )出来的对象。
- 必须带new 。
- 构造函数首字母大写,这是规范,官方都遵循这一个规范,如Number() Array()。
contructor:这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数,即CreateCar。 - contructor:这时n和b会自动含有一个constructor属性,指向它们的构造函数,即CreateCar。
alert(n.constructor == CreateCar); //true
alert(b.constructor == CreateCar); //true
- 每定义一个函数,这个函数就有一个 prototype 的属性{},
__prop__
指向被实例化的构造函数的prototype,prototype默认带constructor属性,constructor指向构造函数。 - instanceof 运算符:object instanceof constructor运算符,验证构造函数与实例对象之间的关系。
alert(n instanceof CreateCar ); //true
alert(b instanceof CreateCar ); //true
构造函数的问题
构造函数方法很好用,但是存在一个浪费内存的问题。如果现在为其再添加一个方法showWheel。那么,CreateCar就变成了下面这样,这样做有一个很大的弊端,对于每一个实例对象,showWheel都是一模一样的内容,每一次生成一个实例,都必须生成重复的内容,多占用一些内存。这样既不环保,也缺乏效率。
function CreateCar(color,wheel){
this.color = color;
this.wheel = wheel;
this.showWheel = function(){//添加一个新方法
alert(this.wheel);
}
}
//还是采用同样的方法,生成实例:
var n = new CreateCar("红色","4");
var b = new CreateCar("蓝色","4");
alert(n.showWheel == b.showWheel); //false
- Prototype 原型
Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。 这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。__proto__是原型链,指向实例化的函数原型。
function CreateCar(color,wheel){
//属性写构造函数里面
this.color = color;
this.wheel = wheel;
}
//方法写原型里面
CreateCar.prototype.showWheel = function(){
alert(this.wheel);
}
CreateCar.prototype.showName = function(){
alert('车');
}
//生成实例。
var n = new CreateCar("红色","4");
var b = new CreateCar("蓝色","4");
n.showName();//'车'
//这时所有实例的showWheel属性和showName方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。
alert(n.showWheel == b.showWheel );//true
alert(n.showName == b.showName );//true
console.log(n.__proto__ === b.prototype); //true