您的位置:首页 > Web前端 > JavaScript

javascript学习笔记

2015-12-02 02:21 477 查看
◆javascript的基本介绍

1.js 是用于web开发的脚本语言

脚本语言是什么?

1)脚本语言往往不能独立使用,它和html/jsp/php/asp/asp.net配合使用

2)脚本语言有自己的变量,函数,控制语句(顺序,分支,循环)

3)脚本语言实际上是解释性语言(即在执行的时候直接对源码进行执行)

4)java程序:java--->class--->jvm js--->浏览器(js引擎来解释执行)

2.js 在客户端(浏览器)执行



客户端向服务器发送请求,下载html和js文件,然后在客户端执行操作。

3.因为js是有浏览器来解释执行的,因此这里有个问题,不同类型的浏览器可能对js的支持不一样。

◆js的开发工具选择

1.记事本

2.eclipse(myeclipse)

注意:javascript严格区分大小写,每一句语句最后一定要以 ; 结尾

案例1

需求:打开网页后,显示hello world

<html>

<head>

<!--js代码一般是放在 head标签间的,但实际上也可以在别的位置-->

<script language="javascript">

window.alert("hello!");

</script>

</head>

<body>

</body>

</html>

问题

1.js代码可以放在head里,也可以放在body里

2.js必须用

<script language="javascript">

js代码

</script>

注意:如果没有用script包起来,浏览器会将其视为普通文本。

3.在一个html文件中(jsp/php/asp)可以出现多对<script>片段,浏览器将会按照先后顺序依次执行

案例2:

对前面的程序,改进成一个简单的家法运算程序

<html>

<head></head>

<body>

<!--js代码一般是放在 head标签间的,但实际上也可以在别的位置-->

<script language="javascript">

//js中变量的定义(在js中变量用var表示,不管实际类型)

var num1=456;

var num2=89;

var result=num1+num2;

window.alert("结果是"+result);//alert函数,是

</script>

</body>

</html>

◆js的变量的类型究竟怎样决定:

1.js是弱数据类型语言(即定义变量的时候无需指定类型)

即:在定义变量的时候,统一使用var表示,甚至可以去掉var这个关键字

2.js中的变量的数据类型,是由js引擎来决定的。

var name="creabine"; //name是字符串类型

var kk=2 //kk是数字类型

var yy //yy是undefined

如果name="233" //这时name自动变成数字类型

◆即,js引擎可以根据数据的值来判断数据类型

◆js的命名规范(变量,函数的命名)

1.使用大小写字母,数字,_,$,可以命名

2.不能以数字开头

3.不能使用js的关键字和保留字

4.区分大小写

5.单行注释使用 // 多行注释使用 /**/

◆js的数据类型

1.基本数据类型,分为:

(1)Number 数值

1).整形常量(十进制、八进制、十六进制)

注意此例:

var a=123;

var b=034;//十进制中不以0开头,而这里的034以0开头,js将认为034为八进制数,此八进制数转换为十进制数(4*8^0+3*8^1+0*8^2=28)的结果为28,故c=a+b=123+28=151。

var c=a+b;

window.alert(c);

2).实型常量

12.32、19.458、5E3(即5*10^3,这里的e大小写都可以,也可以写作5e3)

var a=12.32;

特殊数值:

1.NaN (not a number)

例:

var a="abc";

window.alert(parseInt(a)); //parseInt(a)这个函数为:解析一个字符串并转为整数。这里的变量a=abc,a并不是数值类型,故无法转为整数,会报错为NaN。也可以用这个技巧去判断一个值是不是数字。

2.infintiy(无穷大)

例:

window.alert(6/0); //6/0就是无穷大

◆有两个函数可以用于判断NaN,infinity,分别是

isNaN() 检查某个值是不是数字

is

Finite() 检查某个值是否为有穷大的数

下面只举例isNaN:

window.alert(isNaN("abc")); //判断abc是否不是数字,确实不是数字,返回true

window.alert(isNaN("123")); //判断123是否不是数字,是数字,返回false

(2)String 字符串型

"a book of JavaScript" 、 "a" 、 "dkfjkd"fdf "fd f"

例:

var a="abc";

var b="abcddd";

car c="fdskfjkls\"gfg\"faksjf"; //字符串类型的值,要用“”包起来,而当值中有“”引号时,用反斜杠\ 来转意,这时输出的时候,并不会输出反斜杠\,会输出它旁边的双引号,

window.alert(c);

(3)Boolean 布尔型:即true和false

举例:

var a=true;

var b=false;

js中非0的数,都为true,包括小数;js中字符串也是true。

if(1.1){

window.alert('ok');

}

通过typeof可以看到变量的具体数据类型是什么,举例:

<html>

<head>

<script language="javascript">

var v1="abc";

var v2=890;

window.alert("v1是"+typeof v1);

window.alert("v2是"+typeof v2);

v1=567;//js是动态语言,变量类型是可以动态变化的,这里赋值567,v1又变成了数字类型。

window.alert("v1是"+typeof v1);

</script>

</head>

<body>

</body>

</html>

2.复合类型,分为

(1)数组

(2)对象

3.特殊类型

1.null 空值

var a=null;

2.undefine 未定义

var tt;

window.alert(tt);//弹框说明未定义

◆js数据类型的转换

1.自动转换

var a=123; //a是数值

var a="hello"; /a是字符串

2.强制转换 parseInt() parseFloat()

如:

var a=12345;

a=parseInt(a); //使用系统函数强制转换,转为Int,整数。

var b=90; //b是数值

b=b+""; // b+“”空值,把b转为字符串

◆js的运算符

+ - * / %(取模,即两数相除取余,常用于判断两个数是否能够整除)

例:

var a=80;

var b=30;

var c=a%b;

window.alert(a%b);//取模主要用于整数型,小数会不明确

if (c==0){

window.alert("a能被b整除");

}else{

window.alert("a不能被b整除");

}

◆注意:++运算符 --运算符的意义

举例:举了++,--同理。

var a=57;

var b=++a;//b=++a 等价于 [a=a+1;b=a]; 而 b=a++ 等价于[b=a;a=a+1;] 简单来说,就是++在前,就是a先自加再赋值;++在后,就a先赋值,a再自加。两种处理得到的b的值是不同的

window.alert(b);

window.alert(a);

◆ +=左加 -+左减 /=左除 %=左取模

例子:

var a=56; var b=90;

a-=34;//a=a-34; a=22

b%=a;//b=b%a; 此时b=90,a=22,取模结果为2

window.alert(b);

window.alert(a);

介绍 window.prompt() 和 document.writeln() 两个函数

var val=window.prompt('请输入值');//该函数为弹出一个框输入值

var val2=window.prompt('请再输入一个值');

document.writeln('你的输入是'+(val+val2));//这里是字符串拼接

document.writeln('你的输入是'+(parseFloat(val)+parseFloat(val2)));//这里把字符串转为数值,然后进行加法运算。

◆关系运算符

== 等于 >大于 < 小于 >=大于等于 <= 小雨等于 != 不等于

案例:

var a=window.prompt('请输入数字a');

var b=window.prompt('请再输入数字b');

a=parseFloat(a);//这里把a转为小数,因为不知道输入的是整数还是小数,统一转为小数

b=parseFloat(b);

if(a==b){

window.alert('a=b');

}else if(a<b){

window.alert('a<b');

}else{

window.alert('a>b');

}

◆逻辑运算符

1.与 &&

重要的案例:

var a=90;

var b=9;

if(a>b && a++>90){//这里a>b为true,故继续执行a++>90,等价于[a>90; a++],而a>90为false,所以输出no;a++之后a=91,所以输出a=91.

window.alert('ok');

}else{

window.alert('no');

}

window.alert('a='+a);

案例说明:

if(逻辑表达式1 && 逻辑表达式2){

}

如果 逻辑表达式1为true,则会继续执行逻辑表达式2

如果 逻辑表达式1为false,则不会执行逻辑表达式2(因为与需要1、2同时为true才为true,1为false,没必要判断2了)

2.或 ||

if(逻辑表达式1||逻辑表达式2){

}

如果,逻辑表达式1为true,则不再执行逻辑表达式2(因为只要1为true,就为true了,没必要判断2)

如果,逻辑表达式1为false,才会执行逻辑表达式2

案例1:

var a=90;

var b=9;

if(a>b || a++>90){//修改a b之间的大于小于号,可以测试a++的执行与否

window.alert('ok');

}else{

window.alert('no');

}

window.alert('a='+a);

这里有一个非常重要的知识点:

//在js中||究竟返回什么值

//结论:|| 将返回第一个不为false的值(对象亦可),或者返回最后一个值(若全部都是false的话)

//返回的结果,不一定是布尔值,也可能是对象

案例:

var a=4;//js中,非0的数字即为true,按上述结论,即返回4

var b=90;

window.alert(a||b);

var d=0;

window.alert(d||b);//此时d为false,b为true, b是第一个不为false的值,所以返回90

var f=null;

window.alert(d||f);//此时d,f都为false,返回最后一个值,即f的值,0

var obj=new Object();//这里说明,||所返回的值,不一定是布尔型,还可能为对象

var g=d||f||obj;

window.alert(g+"类型"+typeof g);

3.非 !

if(! 逻辑表达式){

}

如果 逻辑表达式 为true, 【!逻辑表达式】为false,

如果 逻辑表达式 为false, 【!逻辑表达式】为true。

特别说明:在逻辑运算中,0、“”、false、null、undefined、NaN均表示false;其他都认为是true。

例如:

var a=0;//这里的0换成 “”、false,null,undefined,NaN,均一样。

if(a){//这里a=0,表示false,即不执行window.alert('ok') 语句;若改为if(!a),则为true,执行window.alert('ok')语句。

window.alert('ok')

}

◆js也有位运算和移位运算,其规范和java一致,这里没太搞懂,虽然不是重点,实际开发用的少。

案例:

var a=4>>2;

window.alert(a);//结果是1

var b=-4>>2;

window.alert(b);//结果是-1

◆javascript的控制语句

1.顺序控制

对编程而言,不控制其流程就是顺序执行

2.分支控制

1)单分支

基本语法:

if(条件表达式){

//执行语句;

}

2)双分支

基本语法

if(条件表达式){

执行语句1;

}else{执行语句2;

}

案例:

编写一个程序,可以输入人的年龄,如果年龄大于18岁,则输出“你年龄大于18,能上这个网站了=w=”,否则输出“你还未满18岁不能看这种奇怪的东西”

代码:

var age=window.prompt("请输入你的年龄");

if(age>=18){

window.alert("你成年了,能上这个网站了=w=");

}else{window.alert("你还未满18岁不能看这种奇怪的东西");

}

3)多分支

基本语法:

if(条件表达式1){

//执行

}else if{

//执行

}else if...{//可以有多个else if

}

else{//最后可以没有这个单独的else

}

举例:

如果是男,就去男厕所,如果女,就上女厕所,否则不上厕所。

代码:

var sex=window.prompt("请输入性别");

if(sex=="男"){

window.alert("上男厕所");

}else if(sex=="女"){

window.alert("上女厕所");

}else{

window.alert("不上厕所");

}

注意:代码会按照顺序依次进行判断,一旦找到一个满足条件的执行完了之后,就结束整个多分支,后边的都不会再去判断。

◆switch 如果选择是具体的值,用switch;如果是个范围,用if..else

基本语法:

switch(表达式){

case 常量1;

//执行语句

break;

case 常量2;

//执行语句

break;

...
default;

//执行语句

}

案例:

//switch 语句,它的值可以是js允许的任何值

var a=890;

switch(a){

case 890://注意这里是冒号 :

window.alert("890");

break;//break 作用是跳出整个switch。如果这里没有break,会不再判断,继续向下执行,直到遇到break。也就是说,如果去掉这里的break,接下来不会管case 90,会直接执行window.alert("90");然后遇到break,再跳出循环

case 90://注意这里是冒号 :

window.alert("90");

break;

default://注意这里是冒号 :

window.alert("没有匹配的值");

break;

}

window.alert("end");

针对该案例,我们得出以下结论:

1.js的switch语句的数据类型可以是js支持的任何类型,数值,字符串,null,undefined,甚至变量都可以,但数组和对象除外。

2.case后面的值得数据类型可以是任意的,数组和对象除外。

3.break的作用是跳出整个switch

4.如果没有匹配值,则执行default。

◆for循环

基本语法:

for(循环初值;循环条件;步长){

语句;//循环体

}

案例:

for(var i=0;i<10;i++){

document.writeln("你好</br>");

}

for循环的流程图:





结束---------------| (接上图)

◆while循环 判断是否为真,为真就执行,为假就跳出来。

基本语法:

while(条件表达式){

//执行语句;

}

案例:输出hello10次

var i=0;

while(i<10){

document.writeln("hello</br>");

i++;

}

◆ do......while

基本语法:

do{

//执行

}while(条件表达式){

}

案例:

var i=0;

do{

document.writeln("hello</br>");

i++

}while(i<10);



注意:while是先判断再执行,do...while是先执行一次再判断是否循环

练习题:

//请编写一个程序,可以接收一个整数n,(1)计算1+2+...+n的值,(2)计算1!+2!+...+n!的值

//第一题

var n=window.prompt("请输入一个整数n");

n=parseInt(n);//要强制转换,不然默认n是字符串

var result=0;

for(var i=1;i<=n;i++){

result=i+result;

}

document.writeln("结果是"+result);

//第二题

var result2=0;

var temp=1;

for(var i=1;i<=n;i++){//阶乘和的算法想了半天

for( var j=1;j<=i;j++){

temp=temp*j;

}

result2=result2+temp;

temp=1;

}

document.writeln("结果是"+result2);

在IE8中,我们可以通过工具来对js代码进行调试,尤其是页面比较复杂的情况下很有用。

首先要在IE浏览器--Internet选项---高级---取消“禁止脚本调试”



F11:一句一句执行,若遇到函数,则跳入函数中一句依据执行。

F10:按过程执行,若遇到函数,则把整个函数当一个语句执行,不调入函数

shift+F11:从一个函数中跳出

右边监视窗口可以看到变量的值的变化。

右下断点可以看设置的断点情况。

练习:

请编写一个程序,可以接收一个整数N层数,打印出1.金字塔的一半;2.完整的金字塔图形;3.完整的菱形;4.空心菱形。

代码:

//打印金字塔小练习

var n=window.prompt('请输入一个整层数n');

n=parseInt(n);

//1.金字塔的一半

for(var i=1;i<=n;i++){

for(var j=1;j<=i;j++){

document.writeln("*");

}

document.writeln("<br/>");

}

//2.完整的金字塔

for(var i=1;i<=n;i++){

for(var j=1;j<=n-i;j++){

document.writeln(" ");

}

for(var j=1;j<=2*i-1;j++){

document.writeln("*");

}

/*for(var j=1;j<=n-i;j++){

document.writeln(" ");

}这里是*号后边的空格,可以不打,显示上是一样的*/

document.writeln("<br/>");

}

//3.空心金字塔

for(var i=1;i<=n;i++){//这里分行

for(var k=1;k<=n-i;k++){

document.writeln(" ");

}//这个for循环输出每行最开始的空格

for(var j=1;j<=2*i-1;j++){//这里输入每行除了一开始的空格之外的东西

if(i==n){//当i=n,即最后一行的时候,全部输出*

document.writeln("*");

}else if (j==1||j==(2*i-1)){//这里用 或 当j=1,即输出每行的第一个*号,然后结束,不运行 或 后边的东西;当j不为1时,即每行输出第一个*号后,开始判断最后一个*号的位置,即j=2*i-1时输出最后一个*号

document.writeln("*");

}else{

document.writeln(" ");//其他时候都输出空格

}

}

document.writeln("<br/>");//每结束一行,换行一次

}

//4.画菱形

for(var i=1;i<=n;i++){//菱形的上半部分的三角形,包括菱形最宽的一行

for(var j=1;j<=n-i;j++){

document.writeln(" ");

}

for(var j=1;j<=2*i-1;j++){

document.writeln("*");

}

document.writeln("<br/>");

}

for(var i=n-1;i>0;i--){//这里是下边的部分,因为最宽的第n行已经在上边输出过了,所以下边从n-1开始。这里的i相当于下半个三角形从下往上数的第i行。i由上至下的值从n-1到1。

for(var j=1;j<=n-i;j++){

document.writeln(" ");

}//这里正常输入每行前边的空格

for(var j=1;j<=2*i-1;j++){

document.writeln("*");

}//这里通过i计算出每行的*号数量并输出

document.writeln("<br/>");

}

//5.空心菱形【还没搞定,代码显示的不对。】

for(var i=1;i<=n;i++){//这里分行

for(var k=1;k<=n-i;k++){

document.writeln(" ");

}//这个for循环输出每行最开始的空格

for(var j=1;j<=2*i-1;j++){//这里输入每行除了一开始的空格之外的东西

if (j==1||j==(2*i-1)){//这里用 或 当j=1,即输出每行的第一个*号,然后结束,不运行 或 后边的东西;当j不为1时,即每行输出第一个*号后,开始判断最后一个*号的位置,即j=2*i-1时输出最后一个*号

document.writeln("*");

}else{

document.writeln(" ");//其他时候都输出空格

}

}

document.writeln("<br/>");//每结束一行,换行一次

}

for(var i=n-1;i>0;i--){//这里是下边的部分,因为最宽的第n行已经在上边输出过了,所以下边从n-1开始。这里的i相当于下半个三角形从下往上数的第i行。i由上至下的值从n-1到1。

for(var j=1;j<=n-i;j++){

document.writeln(" ");

}//这里正常输入每行前边的空格

for(j=1;j<=2*i-1;j++){

document.writeln("*");

if(i==1){

document.writeln("*");

}else if (j==1&&j==(2*i-1)){//这里用 或 当j=1,即输出每行的第一个*号,然后结束,不运行 或 后边的东西;当j不为1时,即每行输出第一个*号后,开始判断最后一个*号的位置,即j=2*i-1时输出最后一个*号

document.writeln("*");

}else{

document.writeln(" ");//其他时候都输出空格

}

}

document.writeln("<br/>");

}

◆JS函数

1.为什么需要函数:将相同的功能封装在函数里,不同的页面之间可以随意调用,减少代码冗余,更精简

2.函数的基本概念

为完成某一功能的代码(语句、指令)的集合

3.基本语法:

function 函数名(参数列表){

//代码

return 值//有的函数有返回式,有的没有,没有就不写。

}

说明:

1.参数列表:表示函数的输入

2.函数主体:表示为了实现某一功能代码块

3.函数可以有返回值,也可以没有

入门案例:

<script language="javascript" type=text/javascript>//这里两个最好都写,兼容性好

<!--

//输入两个数,在输入一个运算符(+、-、*、/),得到结果

var num1=window.prompt("请输入第一个数字num1");

var num2=window.prompt("请输入第二个数字num2");

var operator=window.prompt("请输入运算符(+、-、*、/)");

num1=parseFloat(num1);

num2=parseFloat(num2);

//如何调用函数

document.write("res="+ji_suan(num1,num2,operator));//这里的函数参数是数字,所以上边一定要先转换成数字

//自定义函数.

//输入两个数,在输入一个运算符(+、-、*、/),得到结果

function ji_suan(num1,num2,operator){//特别强调,参数名前不要带 var

var res=0;

if(operator=="+"){

res=num1+num2;

}else if(operator=="-"){

res=num1-num2;

}else if(operator=="*"){

res=num1*num2;

}else{

res=num1/num2;

}

return res;//返回

}

//-->//这里的小括号包起来,也是为了兼容性好

</script>

注意:如果其他的html文件也想使用这个函数要怎么办呢



把上面的函数单独提出,写到js,然后再需要的地方引入

代码:

myfunction.js:

//自定义函数.

//输入两个数,在输入一个运算符(+、-、*、/),得到结果

function ji_suan(num1,num2,operator){//特别强调,参数名前不要带 var

var res=0;

if(operator=="+"){

res=num1+num2;

}else if(operator=="-"){

res=num1-num2;

}else if(operator=="*"){

res=num1*num2;

}else{

res=num1/num2;

}

return res;//返回

}

在需要的文件中引入:

<script language= "javascript" src="js文件的路径"></script>//这里一定要用</script>结尾,否则无法引入。

◆函数调用的方式

1.普通调用

函数名(实际参数...);

2.通过指向函数的变量去调用

var myvar=函数名;

myvar(实际参数);

3.关于接受函数返回值的问题:

var myvar=test("abc");//这里把test("abd")赋值给了myvar,所以会直接弹窗一个abc

//如果test函数没有返回值,但是你又接受了,则返回的就是undefined;

//如果有返回值,则返回值是什么,就是什么。在test代码中加入return 90;则会弹窗出90

window.alert(myvar);

◆js函数的调用过程,内存分析

案例:

//abc是一个函数,它接收一个数值,如果接受的数字大于3,那么-1再赋值给自己

function abc(num1){

if(num1>3){

abc(--num1);//递归

}

document.writeln(num1);

}

若这样调用:

abc(5);

则返回的结果为:3 3 4

分析图:



个人理解:在这个函数运行的时候,其实运行了很多次,直到num1=3的时候(即最右边的方框),函数运行到最后一次,if失效,此时输出了3,之后回到左边的框,也就是上一层函数,if结束之后,还有一个doc..未运行,此时的num1是num1=4自减之后的结果,即为3,再输出一个3;然后再回到左边num1=5的框,运行该框的doc...此时该层的num1是num1=5自减之后的结果,即为4。至此,函数全部运行结束,故输出为3
3 4.

注意:

1.函数的参数个数可以任意指定。

2.参数可以是多个,每个参数的类型可以是任意的。

3.js函数天然支持参数个数可变。

如:

//编写一个函数,可以接受任意多个数,并计算他们的和

function abc2(){

//在js中有一个 arguments,可以访问所有传入的值

//window.alert(arguments.length);这样可以访问个数

//那么我们可以用for循环来遍历所有的参数

for(var i=0;i<arguments.length;i++){

window.alert(arguments[i]);

}

}

可以这样调用:

window.alert("abc2(45,90,900);");

abc2(45,90,900);

window.alert("abc2(4,\"hello world\")");

abc2(4,"hello world");

window.alert("abc2();");

abc2();

4.js支持动态创建函数。

练习:(视频第26讲结尾处)

1.金字塔封装

2.页面输入九九乘法表

◆数组

1.为什么需要数组

看一个需求:

王大爷养乌龟的问题:王大爷有6只乌龟,体重高分别是3kg、5kg、1kg、3.4kg、2kg、50kg。请问六只乌龟的总体重是多少?平均体重是多少?

2.解决方法:

使用数组,这种数据类型(引用类型/复杂类型/复合类型),数组的基本概念:用于存放一组数据。

特别强调:js中的数组,可以存放各种类型的数据(数值,字符串...)

王大爷养乌龟(快速入门):

//数组的遍历

for(var i=0;i<weights.length;i++){

document.writeln(weights[i]);

all_weight+=weights[i];

}

avg_weight=all_weight/weights.length;

document.writeln("总体重是"+all_weight);

document.writeln("平均体重是"+avg_weight.toFixed(2));//toFixed()函数可以控制一个数字的小数位数

window.alert(avg_weight.constructor);//若想知道某个变量的数据类型,可以使用这个来看数据类型。

3.数组的细节:

1)基本用法:

var 数组名=[元素1,元素2,...]

元素的值可以是任意类型: var a=[1,2.5,sfd,true]

数组在内存中的存在形式:

2)js中的数组是引用传递

举例说明:

var myarr=[456,90,900];

function abc2(arr){

arr[0]=35;

}

abc2(myarr);

for(var i=0;i<myarr.length;i++){

document.writeln(myarr[i]);

}//输出结果为多少? 答案是35 90 900

原理图:



3)数组的引用

基本用法:

数组名称[下标] 下标从0开始

比如:

var a=[23,dsad,4.6];

我们访问a[2],则会输出4.6;因为下标从0开始。

如果我们访问a[3](没有第四个元素),则会输出undefined(实际上并没有弹窗)

结论:不能访问不存在的元素

4)js的数组可以动态增长,即已经定义好的数组,可以随时增加元素个数。

var a=[2,3];

alert("数组的大小是"+a.length);

a[2]=56;//动态的增长,数组变成了a=[2,3,56]

alert(a[2]);

alert("数组的大小是"+a.length);

5)字符串分割生成一个字符串数组,split()函数

比如:

var str="hello world creabine 陈磊";

var arr=str.split("",2);//split(“以什么分割字符串”,显示前几个【若不写则全部显示】)

for(var i=0;i<arr.length;i++){

document.write(arr[i]+" ");

}

6)遍历数组还有这个方法,不过很少用,了解即可,不用深究

var arr=[45,90,0];

//arr["gg"]=9000;//js的数组下标不仅可以用数字,还能用字符串,但是一般不用这个,了解即可

for(var key in arr){

window.alert(key+"="+arr[key]);

}

//这里的key是数组的下标,从0开始

//练习,运动会上,五个小孩比赛轮滑,他们划100米,分别用时10s,12s,5.7s,9s,14s,编写一个程序,计算它们的平均时间。在基础上,实现自主输入用时,并且显示平均值为2位小数。

//var time=[10,12,5.7,9,14];

//自主输入数字数组的方法

var a=window.prompt("请分别输入他们的时间,以,号间隔");

var time=a.split(",");//将输入的字符串转化为字符串数组

for(i=0;i<time.length;i++){

time[i]=parseFloat(time[i]);

}//遍历数组的所有元素并将他们的数据类型转为浮点型

var sum=0;

var avg=0;

for(var i=0;i<time.length;i++){

sum+=time[i];//遍历数组求和

}

avg=sum/time.length;//求平均

window.alert("平均时间为"+avg.toFixed(2));//显示2位小数

◆多维数组:二维数组

多维数组我们只介绍二维数组:一个数组的元素还可以是数组,这就构成了二维数组。二维数组中的元素数组之间的长度,可以不相同。

举例:

//二维数组

/*

var arr=[["creabine",123,4.5],["a","b","c"],[89,0]];//二维数组的元素数组长度可以不同

//二维数组的遍历方法

for(var i=0;i<arr.length;i++){//遍历每个元素

//输出每个元素arr[i][数组]的元素)

for(var j=0;j<arr[i].length;j++){

document.writeln(arr[i][j]+" ");//arr[i][j]是arr[i]这个数组的j号元素

}

document.writeln("<br/>");//输出了一个元素之后,换行

}

//若要直接访问"c",那应该怎么写

window.alert(arr[1][2]);

*/

//请输出如下图形

/*

0 0 0 0 0 0

0 0 1 0 0 0

0 2 0 3 0 0

0 0 0 0 0 0

*/

代码:

/*

var arr=[[0,0,0,0,0,0],[0,0,1,0,0,0],[0,2,0,3,0,0],[0,0,0,0,0,0]];

for(i=0;i<arr.length;i++){

for(j=0;j<arr[i].length;j++){

document.writeln(arr[i][j]+" ");

}

document.writeln("<br/>");

}

*/

◆矩阵转置

//矩阵转置,即行列互换

var arr=[[2,4,6,8],[8,9,0,-1],[9,6,2,1]];

//定义一个新的数组

var arr2=[];

//初始化,定下来有多少行(旧数组的列就是新数组的行)

for(var i=0;i<arr[0].length;i++){//循环旧数组的列,有4列

arr2[i]=[];//给新数组arr2创造元素数组,也就是新矩阵的行,循环旧数组的列,得到新数组的行,4行。这里开辟的arr2数组的储存空间,所以下边的arr2[j][i]=arr[i][j];才能够实现访问并储存。这里的初始化很重要,要先初始化一个空间给新的数组,不然下边的转置无法实现。

}

//可以动态的添加数据

//遍历旧的数组

for(var i=0;i<arr.length;i++){

for (var j=0;j<arr[i].length;j++){

arr2[j][i]=arr[i][j];//转置是行列互换,直接换i,j即可

}

}

//成功,遍历arr2数组就是一个转置数组

for(var i=0;i<arr2.length;i++){

for (var j=0;j<arr2[i].length;j++){

document.writeln(arr2[i][j]+" ");

}

document.writeln("<br/>");

}

◆js基本语法:排序,用的很少

冒泡排序:

原理图:



原理:从最下边的一个数开始,依次跟头上的数字比较大小,大的就呆在上边,再跟上边一个比较,再换位置。如图第一列,最下边的35跟88比较,88大,维持原位;然后88跟16比较,88大,换到16上边;依次比较,直到88跟90比较,90大,90在上边;然后90再分别与56,79比较,都比他们大,所以90最大,排到第一了。得到第一趟跑完的结果。然后再从最下边开始,跑第二趟,直到排序完成。

案例:

//冒泡排序

var arr=[5,0,-56,900,12,9000,-123];

//大的排序次数(arr.length-1), 第一次排序,找出第一大的放在第一位;第二次排序,找出第二大的放在第二位;以此类推,只要arr.length-1次就够了,倒数第二大的已经在倒数第二位了,最小的不用动了。

for(var i=0;i<arr.length-1;i++){//这里的i可以看作已经跑了i趟,一开始i=0,表示还没跑,跑完一趟之后i=1,表示已经跑了1趟了。

//小的排序

for(var j=0;j<arr.length-1-i;j++){//共有arr.length个数,拿其中一个数,来跟其他数比较,就要比较arr.length-1次。如果已经跑了i趟,那么前i个数已经固定位置了,不需要再比较了,所以只需要比较arr.length-1-i次就可以了。

if(arr[j]>arr[j+1]){//两两比较,若左边的比右边的大,交换

//交换

var temp=arr[j];

arr[j]=arr[j+1];

arr[j+1]=temp;

}

}

}//排序结束

for(var i=0;i<arr.length;i++){

document.writeln(arr[i]+" ");//输出所有元素

}

冒泡排序的优化案例:

//冒泡排序

var arr=[1,4,6,8,9,90,800];

var flag=false;

//大的排序次数(arr.length-1), 第一次排序,找出第一大的放在第一位;第二次排序,找出第二大的放在第二位;以此类推,只要arr.length-1次就够了,倒数第二大的已经在倒数第二位了,最小的不用动了。

for(var i=0;i<arr.length-1;i++){//这里的i可以看作已经跑了i趟,一开始i=0,表示还没跑,跑完一趟之后i=1,表示已经跑了1趟了。

document.writeln("大循环....<br/>");//看看跑了多少趟大循环,在有优化的时候,只要跑一趟,若没有优化,则要跑arr.length-1,也就是6趟。

//小的排序

for(var j=0;j<arr.length-1-i;j++){//共有arr.length个数,拿其中一个数,来跟其他数比较,就要比较arr.length-1次。如果已经跑了i趟,那么前i个数已经固定位置了,不需要再比较了,所以只需要比较arr.length-1-i次就可以了。

if(arr[j]>arr[j+1]){//两两比较,若左边的比右边的大,交换

//交换

var temp=arr[j];

arr[j]=arr[j+1];

arr[j+1]=temp;

flag=true;//flag本来被赋值为false,如果发生了交换,那么falg变为true,也就是,用这个flag的值来判断是否有发生交换。

}

}

//排序优化

if(flag){

flat=false;//这里是,如果falg的值为true,也就是发生了交换,那么把falg的值重置为false。

}else{//如果falg的值是false,说明这一趟,没有发生交换,就说明,已经排序成功了,之后的趟不需要再跑了,直接break跳出循环即可。

break;


}

}//排序结束

for(var i=0;i<arr.length;i++){

document.writeln(arr[i]+" ");//输出所有元素

}

◆js查找:

1.顺序查找:取出来一个一个的比对

2.二分查找:

注意:二分查找有一个前提:该数组必须是有序的。若不是有序数组,则不能使用二分查找。

//二分查找思路:找到数组的中间数(midVal),和你要查找的数(findVal)进行比较,如果midVal>findVal,则说明findVal在数组的左边,就把该数组二分了(就只在左边查找了。)

var arr=[1,4,6,8,9,90,800];

function binarySearch(arr,findVal,leftIndex,rightIndex){

//该函数的变量分别是:数组,要查找的值,数组最左边的脚标,数组最右边的脚标

//防止无穷递归 没懂,为啥???

if(leftIndex>rightIndex){

//提示找不到

document.writeln("找不到");

return;

}

//找到中间这个值

var midIndex=Math.floor((leftIndex+rightIndex)/2);//找到中间的那个脚标。

//leftIndex+rightIndex)/2的值有可能是小数,所以这里使用Math.floor()函数,进行向下取整。

var midVal=arr[midIndex];//由中间的脚标得到中间的值

//与中间值进行比较

if(midVal>findVal){//若中间值大于要找的值,说明要找的值在数组中间值的左边,所以在左边找

//在左边找

binarySearch(arr,findVal,leftIndex,midIndex-1);//这里再次调用函数,讲左边的部分再二分,此时最右的脚标变为了midIndex-1,因为midVal>findVal,所以midVal不等于findVal,他不用参与下一次二分,直接从midIndex-1这个脚标的值开始

}else if(midVal<findVal){//原理同上

//在右边找

binarySearch(arr,findVal,midIndex+1,rightIndex);//原理同上

}else{//也就是midVal=findVal的时候,说明找到了

document.writeln("找到 下标为"+midIndex);//打印出找到的值得下标

return;

}

}

//测试:

binarySearch(arr,8,0,arr.length-1);

js面向(基于)对象编程

澄清概念:

1.js中,基于对象 等同于 面向对象

2.js中,按照标准的说法,是没有类(class)的,没有class这个关键字。但是它去了一个新的名字,叫 原型对象,因此 类 等同于 原型对象。

◆为什么需要对象?

问题提出:

/*

张老太养了两只猫:一只叫小白,3岁,白色。另一只叫小花,10岁,花色。编写程序,当输入猫的名字,就显示猫的名字,年龄,颜色。若用户输入的小猫名字错误,则显示张老太没有这只猫。

*/

//传统放大可以设置多个变量,一个一个赋值,比较麻烦。

//新的解决方法,把猫的属性集中起来,创建一种新的数据类型(原型对象/类)

//用面向对象的方法来解决上面的问题

//这里就是一个Cat类。

function Cat(){

}

//不同的用法,Cat()可以作为函数,也可以作为类。

Cat();//函数

var cat1= new Cat();//类,此时cat1就是一个对象(实例)

cat1.name="小白";

cat1.age=3;

cat1.color="白色";

//从上面的代码我们可以看出:1.js中的对象属性可以动态的添加。2.属性没有限制

window.alert(cat1.name+cat1.age+cat1.color);

◆类(原型对象)与对象的区别和联系:

1.类是抽象的,概念,代表一类事物

2.对象是具体的,代表一个实体

3.对象是以类(原型对象)为模板创建出来的。

◆创建对象的方式有五种:

1.工厂方法--使用new Object创建对象并添加相关属性;

2.使用构造函数来定义类(原型对象)

3.使用prototype

4.构造函数及原型混合方式

5.动态原型方式

目前我们先讲 使用构造函数来定义类(原型对象),然后再创建对象实例。

基本语法:

function 类名(或原型对象名) (){

}

创建对象

var 对象名=new 类名();

现在对对象我们特别说明:

1.js中一切都是对象:

function Person(){}

var a=new Person();

window.alert(a.constructor);//a.constructor,打印出对象实例的构造函数

window.alert(typeof a);//typeof a,打印出a的类型

//其实 a b c 都是类

var b=123;

window.alert(b.constructor);

window.alert(typeof b);

var c="123";

window.alert(c.constructor);

window.alert(typeof c);

◆如何判断一个对象实例是不是某个类型

//思考,如何判断一个对象实例是不是Person类型?

//这里的程序接上边的

//方法一:

if(a instanceof Person){//a instanceof Person 可以判断a是不是Person类型,如果是就返回true,就打印出来了。

window.alert("a是person");

}

//方法二:

if (a.constructor==Person){//a.constructor,打印出对象实例的构造函数判断是否是Person

window.alert("a是person 2");

}

补充说明:函数中带不带 var 的区别

//思考:下边两个例子,返回值为什么有区别

var abc=89;//定义一个全局变量

function test(){

//在下边的函数里,若不带var,则表示使用外边的全局变量abc,输出900

//若带上var,则表示在test()函数里边定义了新的局部变量abc,输出89

var abc=900;

}

test();

window.alert(abc);

◆访问对象的属性的方法有两种:

1.普通方式

对象名.属性名

2.动态访问,这里的属性名是字符串,可以拼接,达到动态访问的目的

对象名["属性名"]

例如:

function Person(){};

var p1=new Person();

p1.name="creabine";

window.alert(p1.name);

window.alert(p1["name"]);

var val="na"+"me";//拼接

window.alert(p1[val]);//拼接之后也能访问

对象引用问题说明:(图)



js还提供一种方式,主动释放对象内存

delete 对象名.属性名;//这样就会立即释放 对象的这个属性空间

案例:

function Person(){};

var a=new Person();

a.age=10;

a.name="小明";

var b=a;

b.name="小白";

window.alert(b.age+"名字"+b.name+"名字"+a.name);

//这里输出 10名字小白名字小白 因为:a和b都只是Persoon()的地址而已,两个变量都是它的地址,访问的都是同一个它,所以b.name="小白";修改之后,用a和b访问,得到的都是小白。

delete a.age;//删除a对象的age属性

window.alert(a.age+"名字a"+a.name);//删除之后age变成undefined

b=null;//将b置 空

window.alert(a.age+"名字a"+a.name);//a还能继续访问

window.alert(b.age+"名字b"+b.name);//b就不行了,不显示任何东西

◆this

问题的提出:

function Person(){

}

var p1=new Person();

p1.name="顺平";

p1.age=60;

window.alert(p1.name+""+p1.age);

var p2=new Person();

window.alert(p2.name);//这里会输出什么(undefined)

//这里我们可以看到window.alert(p2.name);输出的是undefined

实际编程中,可能有这样的需求,当我们创建一个对象之后,就希望该对象自动拥有某些属性,比如上边创造了Person对象后,就希望该对象自动拥有name和age属性,这又怎么办?

使用this来解决:

案例:

//this的使用

function Person(){

this.name="abc";

this.age=90;//这里用this,相当于把name这个属性变成了全局变量,如果直接var name的话,就是这个函数里边的局部变量,这样下边的访问就访问不到,会undefined。

}//这样以后建立的实例都自动拥有name和age属性并且自动赋值。

var p1=new Person();

var p2=new Person();//这里的p1,p2是两个不同的实例,存在不同的地址,修改其中一个的属性不影响另一个,所以有下边的

window.alert(p1.name+""+p2.name);

p2.name="陈磊";

window.alert(p1.name+""+p2.name);

原理图:



可能有人会这样想问题:

function Person(){

var name="abc";//私有的,只能在内部使用

var age=900; //私有的,只能在内部使用

this.show=function(){ //如果你一定要访问私有属性,则需要定义一个公开方法(特权方法)

window.alert("name="+name+"age"+age);

}

}

var p1=new Person();

window.alert(p1.name+""+p1.age);//错误的,无法访问,因为那两个是局部变量,会显示undefined

p1.show();//定义公开方法后,这样就可以访问了。



注意:谁调用函数,函数里的this就是谁。
案例1:

/*

function Person(){

this.name="abc1";

this.age=900;

}

function show1(){

window.alert("hello"+this.name);

}

var p1=new Person();

p1.abc=show1;

show1();//这里并不是p1调用函数,没指定是谁调用跟,就默认window,所以这里函数里边的this是window的this,所以只会输出hello,后边的this.name没东西,什么都不输出

*/

//2

function Person(){

this.name="abc1";

this.age=900;

}

var name="北京";

function show1(){

window.alert("hello"+this.name);

}

var p1=new Person();

p1.abc=show1;

show1();//这里同样也是直接调用函数,没指定是谁调用跟,就默认window,所以this是window的this,但是这次有定义name,故而输出hello北京

案例2:

function Person(){

this.abc=function(){

window.alert(this.v);

}

}

var p=new Person();//p指到Person的地址,

p.v="hello";//给他加了个属性v

p.abc();//p调用了这个函数,P就是this,this.v就是p.v,就是hello

注意事项:this不能放在类的外部使用,否则调用者就变成了window

◆对象-----成员函数(方法)

比如:我们希望对象不但有属性,还希望他有行为(行为在程序中要靠函数来实现)

1.添加speak函数,输出 我是一个好人

2.添加jisuan函数,可以计算从1+...+1000的结果

3.修改jisuan函数,该方法可以接收一个数n,计算从1+...+n的结果

4.添加add成员函数,可以计算两个数的和

代码:做了一部分

function Person(name,age){

//下边就是使用传入的实际参数,去初始化属性

this.name=name;

this.age=age;

//输出自己的名字,这里this.show就是一个公开的函数,函数名是show

this.show=function(){//方法一:这里就是给Person这个类定义了一个初始化的参数,这个参数就是一个函数,这样的话每创建一个Person的对象实例p1,p2,p3.....,他们各自都会有这样一个函数,来输出名字。

document.write("名字="+this.name);

}

//添加一个jisuan函数,可以计算从1+...+1000的结果

//修改,可以接受一个数n来计算和

this.jisuan=function(n){

var sum=0;

for(var i=1;i<=n;i++){

sum+=i;

}

return sum;

}

}

var p1=new Person("呵呵",90);

p1.show();

var p1=new Person("heihei",12);

p1.show();

document.write("<br/>res="+p1.jisuan(100));

◆除了上边的方法给一个对象添加函数还有另外两种种方式:

方法二:

function 类名(){

this.属性;

}

var 对象名=new 类名();

function 函数名(){

//执行

}

对象名.属性=函数名;//这样就相当于把函数赋给了这个 对象名.属性, 此时这个属性名就表示一个函数了

//调用时

对象名.属性名();

具体案例:

function Person(){

this.name="abc";

this.age=900;

}

function show1(){

window.alert("hello"+this.name);

}

//创建一个p1对象

var p1=new Person();

//把show1函数给p1.abc这个属性,这个属性就代表了这个函数了

p1.abc=show1;//这里的show1不带括号,就是把函数本身交给这个属性,如果这里写show1(),那就是把函数返回的值给abc

p1.abc();//调用这个函数

方法三:

对象名.属性名=function 函数名(参数列表){

//代码;

}

调用

对象名.属性名(实际参数)

具体案例:

function Person(){

this.name="ccc";

this.age=900;

}

var p1=new Person();

p1.abc=function show1(){//直接给对象的abc属性添加函数

window.alert("hello"+this.name);

}

p1.abc();

第四种:

前面的几种方法,有一个问题:那就是每个对象会独占函数代码,这样如果对象过多,则会影响效率,js设计者提供了另一个方法:原型(prototype)法,这样多个对象可以共享一个函数代码,节省空间,提高效率

代码解释:

function Person(name,age){

//下边就是使用传入的实际参数,去初始化属性

this.name=name;

this.age=age;

//输出自己的名字,这里this.show就是一个公开的函数,函数名是show

this.show=function(){//使用这种方法的话,每创建一个Person的对象实例p1,p2,p3.....,他们各自都会有这样一个函数,这些函数相互独立存在,在某些情况下,这样会浪费空间。

}

原理图






如果不需要他们相互独立,为了节省空间,可以这样:

function Dog(){

}

var dog1=new Dog();

//在这里,使用prototype[类] 去绑定一个shout。虽然定义的dog1在这句话之前,但定以后dog1也可以访问类里边的shout
Dog.prototype.shout=function(){
window.alert("小狗");
}
dog1.shout();

var dog2=new Dog();

dog2.shout();//此时,这个shout属性被放在了Dog() 这个类里边,由Dog创建的实例dog1,dog2并不会自己加上这个shout属性,但是都可以通过相应的dog1.shout和dog2.shout来访问类里边的shout属性,dog1.dog2共用同一个shout。

原理图:



◆补讲 == 号的作用

1.当 == 的两边都是字符串的时候,则比较内容是否相等

2.若 == 两边是数字,则比较数字的大小是否相等

3.若 == 两边是对象, 或是 对象函数,则比较地址知否相等。若地址相等,则说明用同一个空间。

Object类

Object类是所有js类的基类,提供了一种创建自动一对象的简单方式,不需要程序员再定义构造函数

例如:

/*

//创建Person实例

function Person(){

}

var p1=new Person();

p1.name="sp";

*/

//初步体验Object类:通过Object直接创建对象,方便很多

var p1=new Object();

p1.name="sp";

window.alert(p1.constructor);

小例子:

//我们可以给类添加方法

var i=new Number(10);//这句话其实就等价于 var i=10;

Number.prototype.add=function(a){//这里是给Number这个类增加了一个方法add,add是个函数,输入一个值a,会反回this+a

return this+a;

}

window.alert(i.add(10).add(30));//这里调用add的是i,所以this是i的this,所以返回10+a,即10+10,再+30,所以输出50

◆加深对于 类和对象 的认识

如何给类添加方法(如何给某类型的所有对象添加方法):

//请思考给js的Array对象扩展一个find(Val)方法,当一个Array对象调用该方法的时候,如果能找到val则返回其下标,否则返回-1(正常下标不可能是-1).(数据手册里边已经有了各种该方法,但是如果我们需要,可以自定义一个。)

代码:

//体验一下Array

var arr1=new Array(3);

arr1[0]="a";

arr1[1]="b";

arr1[2]="c";

//遍历该数组

for(i=0;i<arr1.length;i++){

document.write(arr1[i]+" ");

}

document.write("<br/>");

//使用Array提供的方法,颠倒数据

arr1.reverse();

for(i=0;i<arr1.length;i++){

document.write(arr1[i]+" ");

}

//现在我们一起看看如何给所有Array对象添加一个方法find(Val)

Array.prototype.find=function(val){

//遍历数组this

for(var i=0;i<this.length;i++){

if(val==this[i]){

return i;

}

}

return "找不到"//这里我还是没用上边要求的-1,返回了 找不到。

}

document.write("下标="+arr1.find("a"));

◆闭包

这个知识点我们讲封装的时候再说。

◆成员函数的细节:(这里有几个小练习没有做,第33讲43:33前后)

1.成员函数的参数可以是多个

function 函数名(参数1,2,3.....){

}

2.函数可以没有返回值,但是最多只能有一个返回值。

3.js中,函数里边的变量可以是动态的,所以不通过变量的个数来区分函数,只看函数名,当定义同名的函数的时候,后定义的会覆盖先定义的,故只认最后定义的那个。

例如:

function test(a){

window.alert(a);

}

function test(a,b){

window.alert(a+""+b);

}

//js的函数里边的变量可以是动态的,所以不通过变量的个数来区分函数,只看函数名,当定义同名的函数的时候,后定义的会覆盖先定义的,所以不论定义了多少次这里的test只认最后一个,

//test(23);//故而,这里会输出 23undefined。

window.test(3,"hello");//这里的test(23);没写是谁调用,所以默认就是window调用,所以test(23);和window.test(23);是等价的

面向对象变成的综合案例:代码很多,好好看看

采用面向对象的思想设计超级马里奥游戏人物(示意图)



游戏的分析:

1.如何通过按钮来控制图片马里奥的位置

2.设计相关的对象(马里奥x,y)

基本代码写好了,在mario文件里边

未完成的要求1.mario遇到边界给一个提示,功能未完成,应该不难

2.再放一个公主的图片,让mario去抓公主,抓到公主则弹窗哈哈抓到了

1)我一开始自己做了判定是否在同一点

2)改为判定碰撞

3.还能在基础上再加个要求,让mario可以通过键盘的上下左右键来控制。

问题:怎么直接获取css的内容?

答:

//这里仅作测试:如何调用div的各种属性

function test(){

//window.alert("test");

var div2=document.getElementById("div2");

//取出width

window.alert(div2.style.width);//如果div通过style来写各种属性,那么就可以这样调用。但是,如果用css就不行(据说某些浏览器可以)

}

div2代码:

<br/>

<div id="div2" style="width:500px;">div2</div>

<br/>

◆构造函数

基本用法:

function 类名(参数列表){

属性=参数值;

.........

}

举例:

function Person(name,age){

this.name=name;//给了初始化的值,name和age

this.age=age;

}

//创建Person对象的时候,就会直接给名字和年龄

var p1=new Person("abc",80);

window.alert(p1.name+p1.age);

var p2=new Person("ccc",9);

window.alert(p2.name+p2.age);

特别说明:在初始化一个对象实例的时候,也可以给他初始化一个函数,让他的一个属性是个函数

案例:

function jisuan(num1,num2,oper){

if(oper=="+"){

return num1+num2;

}else if(oper=="-"){

return num1-num2;

}else if(oper=="*"){

return num1*num2;

}else{

return num1/num2;

}

}

//创建Person对象的时候,就会直接给名字和年龄和函数

function Person(name,age,fun){

this.name=name;//给了初始化的值,name和age和fun

this.age=age;

this.myfun=fun;

}

//创建Person对象的时候,就会直接给名字和年龄和函数

var p1=new Person("abc",80,jisuan);

window.alert(p1.name+p1.age);

window.alert(p1.myfun(5,6,"+"));//可以直接用这个属性所带的函数

var p2=new Person("hehe",5);//p2实例也可以选择的不传入函数,直接不写,或者写null均可

◆创建对象的又一种形式:

如果一个对象比较简单,我们可以直接创建对象,不要类了,同时还可以给它指定普通属性和函数属性:

案例:

//比较简单的对象可以直接创建对象实例而不要类

var dog={name:"Tom",age:8};

window.alert(dog.constructor);//可以看到他是有构造函数的

window.alert(dog.name+dog.age);//也可以正常调用

扩展:这样也可以加函数

案例:

//甚至也可以给函数,例如

var cat={

name:"Sam",

age:4,

fun1:function(){window.alert("i m cat")},

fun2:function(){window.alert("i m 3")}

};

window.alert(cat.name+cat.age);

cat.fun1();

cat.fun2();

有时,我们会看到这样一种调用方法:

函数名.call(对象实例);//这样调用,就是叫来这个对象实例,来调用该函数,该函数的this就是这个对象实例

案例:

//

var dog={name:"hello"};

function test(){

window.alert(this.name);

}

test();

window.test();

test.call(dog);//表示叫来dog对象,来调用这个test函数,这样test的this就是dog了,this.name就是dog.name了

//dog.test();//但是这里用dog.test();什么都没有,为什么???

//因为,dog.test();是在调用dog的私有函数,写在dog的定义里才行,而这里的test是全局函数,无法这样调用。详见文件object.html的第110行,this的使用案例。

◆js面向对象编程的三大特性

1.封装

js提供有以下几种控制方法和属性的访问权限:

1)公开级别:对外公开

2)私有级别:类本身可以访问,不对外公开

案例:

//封装属性 和 方法

function Person(name,agei,sal){

this.name=name;//公开的属性

var age=agei;//私有属性

var salary=sal;//私有属性

//在类中如何定义公开方法(特权方法),私有方法(内部方法)

//若我们希望操作上边的私有属性,则可以通过公开方法实现

this.show=function(){//公开方法

window.alert(age+" "+salary);

}

//私有方法,类本身可以访问对象的属性,但无法在外边使用,被封装了

function show2(){

window.alert(age+" "+salary);

}

}

var p1=new Person("sp",20,50000);

window.alert(p1.name+" "+p1.age);//这里访问公开的name就可以,访问私有的age就会失败。

p1.show();//通过公开方法来访问私有属性

p2.show2();//无法在类的外部使用私有方法。被封装了

强调:我们前面学习过,通过prototype给所有的对象添加方法,但是这种方式,不能访问类的私有属性和方法。

举例:

function Person(){

this.name="abc";

var age=90;

//公开方法

this.abc=function(){

window.alert("abc()");

}

//私有方法

function abc2(){

window.alert("abc2()");

}

}

//使用prototype

Person.prototype.fun1=function(){

window.alert(this.name);//name是公开属性,能够显示

//window.alert(age);//age是私有属性,无法显示

this.abc();//这里的函数abc();是公开的,可以调用

//abc2();//这里无法调用abc2();因为他是私有方法

}

var p1=new Person();

p1.fun1();

2.继承

1)为什么需要继承?

问题:

/*

//继承例子

function MdiStu(name,age){

this.name=name;

this.age=age;

this.show=function(){

window.alert(this.name+" "+this.age);

}

//计算学费

this.payFee=function(money){

window.alert("应缴"+money*0.8);

}

}

function Pupil(name,age){

this.name=name;

this.age=age;

this.show=function(){

window.alert(this.name+" "+this.age);

}

//计算学费

this.payFee=function(money){

window.alert("应缴"+money*0.5);

}

}

*/

上面的代码存在冗余的问题。

可以用继承(js是通过对象冒充来实现继承效果的)来解决这个问题:

//怎么解决上边代码冗余问题? 用继承

//抽象出一个学生类(即把上边的中学生,小学生的共性取出)

function Stu(name,age){

this.name=name;

this.age=age;

this.show=function(){

window.alert(this.name+""+this.age);

}

}

function MidStu(name,age){

window.alert(Stu);//这里的Stu是个函数

this.stu=Stu;//这里相当于把Stu函数给了这个stu属性,所以这个属性拥有了这个函数所设定的那些name,age等属性。

this.stu(name,age);//stu属性经过上边那句,已经成了一个函数,相当于调用了这个函数,函数运行,就有了值;若不运行,函数里边的name,age也是空的,就没用了。这里的this.show并不会执行,因为没叫他执行。

/*

//MidStu可以覆盖Stu父类的show,这里覆盖了,所以最下边的midStu.show();会显示MidStu show();,若注销这里,不覆盖改,则会使用父类的函数,下边就会输出"顺平",20

this.show=function(){

window.alert("MidStu show();");

}

*/

}

function Pupil(name,age){

this.stu=Stu;

this.stu(name,age);//js中实际上是通过对象冒充,来实现继承的,这句话不能少,就是通过它实现了继承

}

var midStu=new MidStu("顺平",20);

midStu.show();

特别说明:js通过对象冒充的方式可以实现多重继承的效果。即可以继承好几个函数。

◆js的重载和重写: js不支持重载,但又天然支持重载

说js不支持重载(即不可以通过参数的个数来决定调用哪个一同名函数),是因为js函数的变量个数是可变的,区分js函数只看函数名而不看变量个数,所以无法拥有重名的函数,若重名只认最后一个;但是又因为js支持参数个数可变,参数类型可变,所以可以随时修改,所以说又是天然支持重载的。

如:

function abc(){

fi(argument.length==?){

}else if(argument.length==?){

}else{}

}

重写:子类可以重新写函数,来覆盖父类的某个方法。见上边的例子。

◆多态 js是动态语言,在执行过程中会动态的变化,所以可以说是天然支持多态

案例:

function Person(){

this.test1=function(){

window.alert("Person test1");

}

}

function Cat(){

this.test1=function(){

window.alert("Cat test1");

}

}

var v=new Person();

v.test1();

v=new Cat();//js是动态语言,值会随着赋值的变化而变化,你给v什么,他就是什么

v.test1();

多态经典案例:主人给动物喂食

代码:

function Master(){

//主人刚给动物喂食

this.feed=function(animal,food){

document.write("主人给"+animal.name+"喂"+food.name);

}

}

//写食物类

function Food(name){

this.name=name;

//...其他

}

function Fish(name){

this.food=Food;

this.food(name);

}

function Bone(name){

this.food=Food;

this.food(name);

}

//写动物类

function Animal(name){

this.name=name;

//....其他

}

function Cat(name){

this.animal=Animal

this.animal(name);

}

function Dog(name){

this.animal=Animal

this.animal(name);

}

//

var cat=new Cat("小猫咪");

var dog=new Dog("小狗");

var fish=new Fish("小鱼");

var bone=new Bone("小骨头");

var master=new Master();

master.feed(cat,fish);

master.feed(dog,bone);

master.feed(cat,bone);

◆补充讲解闭包:

解释:

1.闭包和gc(垃圾回收)是相关联的

2.闭包实际上是涉及一个对象的属性何时被gc处理回收的问题

3.怎样才能对对象的属性形成闭包:当一个类里边有个变量,被外部引用的时候,这个变量的储存空间就不会被马上回收,而是留着,以防外部再度引用

案例:

//闭包 closure

function A(){

var i=0;

function b(){

window.alert(i++);

}

return b;

}

//闭包<---->gc

//A();//这里如果直接这样调用A函数,此时内存会分配给i一个空间,当你执行完函数之后,因为没有其他变量指向i,所以gc会回收i的空间

var c=A();//但是如果这样调用,把调用A函数之后的结果赋值给c,运行结束之后,因为还有c指向函数,所以gc认为以后还可能会用到,就不去收回i的空间,i的值就还在

c();//输出0,但是执行之后i变成了1

window.alert("aa");

//..之后可能还有其他执行语句

//..

c();//不论执行了什么,这里还能输出1,说明执行过后的i依然存在,值是1

c();//输出2,i依然存在,没被回收,被闭包了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: