最近一直有小伙伴跟我说JS
有不少知识点常常不用,已经忘记的差很少了。平时找一个小问题都要在网上找半天,但愿能有一套比较全面的笔记或者文章。可是网上的文章太过于分散,学习起来不是很方便。恰巧最近比较闲,因此为你们整理出来了一套比较全面的JS
基础阶段的文章,对于初学者仍是颇有帮助的,若是你是一名熟练掌握JS
的攻城狮,你可能会以为文章写得太过于啰嗦,可是为了照顾你们,啰嗦一点仍是有必要的。javascript
这篇文章主要讲的是关于JS
基础的知识点,后面会陆续更新DOM
、JS高阶
、Ajax
、H5C3
、JQ
,包括一些主流的框架,可是本人时间有限,不可能专门去花费时间来写,并且工做量也是很是大的,因此喜欢的小伙伴能够点一波关注,后续会陆续更新。css
因为是本身所写,因此里面有些语言可能表达的有些不明确,不明白的能够给我留言。html
javascript是一种运行在客户端
的脚本语言
客户端: 即接受服务的一端
,与服务端相对应,在前端开发中,一般客户端指的就是浏览器
。前端
脚本语言: 也叫解释型语言
,特色是执行一行
,解释一行
,若是发现报错,代码就中止执行。java
javascript的三个组成部分:ECMAScript
、BOM
、DOM
ECMAScript: 定义了javascript
的语法规范。程序员
BOM: 一套操做浏览器功能的API
。segmentfault
DOM: 一套操做页面元素的API
。数组
一、script标签的书写方式浏览器
书写Javascript
代码有两种方式,第一种是直接在script
标签中书写,第二种是将代码写在js
文件中,经过script
的src
属性进行引入。
直接在script
中书写javascript
代码:框架
<!-- type="text/javascript" 能够省略 --> <script type="text/javascript"> alert("今每天气真好呀"); </script>
经过script标签引入一个JS文件,须要指定src
属性:
<!-- 表示引用了test.js文件,而且script标签内不能够继续写代码 --> <script src="test.js"></script>
若是script
标签指定了src
属性,说明是想要引入一个js
文件,这个时候不能继续在script
标签中写js
代码,即使写了,也不会执行。
二、script标签的书写位置
script
标签的书写位置,原则上来讲,能够在页面中的任意位置书写。
写在head
标签中,style
标签以后:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="demo.css"> <!-- 写在这里 --> <script src="demo.js"></script> </head> <body> </body> </html>
浏览器有一个特性,就是在遇到<body>
标签时才开始呈现内容。若是在head
里面引用js
文件的话,意味着必需要等到所有的javascript
代码都被下载、解析和执行完成以后,才能开始呈现页面的内容。若是文件数量一旦过多,将会影响页面加载速度,此时页面有可能会在加载完成前一片空白。
写在</body>
标签的前面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="demo.css"> </head> <body> <!-- 写在这里 --> <script src="demo.js"></script> </body> </html>
在解析javascript
代码以前,页面的内容已经彻底呈如今浏览器当中了,用户会明显感受页面加载变快了。
console.log
控制台输出日志console.dir
对象的形式打印一个对象document.write
往页面中写入内容alert
弹框警告confirm
确认框prompt
输入框不被程序执行的代码。用于程序员标记代码,在后期的修改,以及他人的学习时有所帮助,在JS中,分为单行注释
和多行注释
以及文档注释
。
单行注释
//这是单行注释,只能注释一行
多行注释
/* 这是多行注释,不能嵌套 */
文档注释
/** * 求圆的面积 * @param r {number} 圆的半径 * @returns {number} 圆的面积 * 这是文档注释 */ function getArea (r) { return Math.PI * r * r; }
注释的做用
变量,能够变化的量
,变量是在计算机中存储数据的一个标识符
。能够把变量当作存储数据的容器
。
变量与字面量:
10
、20
、“abc”
、true
这种从字面上就能看出来类型和值的量叫作字面量。// 1- 同时声明而且赋值 var num = 100; console.log(num); // 100 // 2- 先声明了一个变量,再赋值 var num1; num1 = 100; console.log(num1); // 100 // 3- 没有声明变量,直接赋值(能够,可是不推荐) num2 = 200; console.log(num2); // 200 // 4- 有变量声明,可是没有赋值(能够,没有赋值,变量的值默认是个undefined) var num9; console.log(num9); // undefined // 5- 既没有声明,也没有赋值,直接用。 console.log(num3); //报错 num3 // 6- 一个 var,逗号分隔 能够同时声明多个变量 var name = "Levi丶", age = 18, gender = "男";
命名规则(必须遵照):
$
符号组成,开头不能是数字。命名规范(建议遵照):
方法一: 声明一个新的变量
// 交换 num1 和 num2的值 var num1 = 11; var num2 = 22; var temp; temp = num1; // num1=11 temp=11 num1 = num2; // num1=22 num2=22 num2 = temp; // temp=11 num2=11
方法二: 不经过声明变量的方式
// 不使用临时变量 var num1 = 11; var num2 = 22; // num1 = 11 + 22 num1 = num1 + num2; // num1=33 // num2 = 33 - 22 num2 = num1 - num2; // num2=11 // num1 = 33 - 11 num1 = num1 - num2; // num1=22
基本数据类型包括了:number
、string
、boolean
、undefined
、null
使用
typeof
关键字查看数据类型
typeof(name); // 括号能够省略 typeof name;
进制
0
和1
0
开头的数值,数值序列:0-7
0x
开头的数值,数值序列:0-9
、A-F
、a-f
浮点数
所谓浮点数,就是该数当中必须包含一个小数点,而且小数点后面至少有一位数字。
科学计数法:
//如何表示0.003和20000? var num = 3e-3; // 0.003 var num2 = 2e+4; // 20000
浮点数的精度问题:
0.1 + 0.2 = ? // 0.30000000000000004 0.07 * 100 = ? // 7.000000000000001
浮点数在运算的时候会出现精度丢失的问题,所以在作比较运算的时候,尽可能不要用小数进行比较。在第五章的时候会着重讲解这个问题
数值范围
javascript
不能表示世界上全部的数,所以在javascript
中,数值大小是有必定限制的。
Number.MIN_VALUE
:5e-324 (js
里面能表示最小的数)Number.MAX_VALUE
:1.7976931348623157e+308 (js
里面能表示最大的数)Infinity
:正无穷 (若是超出js
里面最大的数,将会显示infinity
)-Infinity
:负无穷 (若是超出js
里面最小的数,将会显示-infinity
)数值判断
NaN
: 表示一个非数值
,当没法运算或者运算错误的时候,会获得一个NaN
,NaN
是number类型
,表示一个非数值。NaN
与任何值都不想等,包括它自己isNaN
: 用来判断是不是一个数字,当返回true
的时候说明是NaN
,表示的不是一个数字,返回false
,说明不是NaN
,表示的是一个数字。示例代码:
var str = "abc"; console.log(isNaN(str)); // true 说明不是一个数字
字面量
字符串的字面量:“abc”
、‘abc’
字符串能够是双引号,也能够是单引号引发来。
无论是双引号,仍是单引号,都是成对出现的,假如打印的字符串里有引号怎么办呢?
这里就要活学活用,若是只有一处有引号,就能够用单双引号混合使用:
console.log('我是"帅哥"'); // ==> 我是"帅哥"
假如引号很是多的时候怎么办呢? 用转义字符:“\”
:
console.log("我是'帅哥',\"哈哈哈\""); // ==> 我是'帅哥',"哈哈哈"
字符串拼接
拼接字符串使用
+
号
示例代码:
console.log(11 + 11); // 22 console.log("hello" + " world"); // "hello world" console.log("100" + "100"); // "100100" console.log("11" + 11); // "1111"
总结:
+
就是字符串拼接功能字符串长度
length
属性用来获取字符串的长度
var str = "abcdefghij"; str.length;// 字符串的长度 10
boolean
类型只有两个字面量,true
和false
,区分大小写(True,False不是布尔类型,只是标识符)。
全部类型的值均可以转化成true
或者false
NaN
、""
、undefined
、null
、alse
、0
这6
个值能够转换成false
,其他的都是true
。
undefined
表示一个声明了没有赋值的变量
var name ; console.log(name); // undefined
null
表示一个空的对象
var name = null; console.log(typeof name); // Object
若是定义的变量,未来是准备用于保存对象的话,最好将变量初始化为null
var name = null;
undefined
与 null
的关系
undefined == null; // true undefined === null; // false
实际上,undefiner
值是派生自null
值的,因此判断相等时为true
,可是两种用途是彻底不同的。
如何使用谷歌浏览器,快速的查看数据类型?
黑色
的蓝色
的蓝色
的undefined
和null
是灰色
的这个在调试过程当中时很是有用的。
一、String()
函数转换
var num = 123; console.log(String(num)); // "123"
二、toString()
转换不了undefined
和 null
var num = 123; console.log(num.toString()); // "123" console.log(undefined.toString()); // 报错 console.log(null.toString()); // 报错
三、+ ""
加引号
var num = 123; console.log(num + ""); // "123"
一、Number
0
;NaN
;console.log(Number("-123")); // -123 console.log(Number("")); // 0 console.log(Number("123abc")); // NaN
二、parseInt
(取整)
NaN
;console.log(parseInt("123.123")); // 123 console.log(parseInt("123.123abc")); // 123 console.log(parseInt("abc123.123")); // NaN console.log(parseInt("")); // NaN console.log(parseInt("abc")); // NaN
三、parseFloat
(取数)
NaN
;console.log(parseFloat("123.123")); // 123.123 console.log(parseFloat("123.123abc")); // 123.123 console.log(parseFloat("abc123.123")); // NaN console.log(parseFloat("")); // NaN console.log(parseFloat("abc")); // NaN
四、参与运算==> "+
" or "-0
"
var str = "-123"; console.log(+str); // -123 console.log(str-0); // -123
布尔类型只有true
和false
,可是全部类型的值均可以转换成布尔类型
一、可以转换成false
的只有6
种:
""
0
NaN
undefined
null
false
其他的都是true
二、!
转换
var str = ""; // Boolean() 判断这个参数的布尔类型 console.log(Boolean(str)); // false console.log(!str); // true
js
在使用小数进行计算的时候,会出现精度丢失的问题。不要用来跟其余的小数作比较。
0.1 + 0.2 != 0.3 //true 0.30000000000000004 // 16位数 和 17位数相等 9999999999999999 == 10000000000000001 // true 9007199254740992 + 1 == 9007199254740992 // true
计算机的二进制实现和位数限制有些数没法有限表示。就像一些无理数不能有限表示,如 圆周率 3.1415926...
,1.3333...
等。JS
遵循 IEEE 754
规范,采用 双精度存储(double precision
) ,占用 64 bit
。如图
意义:
1
位用来表示符号位11
位用来表示指数52
位表示尾数浮点数,好比:
0.1 >> 0.0001 1001 1001 1001…(1001无限循环) 0.2 >> 0.0011 0011 0011 0011…(0011无限循环)
此时只能模仿十进制进行四舍五入了,可是二进制只有0
和1
两个,因而变为0
舍1
入。这便是计算机中部分浮点数运算时出现偏差,丢失精度的根本缘由。
大整数的精度丢失和浮点数本质上是同样的,尾数位最大是 52
位,所以 JS
中能精准表示的最大整数是 Math.pow(2, 53)
,十进制即 9007199254740992
。
大于 9007199254740992
的可能会丢失精度:
9007199254740992 >> 10000000000000...000 // 共计 53 个 0 9007199254740992 + 1 >> 10000000000000...001 // 中间 52 个 0 9007199254740992 + 2 >> 10000000000000...010 // 中间 51 个 0
实际上:
9007199254740992 + 1 // 丢失 9007199254740992 + 2 // 未丢失 9007199254740992 + 3 // 丢失 9007199254740992 + 4 // 未丢失
结果如图:
以上,能够知道看似有穷的数字,在计算机的二进制表示里倒是无穷的,因为存储位数限制所以存在“舍去”,精度丢失就发生了。
对于整数,前端出现问题的概率可能比较低,毕竟不多有业务须要须要用到超大整数,只要运算结果不超过 Math.pow(2, 53)
就不会丢失精度。
对于小数,前端出现问题的概率仍是不少的,尤为在一些电商网站涉及到金额等数据。解决方式:把小数放到位整数(乘倍数),再缩小回原来倍数(除倍数)
// 0.1 + 0.2 (0.1*10 + 0.2*10) / 10 == 0.3 // true
一元
运算符有1个
操做数。例如,递增运算符"++"
,或者递减运算符"--"
就是一元运算符。二元
运算符有2个
操做数。例如,除法运算符"/"
有2
个操做数。三元
运算符有3个
操做数。例如,条件运算符"?:"
具备3
个操做数。递增"++"
和 递减"--"
还分为前自增
或后自增
,前自减
或后自减
,两种自增自减的运算结果是不同的;
++num
前自增 --num
前自减 先+1
或-1
,再返回值num++
后自增 num--
后自减 先返回值,再+1
或-1
举个例子,看代码:
var num = 5; console.log(num++); // 5 console.log(++num); // 7 (由于刚刚num自增了一次,这里打印的话就等于在6的基础上前自增了,在计算机科学中,被称为副效应) console.log(num--); // 7 (这里是后自减,因此先返回值,返回7,再运算--,此时的num实际是等于6了) console.log(--num); // 5
&&
(与运算):只要有一个值为假
,结果就是假
。找假
值 找到假值就返回,若是都是真
,返回最后一个||
(或运算):只要有一个值为真
,结果就是真
。找真
值 找到真值就返回,若是都是假
,返回最后一个!
(非运算):取反示例代码:
/*细读上面三句话,就能理解为何会是这个打印结果了*/ console.log(true && true); //true console.log(false || false); //false console.log(null && undefined); //null console.log(null || undefined); //undefined console.log("abc" && undefined); //undefined console.log("abc" || undefined); //abc console.log(null || false || 0 || 1 || null); //1 console.log("abc" && "bcd" && "def"); //def
()
优先级最高++
--
!
*
/
%
后 +
-
>
>=
<
<=
==
!=
===
!==
&&
后||
示例代码:
// 第一题 true && true console.log(((4 >= 6) || ("人" != "狗")) && !(((12 * 2) == 144) && true)); // true // 第二题 var num = 10; // true && true if(5 == num / 2 && (2 + 2 * num).toString() === "22") { console.log(true); // true }else{ console.log(false); }
语法:
只有一个判断条件的时候 if..else
:
if(判断条件){ // 当判断条件为true的时候执行代码1,为false的时候执行代码2 代码1; }else{ 代码2; }
当不止一个判断条件的时候 else
用else if
代替:
if(判断条件1){ // 判断条件 1 为 true 的时候执行 代码 1 代码1; }else if(判断条件2){ // 判断条件 2 为 true 的时候执行 代码 2 代码2; }else{ // 两个条件都不知足的时候执行代码 3 代码3; }
思考1:
18
,告诉他能够看电影16
,告诉他能够在家长的陪同下观看16
,告诉他不许看var age = 20; if(age >= 18){ console.log("没时间解释了,赶忙上车吧"); // 打印这条 }else if(age >= 16){ console.log("请在家长的陪同下观看"); }else { console.log("回家学习吧"); }
思考2:
new Date().getDay()
获取今天是星期几var date = new Date(); // 获取当前的时间 var week = date.getDay(); // 得到 0-6 表示周几 0:星期日 if(week == 0){ console.log("今天是星期天"); }else if(week == 1){ console.log("今天是星期一"); }else if(week == 2){ console.log("今天是星期二"); }else if(week == 3){ console.log("今天是星期三"); }else if(week == 4){ console.log("今天是星期四"); }else if(week == 5){ console.log("今天是星期五"); }else if(week == 6){ console.log("今天是星期六"); }else{ console.log("你火星的来的吧"); }
语法:
// switch: 开关; case: 案列; switch(变量){ // 判断变量是否全等于case的值1,或者值2, case 值1: 执行代码1; // 全等于的时候执行代码1 break; // 而后break;代码跳出switch语句, 不加break,会继续执行下面的代码 case 值2: 执行代码2; break; default: 执行代码3; // 当都不知足条件的时候,会执行默认里的执行代码3 }
思考:素质教育(把分数变成ABCDE)
// 90-100 : A // 80-89: B // 70-79: C // 60-69: D // 0-59 : E // 这里的等级是根据一个范围的分数划定的,用if..else很容易实现,可是switch..case是一个具体的条件,怎么办呢? // 方法:将分数除以10再用parseInt属性取整 var score = 85; score = parseInt(score/10); // 8 switch (score) { // score = 10 或者 9 的时候 返回 A case 10: case 9: console.log("A"); break; // score = 8 的时候 返回 B case 8: console.log("B"); break; case 7: console.log("C"); break; case 6: console.log("D"); break; default: console.log("E"); }
这个运算符能够用来代替if..else
条件判断。可是为何有这个运算符呢?这里的缘由是if..else
使用两个代码块,却只有一个会执行,在讲究的程序员看来是一种浪费。因此使用三元运算符,用一条语句就能够完成功能。
语法:
判断语句?表达式1:表达式2; 根据判断语句返回的布尔值,true的话,返回表达式1,false的话返回表达式2
举个例子,看代码:
var sex = 1; sex == 1 ? "男":"女"; // 判断sex是否等于1,若是true,返回第一个表达式:"男"
例题:判断两个数的大小
// 用if..else语句解决 // 这里使用了两个代码块,有点浪费 var num1 = 18; var num2 = 39; var max; if(num1>num2){ max = num1; }else{ max = num2; } console.log(max); // 用三元运算符 var num3 = 28; var num4 = 49; var max1 = num3>num4? num3:num4; console.log(max1);
注意(容易出错的地方):
下面这个语句判断若是是会员,费用为2
美圆,非会员,为10
美圆。如今设置了非会员,却打印出了2
美圆,显然出错了。
var isMember = false; console.log("当前费用" + isMember ? "$2.00" : "$10.00"); // "$2.00"
出错的缘由是?
号的优先级比+
号低,因此实际运行的语句是
// true console.log("当前费用false" ? "$2.00" : "$10.00"); // "$2.00"
语法:
true
的时候,就会执行循环体false
的时候,结束循环。// 1. 若是循环条件的结果是true的时候,就会执行循环体 // 2. 若是循环条件的结果是false的时候,结束循环。 while(循环条件){ 循环的代码; // 循环体 自增或者自减; // 必定不要忘记自增或自减,不然就会死循环 }
例如,求0~100的和:
var num = 0; var sum = 0; while(num <= 100){ sum += num; num++; } console.log(sum); // 5050
语法:
do..while
循环和while
循环很是像,两者常常能够相互替代do..while
的特色是无论条件成不成立,都会执行1
次。do{ 循环的代码; // 循环体 自增或者自减; // 必定不要忘记自增或自减,不然就会死循环 }while(循环条件);
例如,求0~100的和:
var num = 0; var sum = 0; do{ sum += num; num++; }while(num<=100); console.log(sum); // 5050
写while
循环的常常会忘记自增,for
循环实际上是while
循环演化过来的,语法更加的简洁明了,使用很是的普遍。
语法:
//主要for循环的表达式之间用的是;号分隔的,千万不要写成,号 for(初始化表达式;判断表达式;自增表达式){ //循环体 }
例如:求0~100的和:
var sum = 0; for(var num = 0; num <= 100; num++){ sum += num; } console.log(sum); // 5050
break
:当即跳出整个循环,即循环结束,开始执行循环后面的内容(直接跳到大括号)
continue
:当即跳出当前循环,继续下一次循环(跳到i++
的地方)
一、continue 示例代码:
for(var i = 1; i <= 10; i++) { if(i == 5) { continue; } console.log(i); // 1,2,3,4,6,7,8,9,10 }
二、break 示例代码:
for(var i = 1; i <= 10; i++) { if(i == 5) { break; } console.log(i); // 1,2,3,4 }
一、计算一个数的位数
当不知道循环次数的时候,用while
循环:
var num = 1234567; //由于不知道循环次数,因此推荐使用while循环 var count = 0; // count记录位数 while(num != 0){ // 循环条件 num = parseInt(num/10);// 让num缩小10倍 count++; // ,每缩小10倍就计算一次位数了 } console.log(count); // 7
二、翻转一个数
var num = 12345678; //由于不知道循环次数,因此推荐使用while循环 var str = ""; while(num != 0){ str += num%10; // 将每一位取余 num = parseInt(num/10);//让num缩小10倍 } // str 是一个字符串,因此 +str将它转回Number类型 console.log(+str); //
三、总结:
for
循环用while
循环do..while
循环。所谓数组,就是将多个元素(一般是同一类型的),按必定顺序排列放到一个集合中,那么这个集合就称之为数组
在javascript
中,数组是一个有序
的列表,能够在数组中存放任意
的数据,而且数组的长度能够动态
的调整
一、经过构造函数建立数组:
var arr = new Array();
建立了一个空数组;var arr = new Array('aa','bb','cc');
建立了一个数组,里面存放了三个字符串var arr = new Array(11,22,33)
建立了一个数组,里面存放了三个数字二、经过数组子面量建立数组:
var arr = [];
建立了一个空数组var arr = [11,22,33];
建立了一个数组,里面存放了三个数字var arr = ['aa','bb','cc'];
建立了一个数组,里面存放了三个字符串数组的下标:
数组是有序的,数组中的每个元素都对应了一个下标,下标是从
0
开始的
var arr = ['aa','bb','cc']; arr[0]; // 下标是0,对应的值是'aa' arr[2]; // 下标是2,对应的值是'cc'
数组的长度:
跟字符串同样,数组也有一个length
的属性,指数组中存放的元素的个数
var arr = ['aa','bb','cc']; arr.length; // 数组的长度为3
空数组的长度为0
数组的长度与下标的关系:
数组的最大下标
= 数组的长度
- 1
数组的取值:
数组名[下标]
undefined
var arr = ['red','blue','green']; arr[0]; // red arr[2]; // green arr[3]; // 返回undefined,由于数组最大的下标为2
数组的赋值:
数组名[下标] = 值;
3
,但是却给数组下标为5
赋了一个值,则下标为三、4
的值为empty
(空)var arr = ["red", "green", "blue"]; arr[0] = "yellow"; // 把red替换成了yellow arr[3] = "pink"; // 给数组新增长了一个pink的值 arr[5] = "black"; // 数组输出为["red", "green", "blue",empty,empty,"black"]
遍历: 对数组的每个元素都访问一次,叫作遍历
数组遍历的基本语法:
var arr = [1,2,3,4,5,6,7,8,9]; for(var i = 0; i < arr.length; i++){ console.log(arr[i]); // 1 2 3 4 5 6 7 8 9 }
数组遍历的逆向遍历语法:
// i= arr.length-1 ==> 表示初始化表达式 从数组最后一位开始遍历 // i>=0 表示判断条件,下标要知足大于等于0 // i--,表示每次遍历 初始值都是自减的 var arr = [1,2,3,4,5,6,7,8,9]; for(var i = arr.length-1; i >= 0; i--){ console.log(arr[i]); // 9 8 7 6 5 4 3 2 1 }
一、求一个数组中的最大值、最小值以及对应的下标
var arr = [298, 1, 3, 4, 6, 2, 23, -88,77,44]; var max = arr[0]; // 随机取数组中的一个值与其余值比较 var maxIndex = 0; // 初始化最大值的下标 var min = arr[0]; var minIndex = 0; for(var i = 0; i< arr.length; i++){ if(max < arr[i]){ // 用一开始选择的值,与遍历后的值进行比较 max = arr[i]; // 当后面的值比初始值大,就将后面的这个值赋值给初始值,再用这个全新的值再v 去与后面的比较 maxIndex = i; // 比较结束后,此时的索引就是最大值的索引 } if(min > arr[i]){ min = arr[i]; minIndex = i; } } console.log("最大的值是:" + max); console.log("最大值的下标是:" + maxIndex); console.log("最小的值是:" + min); console.log("最小值的下标是:" + minIndex);
二、让数组倒序保存到一个新的数组中
须要了解数组的一个方法 push
,在数组的最后面
添加
var arr = ["大乔", "小乔", "甄姬", "不知火舞"]; var newArr = []; for (var i = arr.length - 1; i >= 0; i--) { newArr.push(arr[i]); } console.log(newArr); // ["不知火舞", "甄姬", "小乔", "大乔"]
三、将字符串数组用"|"或其余符号拼成一个字符串
var arr = ["aa","bb","cc","dd"]; var str = ""; for(var i = 0; i<arr.length; i++){ if(i == arr.length-1){ str = str + arr[i]; // 判断一下,若是是最后一个的话就不用加“|” }else{ str = str + arr[i]+"|"; // str初始值是一个空字符串,遍历的时候须要加上前一次的结果 } }
四、数组去重
push
到新数组中;var arr = [1, 1, 5, 7, 8, 3, 2, 5, 7, 2, 4, 6, 2, 5, 7, 2, 5]; //定义一个新数组 var newArr = []; //遍历须要去重的数组 for (var i = 0; i < arr.length; i++) { //假设不存在 var flag = true; //须要判断arr[i]这个值是否在新数组中存在 for(var j = 0; j < newArr.length; j++){ //进行比较便可 if(arr[i] == newArr[j]){ //若是发现了相等的数,说明存在 flag = false; } } if(flag){ //若是假设成立,说明不存在 newArr.push(arr[i]); } } console.log(newArr);
一个有
8位
元素的数组,让它的第一位与后面每一位进行比较,前面一位小于后面的时候,位置不变,前面的大于后面的交换位置,就这样一共要比七趟(最后一趟不要比,就剩一位,就是最小的);
实现原理以下图:
一、冒泡排序 60分:
var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6]; var tang = 0; var ci = 0; for (var i = 0; i < arr.length - 1; i++) { // 外层for循环,循环的是比较的趟数,由于只要比较8趟 因此i判断的条件为length-1 tang++; for (var j = 0; j < arr.length - 1; j++) { // 内层for循环,循环的是比较的次数,每趟比较8次 ci++; if (arr[j] > arr[j + 1]) { // 判断比较的两个数,若是前面的大于后面的一位,交换位置 var temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } console.log("趟数:" + tang); // 8趟 console.log("次数:" + ci); // 64次 console.log(arr); }
for
循环,循环的是比较的趟数
,由于只要比较8
趟(数组长度为9
) 因此i
判断的条件为length-1
;for
循环,循环的是比较的次数
,每趟比较8
次,其实这里次数多比较了,由于第一趟已经找到一个最大值了,第二趟就不须要比8
次了 应该比7
次,这里先无论,下面会进行优化;测试代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <span id="demo"></span><br/> <button id="stb">从小到大</button> <button id="bts">从大到小</button> <span id="show"> </span> <script> var demo = document.getElementById("demo"); var show = document.getElementById("show"); var bts = document.getElementById("bts"); var stb = document.getElementById("stb"); var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6]; demo.innerHTML = arr; bts.onclick = function() { bubbleSort(function(a, b) { return b - a; }); } stb.onclick = function() { bubbleSort(function(a, b) { return a - b; }); } function bubbleSort(fn) { var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6]; var strArr = []; show.innerHTML = ""; strArr.push("<br/>"); var inner = 0; var outer = 0; for (var i = 0; i < arr.length - 1; i++) { strArr.push("第" + (i + 1) + "趟"); for (var j = 0; j < arr.length - 1; j++) { if (fn(arr[j], arr[j + 1]) > 0) { var tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; } inner++; } strArr.push(arr.toString()); strArr.push("共" + j + "次" + "<br/>"); outer++; } strArr.push("外循环" + outer + "次"); strArr.push("内循环" + inner + "次"); show.innerHTML = strArr.join(" "); } </script> </body> </html>
每趟都比较8次?明显是多余了,下面进行优化
二、冒泡排序80分:
var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6]; var tang = 0; var ci = 0; for (var i = 0; i < arr.length - 1; i++) { tang++; for (var j = 0; j < arr.length - 1 - i; j++) { // 第二趟只比了7次 依次递减 ci++; if (arr[j] > arr[j + 1]) { var temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } console.log("趟数:" + tang); // 8趟 console.log("次数:" + ci); // 36次 console.log(arr);
i
是从下标0
开始的,第一趟的时候i=0
,比了8
次,第二趟i=1
,只须要比7
次,第三趟i=2
,只须要比6
次...依次类推,因此 比的次数应该就是arr.length - 1 -i
;
测试代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <span id="demo"></span><br/> <button id="stb">从小到大</button> <button id="bts">从大到小</button> <span id="show"> </span> <script> var demo = document.getElementById("demo"); var show = document.getElementById("show"); var bts = document.getElementById("bts"); var stb = document.getElementById("stb"); var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6]; demo.innerHTML = arr; bts.onclick = function() { bubbleSort(function(a, b) { return b - a; }); } stb.onclick = function() { bubbleSort(function(a, b) { return a - b; }); } function bubbleSort(fn) { var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6]; var strArr = []; show.innerHTML = ""; strArr.push("<br/>"); var inner = 0; var outer = 0; for (var i = 0; i < arr.length - 1; i++) { strArr.push("第" + (i + 1) + "趟"); for (var j = 0; j < arr.length - 1 - i; j++) { if (fn(arr[j], arr[j + 1]) > 0) { var tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; } inner++; } strArr.push(arr.toString()); strArr.push("共" + j + "次" + "<br/>"); outer++; } strArr.push("外循环" + outer + "次"); strArr.push("内循环" + inner + "次"); show.innerHTML = strArr.join(" "); } </script> </body> </html>
还有什么能够优化的吗? 假如8
个数在第3
趟的时候就排好了,还须要继续排吗?
三、冒泡排序100分:
假设成立法(3步):
var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6]; var tang = 0; var ci = 0; for (var i = 0; i < arr.length - 1; i++) { var flag = true; // 假设每一次进来都排好了 tang++; for (var j = 0; j < arr.length - 1 - i; j++) { ci++; if (arr[j] > arr[j + 1]) { flag = false; // 若是两位比较还知足前面的比后面的大的时候,说明假设不成立 var temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } if (flag == true) { // 最后判断一下,若是假设推翻不了,就中止运行。 break; } } console.log("趟数:" + tang); // 4 趟 console.log("次数:" + ci); // 26 次 console.log(arr);
当顺序已经排好后,就不用再去执行趟数了;
测试代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <span id="demo"></span><br/> <button id="stb">从小到大</button> <button id="bts">从大到小</button> <span id="show"> </span> <script> var demo = document.getElementById("demo"); var show = document.getElementById("show"); var bts = document.getElementById("bts"); var stb = document.getElementById("stb"); var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6]; demo.innerHTML = arr; bts.onclick = function() { bubbleSort(function(a, b) { return b - a; }); } stb.onclick = function() { bubbleSort(function(a, b) { return a - b; }); } function bubbleSort(fn) { var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6]; var strArr = []; show.innerHTML = ""; strArr.push("<br/>"); var inner = 0; var outer = 0; for (var i = 0; i < arr.length - 1; i++) { var sorted = true; strArr.push("第" + (i + 1) + "趟"); for (var j = 0; j < arr.length - 1 - i; j++) { if (fn(arr[j], arr[j + 1]) > 0) { var tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; sorted = false; } inner++; } strArr.push(arr.toString()); strArr.push("共" + j + "次" + "<br/>"); outer++; if (sorted) { break; } } strArr.push("外循环" + outer + "次"); strArr.push("内循环" + inner + "次"); show.innerHTML = strArr.join(" "); } </script> </body> </html>
第三趟已经排好了,为何还要排第四趟呢? 缘由很简单,由于第三趟的时候js是不知道你已经排好的,只有第四趟的时候,js再进行换位比较的时候,发现位置都不须要换了,说明排好了。