JS面向对象
第一课时 入门基础
知识点:
- 操作系统就是个应用程序
- 只要是应用程序都要占用物理内存
- 浏览器本身也是一个应用程序
- 浏览器本身只懂得解析
HTML
- 调用浏览器这个应用程序的一个功能绘制
1、javascript介绍
-
JavaScript
操作DOM
的本质是=获取+触发+改变 -
目的:就是用来操作内存中的
DOM
节点- 修改
DOM
节点的属性 - 过
javascript
语法组织逻辑代码操作DOM BOM(window)
它包含了DOM
DOM(document)
script
脚本推荐放在最下边好处:防止因网络问题,页面加载时间长,出现空白;即便网络问题,浏览器也把DOM
加载渲染完成,等待从服务端下载完js
脚本,出现效果css
不放在最下面原因通俗地讲:好比先穿好衣服在出去,浏览器先把css
样式准备好,在加载结构层,使得页面有样子;如果放在下面,因为页面是从上往下加载,没有css
,就剩下裸露的标签,很难看,使得用户体验不好
- 修改
2、基于对象的内存管理
javascript
就是来操作这些对象- 通过逻辑组织对象之间的关系和行为
- 如何操作这些对象?通过变量引用
3、变量
- 变量本质是一个空盒子,里面记录了一个内存地址,使能找到内存中的对象,保存了指向具体的实在的东西的地址
- 变量存在栈中,对象存在堆中
- 变量的意义:方便我们去操作对象
- 变量的几种引用方式
- 指针(
C
语言中叫法) - 引用(
Java
) - 变量
- 指针(
- 例如:
var b = document.body
含义:把body
这个对象在内存中的地址放到b变量里面,变量b
(b
是内存地址的别名)本身也存在内存中,以后的操作是针对body
这个地址
- 变量命名规范
- 由字母(
a-zA-Z
)数字(0-9
)下划线(_
)以及美元符号($
) - 不能由数字开头
- 命名尽量用英文并且具有一定的含义
- 如果有多个英文单词,后面单词的首字母大写
- 不能使用关键字
- 首字母不要大写,大写是有特殊含义的
- 由字母(
DOM在内存中的一些图示
第二课时
回顾上节:
-
1、
javascript
介绍 -
2、基于对象的内存管理
-
javascript
就是来操作这些对象- 通过逻辑组织对象之间的关系和行为
- 如何操作这些对象?通过变量引用
- 3、变量
知识点:
1、 window
作用域
- 只要在
script
标签中定义的变量,默认就在window
的作用域之下 - 默认就是
window
这个对象里面写代码
2、数据类型
如何判断js中的数据类型:
-
typeof
、instanceof
、constructor
、prototype
方法比较 -
如何判断
js
中的类型呢,先举几个例子:
vara ="iamstring.";
varb =222;
varc= [1,2,3];
vard =newDate();
vare =function(){alert(111);};
varf =function(){this.name="22";};
最常见的判断方法 : typeof
alert(typeofa) ------------> string alert(typeofb) ------------> number alert(typeofc) ------------> object alert(typeofd) ------------> object alert(typeofe) ------------>function alert(typeof f) ------------>function
- 其中
typeof
返回的类型都是字符串形式,需注意,例如:
alert(typeofa =="string") ------------->true
alert(typeofa ==String) --------------->false
- 另外
typeof
可以判断function
的类型;在判断除Object
类型的对象时比较方便。
判断已知对象类型的方法 : instanceof
alert(c instanceofArray) --------------->true alert(d instanceofDate) alert(f instanceofFunction) ------------>true alert(f instanceoffunction) ------------>false
- 注意 :
instanceof
后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。
根据对象的 constructor
判断 : constructor
alert(c.constructor === Array) ---------->true alert(d.constructor === Date) ----------->true alert(e.constructor === Function) ------->true
-
注意:
constructor
在类继承时会出错 -
例子:
functionA(){};
functionB(){};
A.prototype = newB();//A继承自B
varaObj =newA();
alert(aobj.constructor === B) -----------> true;
alert(aobj.constructor === A) -----------> false;
- 而
instanceof
方法不会出现该问题,对象直接继承和间接继承的都会报true
:
alert(aobj instanceofB) ---------------->true; alert(aobj instanceofB) ---------------->true;
- 言归正传,解决
construtor
的问题通常是让对象的constructor
手动指向自己:
aobj.constructor = A; //将自己的类赋值给对象的constructor属性
alert(aobj.constructor === A) -----------> true;
alert(aobj.constructor === B) -----------> false;//基类不会报true了;
通用但很繁琐的方法 : prototype
alert(Object.prototype.toString.call(a) === ‘[objectString]’) ------->true;
alert(Object.prototype.toString.call(b) === ‘[objectNumber]’) ------->true;
alert(Object.prototype.toString.call(c) === ‘[objectArray]’) ------->true;
alert(Object.prototype.toString.call(d) === ‘[objectDate]’) ------->true;
alert(Object.prototype.toString.call(e) === ‘[objectFunction]’) ------->true;
alert(Object.prototype.toString.call(f) === ‘[objectFunction]’) ------->true;
- 大小写不能写错,比较麻烦,但胜在通用。
- 通常情况下用
typeof
判断就可以了,遇到预知Object
类型的情况可以选用instanceof
或constructor
方法
Javascript的数据类型有六种(ES6新增了第七种 Symbol
)
- 数值(
number
):整数和小数(比如1和3.14) - 字符串(
string
):字符组成的文本(比如”Hello World”) - 布尔值(
boolean
):true(真)和false(假)两个特定值 undefined
:表示 未定义 或不存在,即此处目前没有任何值null
:表示空缺,即此处应该有一个值,但目前为空- 对象(
object
):各种值组成的集合 - 通常,我们将数值、字符串、布尔值称为原始类型(
primitive type
)的值,即它们是最基本的数据类型,不能再细分了。而将对象称为合成类型(complex type
)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。至于undefined
和null
,一般将它们看成两个特殊值
内存中一共分为几种对象:
- 变量
DOM
对象- 常量
- 自定义对象
数据类型转换
转换函数
toString()
转换为字符串,在JavaScript中所有数据类型都可以转换为string
类型
varn1 =12;
varn2 =true;
vara = [1,2,3];
varo = {};
functionf(){}
n1.toString(); //"12"
n2.toString(); //"true"
a.toString(); //"1,2,3"
o.toString(); //"[object Object]"
f.toString(); //"function f(){}"
-
parseInt()
解析出一个string
或者number
类型的整数部分,如果没有可以转换的部分,则返回NaN
(not a number
)varn1 ="12"; varn2 ="23hello"; varn3 ="hello"; parseInt(n1);//12 parseInt(n2);//23 parseInt(n3);//NaN
parseFloat()
解析出一个string
的浮点数部分,如果没有可以转换的部分,则返回NaN
(not a number
)
varn1 ="1.2.3"; varn2 ="1.2hello" varn3 ="hello" parseFloat(n1);//1.2 parseFloat(n2);//1.2 parseFloat(n3);//NaN
强制类型转换
Boolean(value)
- 把给定的值转换成Boolean
型
Boolean(123);//true
Boolean("");//false
Boolean([]);//true
Boolean({});//true
Boolean(null);//false
Boolean(undefined);//false
Number(value)
-把给定的值转换成数字(可以是整数或浮点数)
Number("123");//123
Number("123h");//NaN
Number(true);//1
Number(false);//0
Number(undefined);//NaN
Number(null);//0
Number([]);//0
Number({});//NaN
-
String(value)
- 把给定的值转换成字符串String(123);//"123" String([1,2]);//"1,2" String(undefined)//"undefined" String(null)//"null" String({})//"[object Object]"
隐式转换
- 数字+字符串:数字转换为字符串
console.log(12+"12")
; //1212 - 数字+布尔值:
true
转换为1
,false
转换为0
console.log(12+true)
; //13 - 字符串+布尔值:布尔值转换为true或false
console.log("hello"+true)
; //hellotrue
- 布尔值+布尔值
console.log(true+true)
; //2
null和undefined
undefined
表示一种未知状态,声明了但没有初始化的变量,变量的值时一个未知状态。访问不存在的属性或对象window.xxx
)方法没有明确返回值时,返回值是一个undefined.
当对未声明的变量应用typeof
运算符时,显示为undefined
。null
表示尚未存在的对象,null
是一个有特殊意义的值。可以为变量赋值为null
,此时变量的值为“已知状态”(不是undefined
),即null
。(用来初始化变量,清除变量内容,释放内存)
undefined==null//结果为true,但含义不同。
undefined===null//false,两者类型不一致,前者为“undefined”,后者为“object”
3、javascript脚本执行顺序
- 第一步定义: 分为
var
定义 和函数定义function
- 第二步执行: 其他所有
- 先从上往下定义完所有的后,再从上往下执行 除了
var
function
定义外的 其他都是执行 如:赋值 函数调用 - 在栈里面找到的,就不去堆里面找,因为栈空间小,就近原则【总之:先在栈里面找,找不到再去堆里面找】在栈里面开辟,就能找到堆里面的地址 如:
var b = function(){}
总结一下 ==
运算的规则:(隐式转换)
-
JS
中的值有两种类型:原始类型(Primitive
)、对象类型(Object
)。 -
原始类型包括:
Undefined
、Null
、Boolean
、Number
和String
等五种。 -
Undefined
类型和Null
类型的都只有一个值,即undefined
和null
;Boolean
类型有两个值:true
和false
;Number
类型的值有很多很多;String
类型的值理论上有无数个。 -
所有对象都有
valueOf()
和toString()
方法,它们继承自Object
,当然也可能被子类重写 -
undefined == null
,结果是true
。且它俩与所有其他值比较的结果都是false
。 -
String == Boolean
,需要两个操作数同时转为Number
。 -
String/Boolean == Number
,需要String/Boolean
转为Number
。 -
Object == Primitive
,需要Object
转为Primitive
(具体通过valueOf
和toString
方法)
第三课时
上节回顾:
-
1、
window
作用域- 只要在
script
标签中定义的变量,默认就在window
的作用域之下 - 默认就是
window
这个对象里面写代码
- 只要在
-
2、数据类型
number
:数字string
:字符类型,必须用引号引起来boolean
:布尔类型true
false
null
:变量引用了一块堆中一个空的空间object
:引用对象类型(存在于堆里面)array
:数组类型function
:函数数据类型
-
对象数据类型:
object
,array
,function
-
3、
javascript
脚本执行顺序- 定义
var
function
- 执行 其他所有
- 定义
知识点:
1、运算符
-
算术运算符(
+
,-
,*
,/
,%
,++
,--
)- 如果引用所指的地方是
null
的话,那么在运算中就会自动变成0
%
运算符 如:4%5
取模 模是4
7%5
取模 模是7-5=2
- 如果引用所指的地方是
-
字符串和数字相加的情况:
- 左右都是数字:数字相加
- 左右有一个字符串:字符串拼接
- 左右边有一个
null
:null
看做0
- 左右边有一个
undefined
:结果是NAN
(not is number
)
-
赋值运算符(
=
,-=
,+=
,*=
,/=
,%=
) -
比较运算符(
==
,===
,!=
,>
,<
,>=
,<=
)- 先执行表达式计算再赋值
==
和!=
在比较之前首先让双方的值做隐士类型转换,===
不转换
-
逻辑运算符(
||
,&&
,!
)||
在js中和PHP中是不一样的 js中返回逻辑或的左边或右边的一个结果 PHP返回||
或出来以后的结果即:true
false
- 特殊性(注意)—一定要记住(这个特性和其他编程语言不一样):在
js
里返回不是布尔值 ||
短路运算 第一个条件为真 后面不执行&&
把表达式最后一个值返回(注意这里)
条件运符( 表达式1?表达式2:表达式3
)三元运算符
表达式1?表达式2:表达式3
表达式1为真 返回表达式2 否则返回表达式3- 三元运算符 可以多层次嵌套使用
2、在js中 有四种被认为是 非
:
undefined
null
false
0
- 例子:
var age = prompt("温馨提示:","请输入您的年龄")||0
- 当点击取消的时候,如果出现
undefined
null
fasle
0
表示非的逻辑 那么||
就会过滤,取右边的值0
第四课时
上节回顾:
-
1、运算符
- 算术运算符(
+
,-
,*
,/
,%
,++
,--
) - 如果
+
号左边和右边有一边是字符串类型的数据的话,这个时候就变成字符串拼接 var str = "你好"+123;
//你好123var count = 2;
var str1 = "你叫了我第"-count+"次";
//你叫了我第2次- 如果引用所指的地方是
null
的话,那么在运算中就会自动变成0
- 算术运算符(
-
2、赋值运算符 *(
=
,-=
,+=
,` =,
/=,
%=`) -
3、 比较运算符(
==,===,!=,>,<,>=,<=
)- 先执行表达式计算再赋值
==
和!=
在比较之前首先让双方的值做隐士类型转换,===
不转换
- 4、逻辑运算符(
||,&&,!
) - 5、条件运算符(
1>2?3:4
)
知识点:
1、 console.log
调试程序
- 开发中大量使用这个 而不用
alert
2、条件结构
if
javascript
中 if
语句优化写法
- 使用常见的三元操作符
if(foo) bar();elsebaz(); ==> foo?bar():baz();
if(!foo) bar();elsebaz(); ==> foo?baz():bar();
if(foo)returnbar();elsereturnbaz(); ==>returnfoo?bar():baz();
- 使用
and(&&)
和or(||)
运算符
if(foo) bar(); ==> foo&&bar();
if(!foo) bar(); ==> foo||bar();
if...else
if...else if...else
- 当通过判断返回某个值的时候,优先使用三元表达式
- 当通过判断执行
N
段逻辑代码的时候,只能用条件结构
第五课时
上节回顾:
- 1、
console.log
调试程序 - 2、条件结构
if
if...else
if...else if...else
- 当通过判断返回某个值的时候,优先使用三元表达式
- 当通过判断执行
N
段逻辑代码的时候,只能用条件结构
知识点:
1、 switch
-
switch case break default
条件 判断 退出 默认- a.只要匹配上一个
case
,那么它下面的所有的case
都会执行包括default
- b.
break
的意思跳出当前结构
- a.只要匹配上一个
2、 for
- 循环有三个要素
- a.循环变量
- b.判断(循环体)
- c.改变循环变量
- d.
continue
的意思结束本次循环进入下次循环
continue
结束本次循环,继续下一次循环 当前这次循环不做 直接做下面的break
结束后面的循环不做了
第六课时
上节回顾:
1、 switch
switch case break default
条件 判断 退出 默认- a.只要匹配上一个
case
,那么它下面的所有的case
都会执行包括default
- b.
break
的意思跳出当前结构
- a.只要匹配上一个
2、 for
- 循环有三个要素
- a.循环变量
- b.判断条件(循环体)
- c.改变循环变量
- d.
continue
的意思结束本次循环进入下次循环
知识点:
1、 while/do...while
没有谁好谁坏 只有适应场景不同
- 比如:先吃饭 在买单
do..while
用户体验高 有风险 扫雷游戏也是先体验 在问是否退出 提高体验 - 比如:先买单 在吃饭
while
用户体验不高 - 一般情况下面,如果条件判断是
数字的
比较==<>
,for
循环优先. - 如果是
非数值相关的
比较循环,while
优先
2、代码内存解析
闭包
- a.程序永远是先定义后执行
- b.执行永远从上到下
- c.函数定义的话在堆(只是一个地址而已)
- d.函数调用的时候,就会有自己的堆和栈(
闭包
)
闭包 作用域
- 记住:先定义
var
function
在从上往下执行 - 定义定义在自己的栈里面 执行在自己的堆里面
- 运行在运行的环境中
- 函数每调用前 只是一个地址
- 只要调用一次函数就会动态开辟一块内存 创建一个封闭的空间 在自己的封闭的空间的栈中定义
var
在执行 - 函数执行完 里面的东西全部销毁
//alert(x);//9:执行弹出x,结果x没定义,错误.
alert(i);//9:执行弹出i,然而i之前已经定义,只不过没地址,因此是undefiend
vari =10;//1:var i; 10:把常量池中10的地址赋给栈中的i
varj ="你好";//2:var j; 11:把常量池中 你好 的地址复给栈中的j
vark = z =null;//3:var k,z; 12:把堆中null的地址赋值给z和k
varm =function(){//4:var m; 5:function匿名函数 13:把匿名函数在堆中的地址赋给栈中的m
alert(2);
}
varb =document.body;//6:var b; 14:把堆中document.body对象的地址赋给栈中的b
varf =true;//7:var f; 15:把常量池中true的地址赋给栈中的变量f
functionm(){//8:function m;
alert(1);
}
functionm(){
c = 50;//在局部变量中找不到定义的c 沿着作用域链找到了全局变量的c
alert('哈哈哈');
//var c;
}
varc =150;// 函数m()还未执行到 还没被销毁 此时全局c的值c=50
m();
varc =20;//到这里一步 m()已经执行完了 函数已经销毁了 这里的c还是20
alert(c);//20
functionm(){
c = 50;//在局部变量中找不到定义的c 沿着作用域链找到了全局变量的c
alert('哈哈哈');
functioninner(){
c = 30;
alert('嘻嘻');
}
inner();//c在函数内部找不到定义 所以沿着作用域链找到了全局的c
}
varc =20;//到这里一步 m()还没执行 函数没被销毁 这里的c是30
m();
alert(c);//30
4、object对象
5、面向对象的程序设计
- a.
function
构造器 - b.
prototype
原型 - c.
foreach
- c.作用域
- d.继承
一些内存图示
原型链的几张图解
- 扩展阅读
第七课时
上节回顾:
- 1.
switch
-
2.
while/do...while
- 一般情况下面,如果条件判断是数字的比较
==<>
,for
循环优先. - 如果是非数值相关的比较循环,
while
优先
- 一般情况下面,如果条件判断是数字的比较
-
3.
function
函数 - 4.代码内存解析
- 闭包
- a.程序永远是先定义后执行
- b.执行永远从上之下
- c.函数定义的话在堆(只是一个地址而已)
- d.函数调用的时候,就会有自己的堆和栈(闭包)
- 闭包
知识点:
1、object对象
new
关键字代表的是新开辟一块内存空间-
没有被引用的内存空间,会在适当的时候被销毁
-
两句代码含义等同
var person = new Object()
;var person = {};
-
-
访问对象的属性除了用 对象引用
.属性
key
以外,还可以使用对象引用[属性key]
new 原理详细解析
- 无论什么时候,只要创建一个新函数,就会根据一组特定的规则为该函数创建一个
prototype
属性,这个属性指向函数的原型对象。 - 在默认情况下,所有原型对象都会自动获得一个
constructor
(构造函数)属性,这个属性包含一个指向prototype
属性所在函数的指针(就是指向新创建的函数)。 - 通过这个构造函数(原型对象的构造函数),可以继续为原型对象添加其他属性和方法。
- 当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。
ECMA-262
第5版管这个指针叫[[Prototype]]
。脚本中没有标准的方式访问[[Prototype]]
,但Firefox
、Safari
和Chrome
在每个对象上都支持一个属性__proto__
;而在其他实现中,这个属性对脚本是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于实例和构造函数的原型对象之间,而不是存在于实例和构造函数之间
new创建对象的步骤
- 创建一个新的对象
- 将构造函数的作用域赋给新对象
- 执行构造函数的代码,为这个新对象添加属性
- 返回新对象
functionPerson(name, age){
this.name = name;
this.age = age;
this.say =function(){
console.log(this.name);
};
}
functioncreatePerson(P){
// 创建一个新对象
varo =newObject();
// 获取传递给Person函数的参数
varargs =Array.prototype.slice.call(arguments,1);
// 新对象的__proto__属性指向Person的原型对象
o.__proto__ = P.prototype;
// Person的原型对象的constructor指向Person
P.prototype.constructor = P;
// 把Person构造函数的作用域赋给新对象
// 给这个新对象添加属性(name,age,say)
P.apply(o, args);
// 返回这个新对象
returno;
}
varp = createPerson(Person,'wang',35);
2、面向对象的程序设计
-
function
构造器- 共同点:
- 动态创建一块内存空间,闭包
- 不同点:
- 函数调用是没有办法拿到空间的地址的,而且这块地址是一块临时地址,执行完函数之后,就会销毁
new
开辟内存空间,把这块空间的地址返回,这块空间就有可能长期的被引用
- 共同点:
prototype
原型- 通过原型使通过同样一个构造器所
new(创建)
出来的对象具有相同的属性和行为 prototype
本质就是一个对象
- 通过原型使通过同样一个构造器所
foreach
this
指代当前创建的这块内存this.name=name
指代当前内存中的这个name
属性 接收外界传过来的值继承
多种构造函数
传统的创建对象
varperson =newObject();
person.name = “lancer”;
person.age = 24;
person.job = “UI”;
person.sayName = function(){
alert(this.name);
}
person.sayName();
工厂模式
functioncreatePerson(name,age,job){
varo =newObject();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(o.name);
}
returno;
}
varperson1 = createPerson(“lancer”,24,”UI”);
person1.sayName();
构造函数
functionPerson(name,age,job){
this.name = name;
this.age = age;
this.job =job;
this.sayName =function(){
alert(this.name)
}
}
varperson1 = createPerson(“lancer”,24,”UI”);
person1.sayName();
原型模式
functionPerson(){
}
Person.prototype.name =”lancer”;
Person.prototype.age =24;
Person.prototype.job = “UI”;
Person.prototype.sayName = function(){
alert(this.name)
}
varperson1 =newPerson();
person1.sayName();
varperson2 =newPerson();
person2.name =”lara”
person2.sayName();
简单原型模式
functionPerson(){
}
Person.prototype = {
name: “lancer”,
age:24,
job: “UI”,
sayName:function(){
alert(this.name)
}
};
varperson1 =newPerson();
person1.sayName();
构造函数和原型模式
functionPerson(name,age,job){
this.name = name;
this.age = age;
this.job =job;
}
Person.prototype = {
constructor:Person,
sayName:function(){
alert(this.name)
}
};
varperson1 =newPerson(“lancer”,”24″,”UI”);
person1.sayName();
动态原型模式
functionPerson(name,age,job){
this.name = name;
this.age = age;
this.job =job;
}
if(typeofthis.sayName !=”function”){
Person.prototype = {
constructor:Person,
sayName:function(){
alert(this.name)
}
};
}
varperson1 =newPerson(“lancer”,”24″,”UI”);
person1.sayName();
稳妥构造函数
varPerson =function(name,age,job){
varO =newObject();
O.sayName = function(){
alert(name);
};
returnO
}
varperson1 = Person(“lancer”,24,”UI”);
person1.sayName();
其他:
- 函数调用后一定有返回值,没有返回值就是
undefined
一些内存图示
第八课时
上节回顾:
1.object对象
new
关键字代表的是新开辟一块内存空间- 没有被引用的内存空间,会在适当的时候被销毁
- 两句代码含义等同
var person = new Object();
var person = {};
- 访问对象的属性除了用 对象引用属性
key
以外,还可以使用对象引用[属性key]
2.面向对象的程序设计
- a.
function
构造器- 共同点:
- 动态创建一块内存空间,闭包
- 不同点:
- 函数调用是没有办法拿到空间的地址的,而且这块地址是一块临时地址,执行完函数之后,就会销毁
new
开辟内存空间,把这块空间的地址返回,这块空间就有可能长期的被引用
- 共同点:
- b.
prototype
原型- 通过原型使通过同样一个构造器所
new
(创建)出来的对象具有相同的属性和行为 prototype
本质就是一个对象
- 通过原型使通过同样一个构造器所
- c.
foreach
- c.
this
- d.继承
知识点:
1.prototype内存解析
prototype
是原型,是一块所有对应构造器创建的对象都共享的内存空间- 在面向对象设计程序的时候,属性应该是对应的空间的,而功能应该是
prototype
公共空间的
2.通过prototype扩展功能
- 所有的构造器都是继承于
Object
构造器的,因此只要Object
的原型里有的功能,所有的对象都有
//多个对象的构造 以及 多个对象之间如何建立联系
functionStudent(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
functionBingqilin(name){
this.name = name;
}
functionGame(name){
this.name = name;
}
functionHour(time){
this.time = time;
}
Student.prototype = {
eat:function(b){
alert(this.name+"喜欢吃"+b.name);
},
mess:function(){
alert(this.name+"的信息:"+this.age+','+this.sex);
},
sleep:function(h){
alert(this.name+"每天睡,"+h.time+'小时');
},
work:function(h){
alert(this.name+"每天工作,"+h.time+'小时');
},
like:function(g){
alert(this.name+"喜欢打,"+g.name);
}
}
vars =newStudent("小明",22,"男");
varb =newBingqilin("黑色的冰淇淋");
s.eat(b);//小明喜欢吃黑色的冰淇淋
varg =newGame("英雄联盟");
s.like(g);//把对象的地址发送给like的参数即可访问构造函数Game的name属性
varh =newHour(10);
s.sleep(h);
s.work(h);
一些内存图示
第九课时
回顾:
1、prototype内存解析
prototype
是原型,是一块所有对应构造器创建的对象都共享的内存空间- 在面向对象设计程序的时候,属性应该是对应的空间的,而功能应该是
prototype
公共空间的
2、通过prototype扩展功能
- 所有的构造器都是继承于
Object
构造器的,因此只要Object
的原型里有的功能,所有的对象都有 - 构造器在定义的时候 就默认创建了一个空的原型
3、封装
- 1:找对象 小头爸爸 大头儿子 饭
- 2:抽象(类,构造器)
-
3:创建对象并且建立关系(操作对象)
-
面向对象例子
//小头爸爸牵着大头儿子的手去吃饭,吃完饭之后,
//小头爸爸背着大头儿子回家,回家后儿子学习,老爸工作,工作学习完后
//儿子看动画片
//围裙妈妈带儿子睡觉
//张三和张四
//分析对象 小头爸爸 大头儿子 饭 以及功能
//设计构造器(类)
//创建对象以及他们之间的关联
functionPerson(name,age){
this.name = name;
this.age = age;
}
functionRice(name){
this.name = name;
}
//Person.prototype.getHand = function(){//这样子写也可以 但还是用默认生成的那块空的内存对象 往里面添加属性 方法
//不浪费内存
//}
//在prototype中定义的每个对象都有这些功能
Person.prototype = {//这样子写 抛弃了默认生成的那块空的内存对象 重新创建了一块新的内存对象 记住:原型的本质是对象
//多个功能写在一起
getHand:function(person){//牵手
alert(this.name+"在牵着"+person.name+"的手....");
},
eat:function(rice){
alert(this.name+"在吃"+rice.name);
},
//需求 18岁以上才能背人
/* //写法一 不推荐 这个满足18岁的功能是自己强加的 不是客户需求的
carry:function(person){//这里设计不合理 让老爸有这个功能 儿子没有这个功能
if(this.age>=18){
alert(this.name+'背着'+person.name);
}else{
alert(this.name+",还未满18岁,背不起");
}
},*/
backhome:function(){
alert(this.name+"回家");
},
study:function(){
alert(this.name+"正在学习");
},
watchTV:function(jm){
alert(this.name+"正在看"+jm+'...');
}
};
varp1 =newPerson("老爸",20);
varp2 =newPerson("儿子",15);
//p1.getHand(p2);
//p1.eat(new Rice("蛋炒饭"));
//p2.eat(new Rice("猪脚饭"));
//p1.carry(p2);//老爸背儿子
//p2.carry(p1);//让儿子背老爸 输出结果:儿子,还未满18岁,背不起
//p1.backhome();
//写法二 不推荐 100对关系 代码写很多遍
/*
//让老爸单独有背的这个功能 儿子没有这个功能
p1.carry = function(person){
alert(this.name+'背着'+person.name);
}
p1.carry(p2);
*/
//-------通过继承解决这个 让老爸单独有背的这个功能 儿子没有这个功能 可以应对多功能 多需求
//功能函数
Object.prototype.extends =function(func,actions){//让所有的子孙 构造器都有这个功能
for(varpropinfunc.prototype){//传进一个func构造器 迭代构造器中的功能 把构造器中的功能全都映射过来 复制一份
this.prototype[prop] = func.prototype[prop];//迭代原型中的所有的功能到 当前里面去
}
for(varpropinactions){
this.prototype[prop] = actions[prop];
}
};
functionFather(name){
this.name = name;
}
Father.extends(Person,{
carry:function(person){
alert(this.name+'背着'+person.name);
},
work:function(){
alert(this.name+"正在工作");
}
});
//扩展
//设计程序有个原则:不修改只增加
functionChildren(name){
this.name = name;
}
Children.extends(Person);
functionMother(name){
this.name = name;
}
Mother.extends(Person,{
scoop:function(person){
//判断必须是children的对象才能执行这个功能
//if(){
alert(this.name+"唱着摇篮曲哄"+person.name+"睡觉");
//}
}
});
/*
Father.prototype.carry= function(person){//创建这个原型的想法是:原来Person有的功能 我都需要有 并在这些基础上加一个功能 carry
//如何建立Father基础Person的功能?写一个继承的小工具来操作
alert(this.name+'背着'+person.name);
};
Father.prototype.work = function(){
alert(this.name+"正在工作");
}
*/
varp1 =newFather("老爸");
varp2 =newChildren("儿子");
p1.carry(p2);//只有老爸有carry这个功能
//p2.carry(p1);//error 儿子没有carry这个功能
p2.study();//儿子在学习
p1.work();//老爸在工作
p1.watchTV('看足球');
p2.watchTV('蜡笔小新');
varp3 =newMother('围裙妈妈');
p3.scoop(p2);
知识点:
- 1.继承
- 2.面向对象程序设计案例(猜拳)
一些内存图示
第十课时
上节回顾:
1.继承
- 本质就是从一个
prototype
对象中把它的功能都copy
到另一个prototype
对象 - 继承为什么要循环
2.call apply方法的使用
func.call(obj)
:调用func
的时候,以obj
这个对象的作用域去调用- 改变函数在调用的时候里面闭包的作用域
call(obj,arg1,arg2,arg3)
;call
第一个参数传对象,可以是null
。参数以逗号分开进行传值,参数可以是任何类型。apply(obj,[arg1,arg2,arg3])
;apply
第一个参数传对象,参数可以是数组或者arguments
对象
知识点:
API application program interface
- 第一:遇到问题
- 第二:查资料或者学习 -> 解决问题
- 第三:记住有这个功能
- 第四:查资料(百度)
常用API
- 1.
String
- 2.
Array
- 3.
Math Math.random();
- 4.
Date
日期型函数 Date
- 声明
varmyDate =newDate();//系统当前时间
varmyDate =newDate(yyyy, mm, dd, hh, mm, ss);
varmyDate =newDate(yyyy, mm, dd);
varmyDate =newDate(“monthName dd, yyyy hh:mm:ss”);
varmyDate =newDate(“monthName dd, yyyy”);
varmyDate =newDate(epochMilliseconds);
- 获取时间的某部份
varmyDate =newDate();
myDate.getYear(); //获取当前年份(2位)
myDate.getFullYear(); //获取完整的年份(4位,1970-????)
myDate.getMonth(); //获取当前月份(0-11,0代表1月)
myDate.getDate(); //获取当前日(1-31)
myDate.getDay(); //获取当前星期X(0-6,0代表星期天)
myDate.getTime(); //获取当前时间(从1970.1.1开始的毫秒数) 时间戳!!
myDate.getHours(); //获取当前小时数(0-23)
myDate.getMinutes(); //获取当前分钟数(0-59)
myDate.getSeconds(); //获取当前秒数(0-59)
myDate.getMilliseconds(); //获取当前毫秒数(0-999)
myDate.toLocaleDateString(); //获取当前日期
myDate.toLocaleTimeString(); //获取当前时间
myDate.toLocaleString( ); //获取日期与时间
- 计算之前或未来的时间
varmyDate =newDate();
myDate.setDate(myDate.getDate() + 10);//当前时间加10天//类似的方法都基本相同,以set开头,具体参考第2点
- 计算两个日期的偏移量
vari = daysBetween(beginDate,endDate);//返回天数
vari = beginDate.getTimezoneOffset(endDate);//返回分钟数
- 检查有效日期
//checkDate() 只允许”mm-dd-yyyy”或”mm/dd/yyyy”两种格式的日期
if( checkDate(“2006-01-01”) ){ }
//正则表达式(自己写的检查 yyyy-mm-dd, yy-mm-dd, yyyy/mm/dd, yy/mm/dd 四种)
varr =/^(d{2}|d{4})[/-]d{1,2}[/-]d{1,2}$/;if( r.test( myString ) ){ }
字符串String型函数API
- 声明
varmyString =newString(“Every good boy does fine.”);
varmyString = “Every good boy does fine.”;
- 字符串连接
varmyString = “Every ” + “good boy ” + “does fine.”;
varmyString = “Every “; myString += “good boy does fine.”;
- 截取字符串
//截取第 6 位开始的字符
varmyString = “Every good boy does fine.”;
varsection = myString.substring(6);//结果: “good boy does fine.”
//截取第 0 位开始至第 10 位为止的字符
varmyString = “Every good boy does fine.”;
varsection = myString.substring(0,10);//结果: “Every good”
//截取从第 11 位到倒数第 6 位为止的字符
varmyString = “Every good boy does fine.”;
varsection = myString.slice(11,-6);//结果: “boy does”
//从第 6 位开始截取长度为 4 的字符
varmyString = “Every good boy does fine.”;
varsection = myString.substr(6,4);//结果: “good”
- 转换大小写
varmyString = “Hello”;
varlcString = myString.toLowerCase();//结果: “hello”
varucString = myString.toUpperCase();//结果: “HELLO”
- 字符串比较
varaString = “Hello!”;
varbString =newString(“Hello!”);
if( aString == “Hello!” ){ }//结果: true
if( aString == bString ){ }//结果: true
if( aString === bString ){ }//结果: false (两个对象不同,尽管它们的值相同)
- 检索字符串
varmyString = “hello everybody.”;
// 如果检索不到会返回-1,检索到的话返回在该串中的起始位置
if( myString.indexOf(“every”) >-1){ }//结果: true
- 查找替换字符串
varmyString = “I is your father.”;
varresult = myString.replace(“is”,”am”);//结果: “I am your father.”
-
特殊字符
: 后退符
v
: 垂直制表符f
: 分页符”
: 双引号’
: 单引号\ 反斜杆
- 将字符转换成
Unicode
编码
varmyString = “hello”;
varcode = myString.charCodeAt(3);//返回”l”的Unicode编码(整型)
varchar =String.fromCharCode(66);//返回Unicode为66的字符
- 将字符串转换成URL编码
varmyString = “hello all”;
varcode =encodeURI(myString);//结果: “hello%20all”
varstr =decodeURI(code);//结果: “hello all”
//相应的还有: encodeURIComponent() decodeURIComponent()
- 扩展阅读
Math对象型
-
Math.abs(num)
: 返回num
的绝对值 -
Math.acos(num)
: 返回num
的反余弦值 -
Math.asin(num)
: 返回num
的反正弦值 -
Math.atan(num)
: 返回num
的反正切值 -
Math.atan2(y,x)
: 返回y
除以x
的商的反正切值 -
Math.ceil(num)
: 返回大于num
的最小整数 -
Math.cos(num)
: 返回num
的余弦值 -
Math.exp(x)
: 返回以自然数为底,x次幂的数 -
Math.floor(num)
: 返回小于num
的最大整数 -
Math.log(num)
: 返回num
的自然对数 -
Math.max(num1,num2)
: 返回num1
和num2
中较大的一个 -
Math.min(num1,num2)
: 返回num1
和num2
中较小的一个 -
Math.pow(x,y)
: 返回x
的y
次方的值 -
Math.random()
: 返回0
到1
之间的一个随机数 -
Math.round(num)
: 返回num
四舍五入后的值 -
Math.sin(num)
: 返回num
的正弦值 -
Math.sqrt(num)
: 返回num
的平方根 -
Math.tan(num)
: 返回num
的正切值 -
Math.E
: 自然数(2.718281828459045
) -
Math.LN2
:2
的自然对数(0.6931471805599453
) -
Math.LN10
:10
的自然对数(2.302585092994046
) -
Math.LOG2E
:log 2
为底的自然数(1.4426950408889634
) -
Math.LOG10E
:log 10
为底的自然数(0.4342944819032518
) -
Math.PI
:π(3.141592653589793)
-
Math.SQRT1_2
:1/2
的平方根(0.7071067811865476
) -
Math.SQRT2
:2
的平方根(1.4142135623730951
)
Number型 常用的数字函数
- 声明
vari =1;
vari =newNumber(1);
- 字符串与数字间的转换
vari =1;
varstr = i.toString();//结果: “1”
varstr =newString(i);//结果: “1”
i = parseInt(str);//结果: 1
i = parseFloat(str);//结果: 1.0
//注意: parseInt,parseFloat会把一个类似于”32G”的字符串,强制转换成32
- 判断是否为有效的数字
vari =123;varstr = “string”;
if(typeofi == “number” ){ }//true
//某些方法(如:parseInt,parseFloat)会返回一个特殊的值NaN(Not a Number)
//请注意第2点中的[注意],此方法不完全适合判断一个字符串是否是数字型!!
i = parseInt(str);
if(isNaN(i) ){ }
- 数字型比较
//此知识与[字符串比较]相同
- **小数转整数**
varf =1.5;
vari =Math.round(f);//结果:2 (四舍五入)
vari =Math.ceil(f);//结果:2 (返回大于f的最小整数)
vari =Math.floor(f);//结果:1 (返回小于f的最大整数)
- 格式化显示数字
vari =3.14159;
//格式化为两位小数的浮点数
varstr = i.toFixed(2);//结果: “3.14”
//格式化为五位数字的浮点数(从左到右五位数字,不够补零)
varstr = i.toPrecision(5);//结果: “3.1415”
- X进制数字的转换
vari =parseInt(“0x1f”,16);
vari =parseInt(i,10);
vari =parseInt(“11010011”,2);
- 随机数
//返回0-1之间的任意小数
varrnd =Math.random();
//返回0-n之间的任意整数(不包括n)
varrnd =Math.floor(Math.random() * n)
5. Regex
//在这个最大的对象的原型上加一个extends方法 使得下面所有的原型 都有这个方法
//这个原型的作用是通过迭代 复制传进来的构造器的所有的原型的方法
Object.prototype.extends =function(parent){
//console.log(parent.prototype);
for(varpropinparent.prototype){
//console.log(prop);//eat extends
this.prototype[prop] = parent.prototype[prop];//复制传进来的构造器的所有的原型的方法给当前正在调用这个方法的对象
}
}
functionPerson(name){
this.name = name;
}
Person.prototype = {
eat:function(){
alert(this.name+"在吃饭");
}
};
functionFather(name){
this.name = name;
}
Father.extends(Person);//extends方法是最大的对象Object加的方法 所有的子孙 构造器都有这个方法
varf =newFather("小头爸爸");
f.eat();
一些图示
- 正则表达式扩展阅读
第十一课时
上节回顾:
- 1.
String
- 2.
Math
Math.random()
知识点:
- 1.
Date
日期类 - 2.
Array
- 3.
Regex
- a.
[]
一个字符的范围 - b.有顺序要求的
- c.
w==[a-zA-Z0-9_]
d==[0-9]
- d.
{count}
设置匹配数量比如w{5}
- e.
//
的正则表达式匹配局部,/^$/
的正则表达式是匹配全部 - f.
()
的作用就是为了分组匹配
- a.
- 简单封装一个对象案例
String.prototype.isEmail =function(){
email = this;
if(email.indexOf("@")!=-1&&email.indexOf(".")!=-1)
{
if(email.indexOf("@")<email.lastIndexOf("@")){
alert("邮箱不合法");
}else{
alert("邮箱合法");
}
}
}
varemail ="jingguanliuye@gmail.com";
email.isEmail();
//===============================日历练习(方法简洁 高效)======================================
//var year = parseInt(prompt("请输入日历年份:"));
//var month = parseInt(prompt("请输入日历月份:"))-1;
Date.prototype.printCalendar =function(){
varyear =this.getFullYear(),month =this.getMonth();
vardate =newDate(year,month,1);
//alert(date.toLocaleString());
document.write("<div class='date'>"+year+"年"+(month+1)+"月</div>");
document.write("日 一 二 三 四 五 六<br />");
varday = date.getDay();
for(vari=0;i<day;i++){
document.write(' ');
}
varcount =newDate(year,month+1,0).getDate();//这里的0返回一个月的最后一天
for(vari=1;i<=count;i++){
document.write(i+' ');
if((i+day)%7==0){
document.write('<br/>');
}
}
}
newDate(2012,2).printCalendar();
第十二课时
上节回顾:
- 1.
Date
期类 - 2.
Array
- 3.
Regex
- a.
[]
一个字符的范围 - b.有顺序要求的
- c.
w==[a-zA-Z0-9_]
d==[0-9]
- d.
{count}
设置匹配数量比如w{5}
,{c1,c2}
- e.
//
的正则表达式匹配局部,/^$/
的正则表达式是匹配全部 - f.
()
的作用就是为了分组匹配
- a.
新知识点:
- 1.
Regex
- g.
+
代表的是1-N
个,*
代表的是0-N
个 - h.
?
代表该字符要不没有要不就有一个 - i.
.
代表的是任意字符 - j.
转义符
- g.
- 2.
BOM
第十三课时
上节回顾:
- 1.Regex
- a.
[]
一个字符的范围 - b.有顺序要求的
- c.
w==[a-zA-Z0-9_]
d==[0-9]
- d.
{count}
设置匹配数量比如w{5}
,{c1,c2}
- e.
//
的正则表达式匹配局部,/^$/
的正则表达式是匹配全部 - f.
()
的作用就是为了分组匹配 - g.+代表的是
1-N
个,*
代表的是0-N
个 - h.
?
代表该字符要不没有要不就有一个 - i.
.
代表的是任意字符 - j.
转义符
- a.
新知识:
window
是Window
构造器造出来的一个对象alert(window instanceof Window)
document
是Document
构造器造出来的一个对象- 任何对象在我们的内存中他都是由某个构造器创建出来的 也就是说 有构造器一定有对应的原型prototype
- 例如:
div
是由HTMLDivElement
这个构造器创建的一个实例div = new HTMLDivElement()
span = new HTMLSpanElement()
- 查看某个对象对应的构造器:
console.log();
- 整个浏览器的实现就是一个面向对象的编程思想 一切皆是对象
1.BOM 浏览器对象模型
- a.
screen
指的不是浏览器的宽度,指的是整个电脑屏幕的分辨率- 可以拿到屏幕可用分辨率
- b.
navigator
- 可以通过
userAgent
判断当前浏览器信息
- 可以通过
- c.
location
URL
:统一资源定位符Union Resource Location
- 可以通过
href
属性重定向(改变)页面的URL,进行页面跳转
- d.
history
go
方法能够让我们进行历史回退或者前进
-
e.
frames
- 获得当前窗体的子页面(
iframe
)
- 获得当前窗体的子页面(
-
f.
document
DOM
模型的核心对象
2. DOM
文档对象模型
-
document
- 功能
getElementById
$('#aaa')
getElementByTagName
$('div')
getElementsByClassName
$('.aaa')
getElementsByName
只用在表单元素中
- 功能
-
document
object
- 属性:
className
,style
id
name
,value
(表单元素)href
,src
…(对应的元素)innerHTML
children
parentNode
- 功能方法:
setAttribute/getAttribute
appendChild
- 属性:
第十四课时
上节回顾:
- 1.BOM 浏览器对象模型
- a.
screen
指的不是浏览器的宽度,指的是整个电脑屏幕的分辨率- 可以拿到屏幕可用分辨率
- b.
navigator
- 可以通过
userAgent
判断当前浏览器信息
- 可以通过
- c.
location
URL
:统一资源定位符Union Resource Location
- 可以通过
href
属性重定向(改变)页面的URL,进行页面跳转
- d.
history
go
方法能够让我们进行历史回退或者前进
- e.
frames
获得当前窗体的子页面(`iframe`)
- f.
document
DOM
模型的核心对象
- a.
- 所有的
DOM
对象都是在堆内存创建的 都是有一个构造器生成的 - 查看对象的构造器器方法:
- step1:查看标签的对象以及构造器
var body = document.body;console.log(body.toString())
- step2:查看对象是否是这个构造器创建出来的
console.log(body instanceof HTMLBodyElement)
- step1:查看标签的对象以及构造器
新知识点:
1.DOM 文档对象模型
document
- 功能
getElementById
:通过传入的ID,返回标识了这个ID的唯一对象的内存地址getElementsByTagName
:通过传入的标签名字,返回所有该标签对象(HTMLCollection
)getElementsByClassName
:通过类的名字,返回所有该类的元素对象(HTMLCollection
)createElement
:想要创建出来的元素能够绘制在页面中,那么它必须在DOM树中- 总结
document
对象是DOM原型的核心对象,它是内存DOM树的根,所以它提供了很多功能让我们快速的找到DOM树中的某些DOM节点(对象)
- 总结
element
-
功能方法:(自定义属性非常灵活好用)
setAttribute/getAttribute
//getAttribute获取标签的属性 –用来操作标签的属性setAttribute
设置标签的属性appendChild
:添加子元素
-
属性:
id
className
,style
name
,value
(只有表单元素有 其他是没有的)href
,src
…(对应的元素)innerHTML/innerText
innerText
返回文本信息children
://子元素集合parentNode
//父元素
- 总结:元素的功能属性直接可以通过元素对象
点
出来,除此意外的自定义属性
,请通过get/setAtribute
去操作
DOM 操作:
- 图片切换的相册效果
tab
切换效果- 表单验证
- 特效就是
DOM
操作的具体应用DOM
操作就是用js
来写HTML
代码 - 节点/元素/标签:
- 三种常用的节点类型:
- 元素节点
- 属性节点
- 文本节点
- 三种常用的节点类型:
操作DOM对象:
- 修改:–找到这个节点
- 删除:–找到这个节点
- 添加:–先造出一个节点 然后插入 插入到哪里?找节点来定位
- 这些都离不开节点的查找
节点的查找:(最重要)
- 1、
document.getElementById
—根据id
查找节点 [返回的是节点本身] - 2、
document.getElementsByTagName
–根据标签名字来查找[返回的是数组]document.getElementsByTagName[i]
- 3、
document.getElemenstByName
–根据name
属性来查找节点(一般用在表单中)[返回的是数组]document.getElemenstByName[i]
-
注意:早期浏览器都认为
name
只出现在表单中 -
因此
document.getElemenstByName
只对表单中的元素发挥作用 后来部分浏览器把Name
属性扩展到一般的元素 如:div
但是IE浏览器还是只能对表单使用byName
因此处于兼容性 我们只能对表单使用byName
DOM
中查找节点的思路:(由大到小 个别情况 由子到父)
-
由大到小:(通过下面的来定位)
- 1、
document.getElementById
—根据id查找节点 [返回的是节点本身] - 2、
document.getElementsByTagName
–根据标签名字来查找[返回的是数组]document.getElementsByTagName[i]
- 3、
document.getElemenstByName
–根据name
属性来查找节点(一般用在表单中)[返回的是数组]document.getElemenstByName[i]
- 1、
- 如果还没有查到自己想要的节点,还可以继续根据上面已经找到的节点再次定位来查找
- 怎么继续定位?
- 答:
childNodes/child
- 答:
继续查找:
- 1、查找子元素
children[index]/childNodes
- 2、查找父元素
node.parentNode
–>获取父元素 - 3、查找兄弟元素
nextSibling
previousSibling
- 4、
nextSibling
previousSibling
firstChild
lastChild
这四个属性容易受到空白文本
的影响建议不用
//============给Object原型加一个方法 消除文本节点对DOM操作的影响 例如:nextSibling` `previousSibling` `firstChild` `lastChild (受到换行 和文本节点影响)
Object.prototype.next =function(){
//NodeType == 3 text的代号
//NodeType == 1 tag的代号
if(this.nextSibling){//判断下一个兄弟节点是否存在
switch(this.nextSibling.nodeType){
case1:
returnthis.nextSibling;
case3:
returnthis.nextSibling.nextSibling;
}
}else{
returnnull;
}
console.log(div1.next().next().innerText);
-
5、对于查到的某个元素里面的子元素非常多 这时候还可利用
getElementsByTagname
进一步筛选 -
注意对于元素对象和
document
对象相比 元素对象只能利用getElementsByTagName
函数 其他两个不能用
-
节点查找也是通过由大到小来定位:找到大的元素进一步细化 完全可以找到页面上任意一个元素控制他
-
子元素 不好找 就找他的父元素
-
要过滤空白文本节点,用
children
取他的文本节点
DOM与节点的关系:
- node:
childNodes[]
parentNode
firstChild
getElementsByTagName('元素标签')
lastchild
nextSibling
previousSibling
children[index]
children
不是w3c
标准 但是各大浏览器兼容性很好
-
通过给原型添加方法在元素后面创建标签
-
启示:在项目中,很多很多地方都需要一个方法但是系统没提供,这时可以通过原型扩展
//var p = document.createElement('p');
//p.innerHTML = "this is a p";
//var child = document.getElementsByTagName('div');
//给Div的HTMLDivElement构造器原型加一个创建元素的方法 要所有的元素都有这个方法 改成 Object
HTMLDivElement.prototype.createElement = function(tagName){
varchild =document.createElement(tagName);
this.appendChild(child);
returnchild;
}
varchild =document.getElementsByTagName('div')[2].createElement("p");
child.innerHTML = 'pppppp';
DOM属性小结
-
Attributes
存储节点的属性列表(只读) -
childNodes
存储节点的子节点列表(只读) -
dataType
返回此节点的数据类型 -
Definition
以DTD
或XML
模式给出的节点的定义(只读) -
Doctype
指定文档类型节点(只读) -
documentElement
返回文档的根元素(可读写) -
firstChild
返回当前节点的第一个子节点(只读) -
Implementation
返回XMLDOMImplementation
对象 -
lastChild
返回当前节点最后一个子节点(只读) -
nextSibling
返回当前节点的下一个兄弟节点(只读) -
nodeName
返回节点的名字(只读) -
nodeType
返回节点的类型(只读) -
nodeTypedValue
存储节点值(可读写) -
nodeValue
返回节点的文本(可读写) -
ownerDocument
返回包含此节点的根文档(只读) -
parentNode
返回父节点(只读) -
Parsed
返回此节点及其子节点是否已经被解析(只读) -
Prefix
返回名称空间前缀(只读) -
preserveWhiteSpace
指定是否保留空白(可读写) -
previousSibling
返回此节点的前一个兄弟节点(只读) -
Text
返回此节点及其后代的文本内容(可读写) -
url
返回最近载入的XML文档的URL
(只读) -
Xml
返回节点及其后代的XML
表示(只读)
DOM方法小结
cloneNode
返回当前节点的拷贝createAttribute
创建新的属性
-
节点操作
DOMDocument
属性和方法-
createCDATASection
创建包括给定数据的CDATA
段 -
createComment
创建一个注释节点 -
createDocumentFragment
创建DocumentFragment
对象 -
createElement_x_x
创建一个元素节点 -
createEntityReference
创建EntityReference
对象 -
createNode
创建给定类型,名字和命名空间的节点 -
createPorcessingInstruction
创建操作指令节点 -
createTextNode
创建包括给定数据的文本节点 -
getElementsByTagName
返回指定名字的元素集合 -
hasChildNodes
返回当前节点是否有子节点 -
insertBefore
在指定节点前插入子节点 -
Load
导入指定位置的XML文档 -
loadXML
导入指定字符串的XML文档 -
removeChild
从子结点列表中删除指定的子节点 -
replaceChild
从子节点列表中替换指定的子节点 -
Save 把
XML`文件存到指定节点 -
selectNodes
对节点进行指定的匹配,并返回匹配节点列表 -
selectSingleNode
对节点进行指定的匹配,并返回第一个匹配节点 -
transformNode
使用指定的样式表对节点及其后代进行转换 -
transformNodeToObject
使用指定的样式表将节点及其后代转换为对象 -
document.documentElement
返回文档的根节点 -
document.activeElement
返回当前文档中被击活的标签节点 -
event.fromElement
返回鼠标移出的源节点 -
event.toElement
返回鼠标移入的源节点 -
event.srcElement
返回激活事件的源节点 -
node.parentNode,node.parentElement
返回父节点 -
node.childNodes
返回子节点集合(包含文本节点及标签节点) -
node.children
返回子标签节点集合 -
node.textNodes
返回子文本节点集合 -
node.firstChild
返回第一个子节点 -
node.lastChild
返回最后一个子节点 -
node.nextSibling
返回同属下一个节点 -
node.previousSibling
返回同属上一个节点 -
node.a(oNode)
追加子节点: -
node.applyElment(oNode,sWhere)
-
sWhere
有两个值:outside
/ inside
应用标签节点 -
node.insertBefore()
-
node.insertAdjacentElement()
-
node.replaceAdjacentText()
-
-
插入节点
node.remove()
node.removeChild()
node.removeNode()
-
删除节点
node.replaceChild()
node.replaceNode()
node.swapNode()
-
替换节点
node.cloneNode(bAll)
返回复制复制节点引用node.contains()
是否有子节点node.hasChildNodes()
是否有子节点
- 扩展阅读
第十五课时
上节回顾:
1.DOM 文档对象模型
document
- 功能
getElementById
:通过传入的ID,返回标识了这个ID的唯一对象的内存地址getElementsByTagName
:通过传入的标签名字,返回所有该标签对象(HTMLCollection
)getElementsByClassName
:通过类的名字,返回所有该类的元素对象(HTMLCollection
)createElement
:想要创建出来的元素能够绘制在页面中,那么它必须在DOM树中- 总结:
document
对象是DOM原型的核心对象,它是内存DOM树的根,所以它提供了很多功能让我们快速的找到DOM树中的某些DOM节点(对象)
- 总结:
element
- 功能方法:(自定义属性非常灵活好用)
setAttribute/getAttribute
//getAttribute获取标签的属性 –用来操作标签的属性setAttribute
设置标签的属性appendChild
:添加子元素
- 属性:
id
className
,style
name
,value
(只有表单元素有 其他是没有的)href
,src
…(对应的元素)innerHTML/innerText
innerText返回文本信息children
://子元素集合parentNode
//父元素- 总结:元素的功能属性直接可以通过元素对象
点
出来,除此意外的自定义属性
,请通过get/setAtribute
去操作
- 功能方法:(自定义属性非常灵活好用)
新知识点:
1.事件(事故)基础
- 白话含义:就是当一个事物遇到某个事情的时候,要做的事情
- (事件源)
- (事件监听名称)
- (事件处理程序)
2.常用事件
onclick:
当事件源被点击的时候调用处理程序onmouseover:
鼠标进入事件onmouseout:
鼠标移出事件onmousedown:
鼠标按下去的时候onmouseup:
鼠标抬起来的时候onscroll:
当事件源滚动条滚动的时候onkeydown:
当键盘按下的时候onkeypress:
当键盘按下去的时候onkeyup:
当键盘弹上来的时候onfocus:
当事件源获得光标onblur:
当事件源失去光标onchange:
当事件源blur
的时候内容改变了的话
浏览器事件注意事项:
- 1.以后我们不要把事件写在标签上,而使用
js
方式操作 - 2.js方式操作的话:
- 非
IE
浏览器第一个对象就会传入event
事件源对象 - IE浏览器第一个对象就不会传入
event
事件源对象(event = event||window.event
;) - 非
IE
浏览器的事件源属性是target
属性(event.target = event.target||event.srcElement
;) IE
浏6览器的事件源属性是srcElement
属性
- 非
- 3.事件冒泡机制
- 4.案例
总结
- 以上是一些很基础的理论,笔记经验终究是别人的,看完了还是会忘记的,要转化成自己的东西,还要靠你不断实践。
JavaScript
读书路线
php面向对象
一、面向对象的基本概念
1.什么是面向对象?
对象
面向
由于目前都还没有一个统一的概念,所以所能理解的就是一个物体被抽象出来,每个物品都是一个对象。
2.什么是对象?
---世间万物皆对象
桌子、人、键盘……
看见的,看不见的(抽象的)
3.对象的基本组成
对象包含两部分
-对象的组成元素
·是对象的数据模型,用于描述对象的数据
·又被称为对象的属性,或者对象的成员变量
-对象的行为
·是对象的行为模型,用于描述对象能够做什么事情
·又被称为对象的方法
4.对象的特点
·每个对象都是独一无二的
·对象是一个特定事务,他的职能是完成特定功能
·对象是可以重复使用的
5.面向对象编程的基本概念
·什么是面向对象?
-面向就是在编程的时候一直把对象放在心上
·面向对象编程就是在编程的时候数据结构(数据组织方式)都通过对象的结构进行存储
-属性、方法
·对象的描述方式更加贴合真实的世界,有利于大型业务的理解
·在程序设计的过程中用对象的视角分析世界的时候能够独立拉近程序设计和真实世界的距离
6.面向对象--实质
·面向对象就是把生活中要解决的问题都用对象的方式进行存储
-属性
-方法
·对象与对象之间通过方法的调用完成互动
-方法
7.面向对象的基本思路
第一步:识别对象
-任何实体都可以被识别为一个对象
第二步:识别对象的属性
-对象里面存储的数据被识别为属性
-对于不同的业务逻辑,关注的数据不同,对象里面存储的属性也不同
第三步:识别对象的行为
-对象自己属性数据的改变
-对象和外部交互
8.面向对象的基本原则
对象内部是高内聚的
-对象只负责一项特定的职能(职能可大可小)
-所有对象相关内容都封装到对象的内部
对象度外是低耦合的
-外部世界可以看到对象的一些属性(并非全部)
-外部世界可以看到对象可以做某些事情(并非全部)
二、PHP中的面向对象编程
1.面向对象基本实践
类的概念
-类以物聚,把具有相似特性的对象归类到一个类中
-类定义了这些相似对象拥有的相同的属性和方法
-类是相似对象的描述,称为类的定义,是该类对象的蓝图或者原型
-类的对象称为类的一个实例(类的实例化)
-类的属性和方法统称为类成员
2.类的实例化
类的实例化就是通过类定义创建一个类的对象
类的定义里面属性值都是空的,而对象的属性都具有具体的值
实例:
// 类的定义以关键字class开始,后面跟着这个类的名称。类的命名通常每个单词的第一个字母大写。以中括号开始和结束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
<?php date_default_timezone_set( "PRC" ); // 类的定义以关键字class开始,后面跟着这个类的名称。类的命名通常每个单词的第一个字母大写。以中括号开始和结束 class NbaPlayer{ public $name = "Jordan" ; public $height = "198cm" ; public $weight = "98kg" ; public $team = "bull" ; public $playerNumber = "23" ; // 默认构造函数,在对象被实例化的时候自动调用 function __construct( $name , $height , $weight , $team , $playerNumber ){ echo "In NbaPlayer constructor <br>" ; $this ->name = $name ; //$this是php里面的伪变量,表示对象自身。可以通过$this->的方式访问对象的属性和方法 $this ->height= $height ; $this ->weight= $weight ; $this ->team= $team ; $this ->playerNumber= $playerNumber ; } // 定义方法 public function run(){ echo "Running
" ; } public function jump(){ echo "Jumping
" ; } public function dribble(){ echo "dribbling
" ; } public function shoot(){ echo "shooting
" ; } public function dunk(){ echo "dunking
" ; } public function pass(){ echo "passing
" ; } // 析构函数,在程序执行结束的时候会自动调用 //析构函数通常被用于清理程序使用的资源。比如程序使用了打印机,那么可以在析构函数里面释放打印机资源 function __destruct(){ echo "Destroying " . $this ->name. "<br>" ; } } //类到对象的实例化 // 类的实例化为对象使用关键字new,new之后紧跟类的名称和一对括号 $Jordan = new NbaPlayer( "lihua" , "198cm" , "98kg" , "bull" , "23" ); // 对象中的属性成员可以通过->符号来访问 echo $Jordan ->name. "<br>" ; echo $Jordan ->height. "<br>" ; // 对象中的成员方法可以通过->符号来访问 $Jordan ->dribble(); $Jordan ->pass(). "<br>" ; $james = new NbaPlayer( "James" , "213cm" , "100kg" , "heat" , "23" ); echo $james ->name. "<br>" ; //通过把变量设置为null 可以触发析构函数的调用 $james =null; echo "From now on james will not be used<br>" ; ?> |
三、面向对象高级实践
1.面向对象--继承
继承的好处:
-父类里面定义的类成员可以不用在子类中重复定义,节约了编程的时间和代价
·比如,人的吃这个方法一旦在父类汇总定义,那么NBA球员和女主播两个子类就不需要实现吃这个方法了,就好像天胜就有这个功能一样
-同一个父类的子类拥有相同的父类定义的类成员,因此外部代码调用它们的时候可以一视同仁
·比如 一个NBA球员和一个女主播,因为她们都是人,所以可以直接调用父类定义的“吃”方法,而不用管他到底是个NBA球员还是女主播
-子类可以修改和调整父类定义的类成员
·我们称为重写
·一旦子类修改了,就按照子类修改之后的功能执行
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<?php class Human{ public $name ; public $height ; public $weight ; function eat( $food ){ echo $this ->name. "'s eating " . $food . "<br>" ; } } //在PHP中可以使用extends关键字来表示类的继承,后面跟父类的类名 // PHP在extends后面只能跟一个类的类名,这就是PHP的单继承原则 class NbaPlayer extends Human{ public $team ; public $playerNumber ; function __construct( $name , $height , $weight , $team , $playerNumber ){ $this ->name = $name ; $this ->height= $height ; //父类中的属性,可以通过$this来访问 $this ->weight= $weight ; $this ->team= $team ; $this ->playerNumber= $playerNumber ; } } $Jordan = new NbaPlayer( "jordan" , "198cm" , "98kg" , "bull" , "23" ); echo $Jordan ->name. "<br>" ; $Jordan ->eat( "chicken" ); //在子类的对象上可以直接访问父类中定义的方法和属性 ?> |
2.面向对象--访问控制
·面向对象的三种访问权限
-public公有的类成员,可以在任何地方被访问
·定义该成员的类(自身)、该类的子类、其他类
-protected受保护的类成员,可以被其自身以及其子类访问
-private私有的类成员,只能被自身访问
//在大括号内的保护对象或是私有对象是可以随便访问的,但是不能在类的外面直接引用
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
<?php class Human{ public $name ; protected $height ; //自身和子类可以访问 public $weight ; private $human =true; //只能自身访问 function eat( $food ){ echo $this ->name. "'s eating " . $food . "<br>" ; } // 可以这样让子类调用私有和保护的对象,这叫封装 public function info(){ echo $this ->name. ";" . $this ->height. ";" . $this ->human. "<br>" ; } } class NbaPlayer extends Human{ public $team = "bull" ; public $playerNumber = "23" ; private $age = "38" ; // 默认构造函数,在对象被实例化的时候自动调用 function __construct( $name , $height , $weight , $team , $playerNumber ){ echo "In NbaPlayer constructor <br>" ; $this ->name = $name ; //$this是php里面的伪变量,表示对象自身。可以通过$this->的方式访问对象的属性和方法 $this ->height= $height ; //父类中的属性,可以通过$this来访问 $this ->weight= $weight ; $this ->team= $team ; $this ->playerNumber= $playerNumber ; } function getAge(){ echo $this ->name. "'s age is " . $this ->age. "<br>" ; } } //类到对象的实例化 // 类的实例化为对象使用关键字new,new之后紧跟类的名称和一对括号 $Jordan = new NbaPlayer( "jordan" , "198cm" , "98kg" , "bull" , "23" ); echo $Jordan ->name. "<br>" ; $Jordan ->eat( "chicken" ); //在子类的对象上可以直接访问父类中定义的方法和属性 $Jordan ->getAge(); // echo $Jordan->height; //保护对象这样不能访问 $Jordan ->info(); ?> |
3.面向对象--静态成员
使用类的静态成员特性就可以达到这样的效果
-static关键字
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
<?php /* 1.静态属性用于保存类的共有数据 2.静态方法里面只能访问静态属性 3.静态成员不需要实例化对象就可以访问 4.类的内部可以通过self 或者static关键字访问自身静态成员 5.可以通过parent关键字访问父类的静态成员 6.可以通过类的名称在类定义外部访问静态成员 */ class Human{ public $name ; protected $height ; //自身和子类可以访问 public $weight ; private $human =true; //只能自身访问 public static $sValue = "this is parent static" ; function eat( $food ){ echo $this ->name. "'s eating " . $food . "<br>" ; } // 可以这样让子类调用私有和保护的对象,这叫封装 public function info(){ echo $this ->name. ";" . $this ->height. ";" . $this ->human. "<br>" ; } } //在PHP中可以使用extends关键字来表示类的继承,后面跟父类的类名 // PHP在extends后面只能跟一个类的类名,这就是PHP的单继承原则 // 类的定义以关键字class开始,后面跟着这个类的名称。类的命名通常每个单词的第一个字母大写。以中括号开始和结束 class NbaPlayer extends Human{ public $team = "bull" ; public $playerNumber = "23" ; private $age = "38" ; // 静态属性定义时在访问控制关键字后面添加static关键字 public static $president = "David Stern" ; // 静态方法定义 public static function changePresident( $newPrsdt ){ // 在类定义中使用静态成员的时候,用self或者static关键字后面跟着::操作符,即可。注意,在访问静态成员的时候,::后面需要跟$符号 self:: $president = $newPrsdt ; // 使用parent关键字就能够访问父类的静态成员 echo parent:: $sValue ; } // 默认构造函数,在对象被实例化的时候自动调用 function __construct( $name , $height , $weight , $team , $playerNumber ){ $this ->name = $name ; //$this是php里面的伪变量,表示对象自身。可以通过$this->的方式访问对象的属性和方法 $this ->height= $height ; //父类中的属性,可以通过$this来访问 $this ->weight= $weight ; $this ->team= $team ; $this ->playerNumber= $playerNumber ; } function getAge(){ echo $this ->name. "'s age is " . $this ->age. "<br>" ; } } //类到对象的实例化 // 类的实例化为对象使用关键字new,new之后紧跟类的名称和一对括号 $jordan = new NbaPlayer( "jordan" , "198cm" , "98kg" , "bull" , "23" ); $james = new NbaPlayer( "james" , "210cm" , "98kg" , "heat" , "23" ); // $james->changePresident();这样会出错! // 在类定义外部访问静态属性,我们可以用类名加::操作符的方法来访问类的静态成员。 echo NbaPlayer:: $president . "<br>" ; NbaPlayer::changePresident( "Dam silver" ); //替换静态变量 echo NbaPlayer:: $president . "<br>" ; //可以输出替换的变量 echo Human:: $sValue . "<br>" ; ?> |
4.面向对象--final成员
使用类的final成员特性就可以达到这样的效果
-final关键字
final使用后就不能继承类或方法,并且方法不能在子类中被修改
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<?php //子类中编写跟父类方法名完全一致的方法可以完成对父类方法的重写(overwrite) // 对于不想被任何类继承的类可以在class之前添加final关键字 // 对于不想被子类重写(修改)的方法,可以在方法定义的前面添加final关键字 // 如果在baseclass前面添加final 那么这个类不能被继承 class BaseClass{ public function test(){ echo "BaseClass::test <br>" ; } // 添加final关键字能够让这个方法不能够在子类中重写 final public function test1(){ echo "BaseClass::test1 <br>" ; } } class ChildClass extends BaseClass{ public function test( $temp =null){ echo "ChildClass::test " . $temp . "<br>" ; } /* 父类中的final给了test1()方法,而不能继承 public function test1(){ echo "ChildClass::test1 <br>"; } */ } $obj = new ChildClass(); $obj ->test( "TMP" ); $obj ->test1(); //可以继承父类中的test1()方法,但是不能改写 ?> |
5.面向对象--数据访问
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
实例: <?php // 1.parent关键字可以用于调用父类中被子类重写了的方法 // 2.self关键字可以用于访问类自身的成员方法,也可以用于访问自身的静态成员和类常量; //不能用于访问类自身的属性;使用常量的时候不需要在常量名称前面添加$符号 //3.static关键字用于访问类自身定义的静态成员,防伪静态属性时需要在属性前面添加$符号 class BaseClass{ public function test(){ echo "BaseClass::test <br>" ; } final public function test1(){ echo "BaseClass::test1 <br>" ; } } class ChildClass extends BaseClass{ // const为常量,不需要用$在前面 private static $sValue = 'static value' ; //这种叫伪静态 const CONST_VALUE = 'A constant value' ; public function test( $temp =null){ echo "ChildClass::test " . $temp . "<br>" ; parent::test(); //用parent关键字可以访问父类中被子类重写的方法 调用父类原来的test方法 self::called(); //可以用self调用自己这个类内的方法 echo self::CONST_VALUE. "<BR>" ; echo self:: $sValue . "<BR>" ; } final public function called(){ echo "ChildClass::called() called <br>" ; } } $obj = new ChildClass(); $obj ->test( "TMP" ); // $obj->test1(); ?> |
6.面向对象--接口
问题:
-人会吃饭,动物也会吃饭
-有些植物也可以吃东西(比如猪笼草)
·接口就是把不同类的共同行为进行了定义,然后在不同的类里面实现不同的功能
·一旦某个类实现了某个接口,那么就必须实现接口定义的方法
·人这个类实现了“会吃东西”这个接口,那么人必须实现接口定义的“吃饭”方法
·某个类实现(implements)了某个接口和继承(extends)了某个类的区别
-实现接口跟继承类很类似,但是接口不能直接创建自己的对象
·如果创建了“会吃东西”这个接口的对象,那么具体怎么吃根本不知道
-继承的父类必须有该方法的具体实现,子类可以重写父类的方法,也可以不重写
-接口里面的方法是不需要具体实现的,只要定义了方法的名称和参数就可以了,具体的实现必须在实现类中定义
-一句话概括:类的方法必须有实现,接口的方法必须为空
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
<?php // interface关键字用于定义接口 interface ICanEat{ // 接口里面的方法不需要有方法的实现 public function eat( $food ); } // implements关键字用于表示类实现某个接口 class Human implements ICanEat{ // 实现了某个接口之后,必须提供接口中定义的方法的具体实现 public function eat( $food ){ echo "Human eating " . $food . "<br>" ; } } class Animal implements ICanEat{ // 实现了某个接口之后,必须提供接口中定义的方法的具体实现 public function eat( $food ){ echo "Animal eating " . $food . "<br>" ; } } $obj = new Human(); $obj ->eat( "Apple" ); $monkey = new Animal(); $monkey ->eat( "Banana" ); // 不能实例化接口 // $eatObj = new ICanEat(); // 可以用instanceof关键字来判断某个对象是否实现了某个接口 var_dump( $obj instanceof ICanEat); function checkEat( $obj ){ if ( $obj instanceof ICanEat){ $obj ->eat( 'food' ); } else { echo "The obj can't eat<br>" ; } } // 相同的一行代码,对于传入不同的接口的实现的对象的时候,表现是不同的,这就是多态 checkEat( $obj ); checkEat( $monkey ); // 可以用extends让接口继承接口 interface ICanPee extends ICanEat{ public function pee(); } class Human1 implements ICanPee{ public function pee(){ echo "I can pee" ; } // 当继承一个接口的时候 也需要实现另一个接口中的方法 // 当类实现子接口时,父接口定义的方法也需要在这个类里面实现 public function eat( $food ){ echo "Animal eating " . $food . "<br>" ; } } ?> |
7.面向对象--多态
因为接口的方法实现可以很多,所以对于接口里面定义的方法的具体实现是多种多样的,这种特性我们称为多态
-比如接口A有两个实现B和C,B和C对A里面定义的方法的实现可以是不同的,这种现象就是多态。
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php function checkEat( $obj ){ if ( $obj instanceof ICanEat){ $obj ->eat( 'food' ); } else { echo "The obj can't eat<br>" ; } } // 相同的一行代码,对于传入不同的接口的实现的对象的时候,表现是不同的,这就是多态 checkEat( $obj ); checkEat( $monkey ); ?> |
8.面向对象--抽象类
·接口里面的方法都是没有实现的,而类里面的方法都是有实现的。
·有没有一种形态,允许类里面一部分方法不实现呢?
-当接口中的某些方法对于所有的实现类都是一样的实现方法,只有部分方法需要用到多态的特性
实例
-人和动物吃东西是不同的,但是呼吸是相同的,不需要为人和动物分别实现呼吸的功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
实例:(既有接口,里面又有类方法) <?php // abstract关键字用于定义抽象类 abstract class ACanEat{ // 在抽象方法前面添加abstract关键字可以标明这个方法是抽象方法,不需要具体实现 abstract public function eat( $food ); // 抽象类中可以包含普通的方法,有方法的具体实现 public function breath(){ echo "Breath use the air<br>" ; } } // 继承抽象类的关键字是extends class Human extends ACanEat{ // 继承抽象类的子类需要实现抽象类中定义的抽象方法 public function eat( $food ){ echo "Human eating" . $food . "<br>" ; } } class Animal extends ACanEat{ public function eat( $food ){ echo "Animal eating" . $food . "<br>" ; } } $man = new Human(); $man ->eat( "Apple" ); $monkey = new Animal(); $monkey ->eat( "banana" ); $monkey ->breath(); //和Animal类共用了抽象类中的breath方法 ?> |
五、面向对象的特殊实践
1.面向对象--魔术方法
·__tostring()
-当对象被当做String使用时,这个方法会被自动调用。
-Echo $obj;
·__invoke()
-当对象被当成方法调用时,这个方法会被自动调用
-$obj(4);
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?php class MagicTest{ // __tostring会在把对象转换为string的时候自动调用 public function __tostring(){ return "this is tostring<br>" ; } // __inboke会在把对象当做一个方法调用的时候自动调用 public function __invoke( $x ){ echo "this is invoke " . $x . "<br>" ; } } $obj = new MagicTest(); echo $obj ; //自动调用__tostring(); $obj (5); //自动调用__invoke方法 ?> |
2.面向对象--魔术方法之 __call()和__callStatic()
·__call()
-当对象访问不存在的方法名称时,__call()方法会被自动调用
·__callStatic()
-当对象访问不存在的静态方法名称时,__callStatic()方法会被自动调用
·这两个方法在PHP里面也被称为方法的重载(overloading)
-注意区分重写(overwrite)
-通过这两个方法,同一个方法的名称的调用可以对应不同的方法实现
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?php class MagicTest{ // 这个方法的参数第一个就是调用的方法的名称,第二个参数是方法调用的参数组成的数组 // implode 分割函数 public function __call( $name , $arguments ){ echo "Calling " . $name . " with parameters " .implode( "," , $arguments ). "<br>" ; } // 静态方法的重载,注意这个方法需要设定为static public static function __callStatic( $name , $arguments ){ echo "Static calling " . $name . " with parameters " .implode( "," , $arguments ). "<br>" ; } } $obj = new MagicTest(); $obj ->runTest( "para1" , "para2" ); //自动调用__call方法 MagicTest::runTest( "para1" , "para2" ); //自动调用__call方法 ?> |
3.面向对象--魔术方法之 __get()和__set(),__isset(),__unset()
-在给不可访问属性赋值时,__set()会被调用。
-读取不可访问属性的值时,__get()会被调用。
-当对不可访问属性调用isset()或empty()时,__isset()会被调用
-当对不可访问属性调用unset()时,__unset()会被调用
-所谓不可访问属性,实际上就是在调用某个属性时发现这个属性没有被定义,这时候不同的操纵会触发不同的魔术方法
-这几个方法也被成为属性重载的魔术方法
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<?php class MagicTest{ public function __get( $name ){ return "Getting the property " . $name . "<br>" ; } public function __set( $name , $value ){ echo "Setting the property " . $name . " to value " . $value . "<br>" ; } public function __isset( $name ){ echo "__isset invoked<br>" ; return true; } public function __unset( $name ){ echo "unsetting property" . $name . "<br>" ; } } $obj = new MagicTest(); echo $obj ->className. "<br>" ; $obj ->className= "MagicClass" ; echo '$obj->className is set?' .isset( $obj ->className). "<br>" ; echo '$obj->className is empty?' . empty ( $obj ->className). "<br>" ; unset( $obj ->className); ?> |
4.面向对象--魔术方法之 __clone()
克隆方法(在没有设置对象的时候,会自动调用)
实例:(既有接口,里面又有类方法)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
实例: <?php class NbaPlayer{ public $name ; function __clone(){ $this ->name = "TBD" ; } } $james = new NbaPlayer(); $james ->name= "james" ; $james2 = clone $james ; echo "Before set up: James2's:" . $james2 ->name. "<br>" ; $james2 ->name= "james2" ; echo $james ->name. "<br>" ; echo $james2 ->name. "<br>" ; ?> |
总的全部就是这么多了,上面还没有说到封装特性。其实封装就是把一个物体抽象出来后作为一个个体进行属性,方法做成一个类,然后流出对应的入口和出口,就叫封装了。