面向对象
1.面向对象是一个比较虚的东西,js是面向对象的语言,一切皆对象。
2.什么是面向对象呢?
生活中有一些个东西呀,比如说一个电视,咱们也不知道里面的工作原理吧?但是咱们会按按钮呀~~~
咱们居然不知道原理就可以用了哎,好神奇
Date对象咱们知道哈,这个货有个getFullYear的方法吧,那么大家想一下,这个东西是怎么知道现在是哪一年的呢? 不了解吧,没关系,咱们会用呀,哦吼吼
,其实像这样的使用者可以不需要知道原理就可以使用它的功能呢,就叫面向对象啦~哦吼吼
什么是对象呢:是一对大象吗?no!
咱们不知道一些东西的内部长什么样子,但是咱们知道这个东西的功能和操作方法,这个货就是对象~~~
就像js里面的那些个对象,date呀,数组呀,咱们不知道内部是个什么原理,但是咱们知道它的属性和方法
其实对象就是一个整体,对外提供一些功能和操作是吧
那么面向对象其实是一种通用思想,可以在编程中用,也可以在生活中用,只不过在生活中这种思想不叫面向对象而已
在编程中呢,如何在使用某些功能来实现效果的过程中可以只关注功能,不关注内部细节的编程思想,就是面向对象
就像jq,咱们知道jq可以用$(".a")来获取一个jq的dom对象,咱们学习jq不需要去学习jq是怎么去获取dom对象的,只需要学习
用jq获取对象的那个操作就ok了,那么jq是不是就是用面向对象编程思想来编写的一个类库嘞
3.面向对象的特点
抽象:抽指把核心的东西抽出来,把与我们要解决的问题有关的东西拿出来摆在面前
比如咱们写一个员工管理系统,那么员工的身高体重什么的咱们是不是不需要去管呀,咱们只需要把姓名,工号,工资啥的 整出来是不是就好了呢
封装:让使用对象的人不考虑内部实现,只考虑功能使用 把内部的代码保护起来,只留出一些个api接口供用户使用
继承:就是为了代码的复用,从父类上继承出一些方法和属性,子类也有自己的一些属性
比如,咱们有一匹母马,咱们又想要一头骡子了,那怎么办,去买一头吗?不需要呀,咱们去借头公驴配个种就可以了呀
,那么这个骡子,是不是就继承了咱们原有的那个母马的基因了呀,这就是继承咯
多重继承是什么呢,盒子有一个功能是装东西,汽车有个功能是能跑,那咱们把汽车和盒子的功能都继承了,是不是就 是大卡车了呀
多态,对于咱们的js这种弱类型语言来说其实意义不大。
4.对象的组成
方法 函数:过程、动态的
属性 变量:状态、静态的
5.this 当前的方法属于谁就是谁
例如点击事件里的this,其实就是触发事件的那个dom对象的onclick方法里的this,当然是人家自己咯
再比如说一个函数里的this,这个函数都属于window的一个方法,当然里面的this也是window咯
还有哦,不要在系统对象上面添加属性和方法,这样不太好
那么在谁身上加呢?在object这个对象身上,别的date呀array呀,这些对象都是有一些个好玩的功能的,
object也就自己最强大的一个功能就是,没有功能~~~~ 这样咱们就可以随意给他加属性和方法而不用去想会不会覆盖了
6.创建对象的方法
1.基础创建
var obj=new Object();
obj.name='allen';
obj.qq='983357618';
obj.showName=function() {
alert(this.name)
}
但是这样又会有问题,比如说,我要创造一百个,就要这么写一百次,太麻烦了
2.工厂方式 通过构造函数
function createPerson(name,qq){
// 原料
var obj=new Object();
// 加工
obj.name=name;
obj.qq=qq;
obj.showName=function() {
alert(this.name)
}
// 出厂
return obj;
}
var obj1=createPerson("allen",'985629856')
var obj2=createPerson("john",'9829856');
这样也没问题哦,但是有个情况啦,注意
alert(obj1.showName)//function(){alert(this.name)}
alert(obj2.showName)//function(){alert(this.name)}
结过都一样哦,但是
alert(obj1.showName==obj2.showName) //false
这里居然是不一样!!我的天,这样的话那我一百个对象就有一百个不一样的方法要占用内充~~~~
也就说会有两种问题:
创建对象没有用到new 感觉心里空落落的
方法都不一样的话太占据空间了~~~~
安啦,去解决!!
function createPerson(name,qq){
// 原料 系统偷偷摸摸做的
// var this=new Object();
// 加工
this.name=name;
this.qq=qq;
this.showName=function() {
alert(this.name)
}
// 出厂 系统偷偷摸摸做的
// return this;
}
var obj1=new createPerson("allen",'985629856')
var obj2=new createPerson("john",'9829856');
这样的话代码又少了很多,很爽,而且还有new了,其实就是利用了一个概念,任何函数都可以new一下
比如
function aa(){};alert(new aa())
结果就是object哦
那它就变成对象啦,那它里面的this就是它new出来的自己啦~~~~
new操作符做的事:
创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
属性和方法被加入到 this 引用的对象中。
新创建的对象由 this 所引用,并且最后隐式的返回 this 。
但是这样还是有一个问题,
alert(obj1.showName==obj2.showName) //false
这里还是false,还是占用很多空间.........
没关系,再去解决,这里,就用到下个概念了
7.prototype 原型~~~
先来看个例子,比如说有两个人A、B去买了同样的手机,A买完手机后又买了个手机壳,那么B看见人家有手机壳就不干了,去找卖手机的理论,为什么他
有我没有,这就不讲道理了吧,毕竟人家那个壳子是A自己花钱又买的,B当然没有了,但是如果说买手机的时候送手机壳的话,这样B就不用去买了,AB
都有了呢,皆大欢喜。
var arr1=[1,2,3];
var arr2=[4,5,6];
arr1.sum=function(){
var result=0;
for(var i=0;i
}
return result;
}
alert(arr1.sum()) //6
alert(arr2.sum()) //error
就像这个例子,arr2根本没有这个方法嘛,想要的话,只能自己去添加咯,再写一遍
arr2.sum=function(){
var result=0;
for(var i=0;i
}
return result;
}
但是这样就比较繁琐了,每次都写一遍是吧,而且都还要占用空间,那么怎么能改一改呢,能不能把这个方法放到一个他两都能用到的地方呢???
大家再想一下哈,在html+css布局里面呢,有十个一样的div,想给他们加一个背景色是黄色,咱们可以给他们的行内都写上style=“background:
yellow;”,但是咱们是不是也可以来创建一个类名为yellow,里面写上背景为黄色,然后给这些个div都加上这个类名就棒棒哒了呢~~
其实这个通用样式的类名放到js里就是原型了呢
var arr1=[1,2,3];
var arr2=[4,5,6];
Array.prototype.sum=function(){
var result=0;
for(var i=0;i
}
return result;
}
alert(arr1.sum()) //6
alert(arr2.sum()) //15
function createPerson(name,qq){
this.name=name;
this.qq=qq;
}
createPerson.prototype.showName=function(){
this.showName=function() {
alert(this.name)
}
}
那么上一个知识点的那两个问题可就都解决了哦~~~
这样也就发展出一个广泛的一个写法了哦
用构造函数去写自有属性和方法,用原型去写共有的属性和方法,这种方式叫混合方式
那么学到现在呢,其实咱们也就对面向对象有一些了解了,它就是一种模式,一种思想,咱们以前写的还是面向过程的多,但是基本所有的效果和功能都可以用面向对象或者面向过程去写,没有固定的非得用什么,只不过呢,面向对象针对某些情况呢要好一些。
1.三大对象类型
本地对象(非静态对象):object、function、array、string、boolean、number、date等对象
内置对象(静态对象 不能new):global(跟鬼一样,说的人多,见得人少,其实只是一个概念)、math
宿主对象:bom、dom
2.命名空间
在这一块内容里面还牵扯到这个命名空间,其实概念也很简单了,比如咱们好几个人一起编写一个js文件,其中A写了一个函数是getUser,B也写了一个函
数是getUser,这样就会造成乱七八糟的冲突,那怎么办呢,可以给每个人来一个json对象,然后把他们自己的方法写到那个地方去
var ghb={};
ghb.getUser=function(){alert(1)};
ghb.getUser();
var max={};
max.getUser=function(){alert(2)};
max.getUser();
3.继承
继承其实就是继承父类的属性和方法啦~~~
function A(){
this.aaa='abc'
}
A.prototype.show=function(){
alert(this.aaa)
}
var mA=new A();
// mA.show()
function B(){
A.call(this)
}
B.prototype= A.prototype
var mB=new B();
mB.show();
先看call,咱们知道哈,如果有个函数A,执行的话就直接写个A(),其实写成 A.call();也是可以的
function A(){
alert(this)
}
A.call();
大家看这样的写法,this当然是window咯,就会弹出window,现在我不想让它谈window,来弹个鼻屎吧,那就可以这么来
function A(){
alert(this)
}
A.call('鼻屎');
现在大家晓得了哇,call里面传的第一个参数就可以冒充为那个函数里面的this呢~~棒棒哒,如果这个函数有形参,当然call后面的参数也可以传咯
function A(a){
alert(this+'\n'+a)
}
A.call('鼻屎','123');
好,call看完了,再来看那个B继承A的原型的时候的一个问题
function A(){
this.aaa='abc'
}
A.prototype.show=function(){
alert(this.aaa)
}
var mA=new A();
function B(){
A.call(this)
}
B.prototype= A.prototype;
B.prototype.fn=function(){
alert(123)
}
var mB=new B();
mB.fn();
mA.fn();
这样mB和mA居然都有这个方法了,明明只给B的原型加了啊,其实这里A和B的原型还是同一个东西,要改变当然都改变咯,参照数组的那个经典案例去理解哦~~~
好吧,有点乱,来整理一下继承的方法,百度上呢有的说有两种,有的说有五种,并且名字还都不一样那到底都是些什么呢,来看看
1.使用对象冒充实现继承
实现原理:让父类的构造函数成为子类的方法,然后调用子类的 该方法,这个时候,这个方法里面的this就指向子类,通过this关键字给所有的属性和方法赋值
function Parent(firstname)
{
this.fname=firstname;
this.age=40;
this.sayAge=function()
{
console.log(this.age);
}
}
function Child(firstname)
{
this.parent=Parent;
this.parent(firstname);
delete this.parent;
this.saySomeThing=function()
{
console.log(this.fname);
this.sayAge();
}
}
var mychild=new Child("李");
mychild.saySomeThing();
2.采用call方法改变函数上下文实现继承(该种方式不能继承原型链,若想继承原型链,则采用5混合模式)
实现原理:改变函数内部的函数上下文this,使它指向传入函数的具体对象
function Parent(firstname)
{
this.fname=firstname;
this.age=40;
this.sayAge=function()
{
console.log(this.age);
}
}
function Child(firstname)
{
this.saySomeThing=function()
{
console.log(this.fname);
this.sayAge();
}
this.getName=function()
{
return firstname;
}
}
var child=new Child("张");
Parent.call(child,child.getName());
child.saySomeThing();
3.采用Apply方法改变函数上下文实现继承(该种方式不能继承原型链,若想继承原型链,则采用5混合模式)
实现原理:改变函数内部的函数上下文this,使它指向传入函数的具体对象
function Parent(firstname)
{
this.fname=firstname;
this.age=40;
this.sayAge=function()
{
console.log(this.age);
}
}
function Child(firstname)
{
this.saySomeThing=function()
{
console.log(this.fname);
this.sayAge();
}
this.getName=function()
{
return firstname;
}
}
var child=new Child("张");
Parent.apply(child,[child.getName()]);
child.saySomeThing();
4.采用原型链的方式实现继承
实现原理:使子类原型对象指向父类的实例以实现继承,即重写类的原型
function Parent()
{
this.sayAge=function()
{
console.log(this.age);
}
}
function Child(firstname)
{
this.fname=firstname;
this.age=40;
this.saySomeThing=function()
{
console.log(this.fname);
this.sayAge();
}
}
Child.prototype=new Parent();
var child=new Child("张");
child.saySomeThing();
5.采用混合模式实现继承
function Parent()
{
this.sayAge=function()
{
console.log(this.age);
}
}
Parent.prototype.sayParent=function()
{
alert("this is parentmethod!!!");
}
function Child(firstname)
{
Parent.call(this);
this.fname=firstname;
this.age=40;
this.saySomeThing=function()
{
console.log(this.fname);
this.sayAge();
}
}
Child.prototype=new Parent();
var child=new Child("张");
child.saySomeThing();
child.sayParent();
那,这里再来一个继承顺序 本身方法→本身原型→父对象方法→父对象原型→顶层对象原型
Object.prototype.say=function() {
alert("我是顶层的方法");
}
function person () {
this.say=function() {
alert("我是父类的方法");
}
}
person.prototype.say=function() {
alert("我是父类原型的方法");
}
function study () {
this.say=function() {
alert("本身的方法");
}
}
study.prototype=new person;
study.prototype.say=function() {
alert("本身原型的方法");
}
var zhangsan=new study ();
alert(zhangsan.say)
4.多态,什么是多态呢 多态用途在于做面向对象开发时,需要有一个方法不变,但是它接收的参数类型是变化的,就可以使用多态。 看这个例子哦
多态有利于代码的维护和扩展,这里我们可以考虑,如果食物加入桃子,动物加入猴子,可以看到Master的feed函数不需要变化。