js 笔记
javaScript的历史
java和javaScript的关系
JavaScript和Java是两种不一样的语言,但是它们之间存在联系。
JavaScript的基本语法和对象体系,是模仿Java而设计的。但是,JavaScript没有采用Java的静态类型,java需要编译器编译运行。
javaScript与ECMAScript的关系
ECMAScript 是一套语言标准,包含:
- javascript
- jscript
- actionscript
javaScript与ECMAScript的区别
ECMA是javascript的标准,javascript是ECMA的实现。
js代码引入
- 使用内嵌方式引入js代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 内联引用 -->
<script>
var name='张三';
</script>
</head>
- 外联方式引入代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 外联引用 -->
<script src="js/main.js"></script>
</head>
<body>
当script标签和link标签同时出现在head区域,那建议script标签写在link标签的后面,这样以保证样式优先加载,不会因为js代码执行阻塞页面渲染。
如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="css/style.css">
<script src="js/main.js"></script>
</head>
<body>
根据YUI
前端性能小组建议script
标签放置在</body>
的前面最佳。
如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- 外联的方式引用 -->
<script src="js/main.js"></script>
</body>
</html>
js注释
- 单行注释
//
<script>
//注释1
//注释2
//注释3
var name='张三';
</script>
- 多行注释
<script>
/*
注释1
注释2
注释3
*/
var name='张三';
</script>
优先考虑单行注释,因为多行注释有可能会造成语法错误。
语句和表达式
语句和表达式的区别
语句指一个为了得到返回值的计算式。语句和表达式的区别在于,前者主要为了进行某种操作,一般情况下不需要返回值;后者则是为了得到返回值,一定会返回一个值。
- js代码通常是以英文状态分号结束
;
- js代码会自动过滤字符之间空格、换行、缩进
- js代码严格区分大小写
变量
变量是对值的引用,变量就是为“值”起名,然后引用这个名字。
var sum = 1+3*10;
alert(sum);//警告框输出
document.write(sum);//文档输出
console.log(sum);//控制台输出,调试代码
变量命名规则
声明变量使用关键字var
,使用此关键字声明的变量没有作用域。
如果想要有作用域,可以使用es6
种的let
或const
这两个关键字。
声明一个变量,一次都没有给它赋值,那么它的值是未定义undefined
- 单个逐行声明
var a = 1;
var b = '您好';
var c = 20;
- 多个一次声明
var a = 1,
b = '您好',
c = 20;
-
var
变量会自动提升
console.log(a);//undefined
var a = 10;
// 以上代码变量会自动提升,相当于下面的代码
var a;
console.log(a);
a = 10;
仔细理解一下代码的区别
//会提升
console.log(a);
var a = 10;
//会报错,因为没有var关键字
console.log(a);
a = 10;
- 变量命名要求
语法
var 变量名 = 值;
变量名,以字母、下划线、`,变量字符之间不要存在空格。
变量命名不能使用(保留字)关键字 if、else、break、with等等
变量命名严格区分大小写
// 错误的命名
var 1a = 10;
var a 1= 20;
var %a = 30;
var a,3 = 20;
var var = 10;
var if = 20;
//正确的命名
var a1 = 20;
var A1 = 30;
var _abc = 10;
var $ab = 20;
var 姓名 = '张三';
- 变量命名风格
Camel Case
小驼峰式命名法
var fullName = '张亮';
Pascal Case
大驼峰式命名法
var FullName = '张亮';
常量命名,通常全部大写
//比如圆周率就是典型的常量
var PI = 3.14;
条件语句
if
条件语句
-
if
单条件语句
var age = 30;
if ( age >= 18) {
console.log( '您已经成年!' );
}
// 条件语句也可以使用下面的风格
var age = 30;
if ( age >= 18)
{
console.log( '您已经成年!' );
}
//简写,仅限条件语句中只有一条语句时成立。
var age = 30;
if ( age >= 18) console.log( '您已经成年!' );
-
if else
双条件语句
var age = 30;
if ( age >= 18 ) {
console.log( '您已经成年!' );
}else{
console.log( '未成年!' );
}
//简写,仅限条件语句中只有一条语句时成立,不推荐这样写。
var age = 12;
if ( age >= 18)
console.log( '您已经成年!' );
else
console.log( '未成年!' );
-
if else if else
多条件语句
&&
并且
||
或者
// < 60 不及格
// >= 60 && <70 及格
// >= 70 && <80 良好
// >= 80 && <90 优秀
// >= 90 极好
var score = prompt('请输入你的分数:');
if ( score < 60 ){
console.log('不及格');
}else if( score >= 60 && score < 70 ){
console.log('及格');
}else if( score >= 70 && score < 80 ){
console.log('良好');
}else if( score >= 80 && score < 90 ){
console.log('优秀');
}else{
console.log('极好');
}
switch
条件语句
语法
switch( 表达式 ){
case 值1:
//跳出条件语句
break;
case 值2:
//跳出条件语句
break;
case 值3:
//跳出条件语句
break;
default:
//输出默认结果
}
注意:switch执行值是严格匹配的,也就是说
5
不等于'5'
示例
var day = new Date().getDay();
switch( day ){
case 0:
console.log('星期日');
break;
case 1:
console.log('星期一');
break;
case 2:
console.log('星期二');
break;
case 3:
console.log('星期三');
break;
case 4:
console.log('星期四');
break;
case 5:
console.log('星期五');
break;
case 6:
console.log('星期六');
break;
default:
console.log('无效的值');
}
循环语句
for循环语句
语法:
for ( 初始值;条件表达式;变量 ) {
// 循环体内语句
}
示例
for ( var i = 0;i<100;i++ ) {
console.log(i);
}
循环也可以把括号中的语句提出到外面,或者置入循环体中
//初始语句外置
var i = 0;
for ( ;i<100;i++ ) {
console.log(i);
}
//变量语句内置
for ( var i = 0;i<100; ) {
console.log(i);
i++;
}
for
循环支持嵌套循环
for{
for(){
}
}
示例
//1. 循环输出 0-99
for ( var i = 0;i<100; i++ ) {
console.log(i);
}
//2. 循环输出 99-0
for( var i=99; i >= 0; i-- ){
console.log( i );
}
//3. 循环输出 0-100的偶数 10 % 3 == 1 , 10 % 5 == 0 % 表示 取余数
for ( var i = 0;i<100; i++ ) {
if( i % 2 == 0 ){
console.log(i);
}
}
//4. 循环输出 0- 100 的总和
var sum = 0;
for ( var i = 0;i<=100; i++ ) {
sum = sum + i;//累积
}
console.log( sum );
//5. 九九乘法表
for( var i=1; i<=9; i++ ){
for( var j = 1; j <= i; j++ ){
document.write( j, '*', i, '=', i*j,' ' );
}
document.write('<br>');
}
break
和 continue
关键字
while循环语句
语法
while( 条件表达式 ){
//循环体语句
//变量
}
示例
var i=0;
while(i<100){
console.log(i);
i++;
}
var i=99;
while(i>=0){
console.log(i);
i--;
}
break
和continue
可以用循环语句中,用来跳出循环
var i=0;
while(i<100){
i++;//放前面,不然会死循环
if(i==50) continue;
console.log(i);
}
for
和while
语句可以混合使用
do while循环语句
do while 无论条件真或假,至少执行一遍。
语法
do {
// 循环体语句
} while ( 条件表达式 );
示例
var i=0;
do {
console.log(i);//0
} while ( i > 10 );
js数据类型
数值 Number
js只有一种数值类型,浮点类型。
var age = 20; //正整型
var price = 34.2; //浮点型
var price = -30; //有符号整型
科学计数法
123e3 // 123000
123e-3 // 0.123
-3.1E+12
.1e-23
正零和负零
-0 === +0 // true
0 === -0 // true
0 === +0 // true
NaN 表示非数字,它的数据类型是数值类型
注意:NaN不等自己
NaN == NaN //false
字符串 String
通常用双引号或单引号包裹的字符,我们称为字符串
单引号里面可以使用双引号,双引号里面可以使用单引号
var name = "张三";
var name = '张三';
//双引号中嵌套使用单引号
var str = "I'm a boy";
//单引号中嵌套使用双引号
var str = '我喜欢吃"苹果"';
//使用转义符,可以安全的输出。
var str = 'I\'m a boy';
var str = "我喜欢吃\"苹果\"";
推荐:优先考虑使用单引号
字符串和变量拼接
字符串和变量用加号+
连接:
- 变量在开头,只需要右加号
var name = '张三';
var str = name + '是我!';
- 变量在中间,需要左右两个加号
var name = '张三';
var str = '我是' + name + '本人。';
- 变量在末尾,只需要左加号
var name = '张三';
var str = '我是' + name;
示例
var name = '张三';
var age = 19;
var xueli = '本科';
console.log('我叫' + name +',今年'+age+'岁。\n 我的学历是'+xueli);
字符串代码不能强制折行,会报错,解决方案如下:
- 字符串拼接换行(差,书写麻烦)
- 末尾加转义符换行(良好)
- es6字符串模板(好用,但要考虑兼容性)
<script>
var name = '张三';
var age = 20;
var xueli = '本科';
var str = `<table border="1">
<tr>
<th>${name}</th>
<th>${age}</th>
<th>${xueli}</th>
</tr>
</table>`;
document.write( str );
</script>
布尔类型 Boolean
布尔类型只有两个值,true
真和 false
假
布尔相关运算符
-
&&
:并且,和,与的意思 -
||
: 或者的意思 -
!
:取反,否定,排除的意思 -
===
:严格等于 -
==
:等于 -
!==
:严格不等于 -
!=
:不等于 -
>
:大于 -
>=
:大于或等于 -
<
: 小于 -
<=
:小于或等于
==
和 ===
的区别
==
它会转换两端的数据类型,以保持相等。
===
它不会转换两端的数据类型,严格等于。
console.log( 1 == '1' );//true 隐式转换
console.log( 1 === '1' );//false
js有那些值会自动转换为假?
-
false
假值 -
0
数值零 -
''
空字符串 -
null
空 -
undefined
未定义 -
NaN
非数字
注意:[]和{} 空数组和空对象都是真值
字符串中注意,只要有值,都是为真值,比如:'0'
、' '
、'false'
都是真值
未定义 undefined
表示一个变量声明了,但是从来没有赋值
空 null
表示变量为空,null
它本质上是一个对象。
undefined
和 null
的区别:
-
undefined
表示声明变量,未赋值 -
null
表示变量值为空 -
undefined
是基本数据类型 -
null
通过typeof
检测它是对象类型
函数 function
函数本身也是一个值,函数允许将多行代码封装起来,然后通过函数名调用,方便代码组织和管理。
function add( c, d){
console.log(c+d );
}
add( 1, 3 );
数组 array
数组是一种集合,存入各种数据类型,可以很方便存取操作,数组是有序的。
var arr = ['苹果','桔子'];
console.log( arr[1] );
对象 object
对象是变量的集合,对象是无序的。
var person = {
age: 20,
name: '张三',
chengnian: true,
habby: ['篮球','美食']
}
console.log( person.habby[1] , person['habby'][1] );
符号 symbol
es6 新增的数据类型,表示唯一值
数据类型总结
js基本类型有那些?
- 数值
- 字符串
- 布尔
- 对象
- undefined
js 有那些数据类型?
- 数值
- 字符串
- 布尔
- 对象
- 未定义 undefined
- 符号 symbol
- 空 null
typeof 检测数据类型
请问typeof
能检测的数据类型有那些?
- number
- string
- boolean
- object
- undefined
- function
- symbol
var a = 10;
var b = '字符串';
var c = true;
var d = [];
var e = {};
var f = Symbol();
var h = null;
var i = undefined;
var g = function(){};
var j = NaN;
var k = '';
console.log( typeof a); // number
console.log( typeof b); // string
console.log( typeof c); // boolean
console.log( typeof d); // object
console.log( typeof e); // object
console.log( typeof f); // symbol
console.log( typeof h); // object
console.log( typeof i); // undefined
console.log( typeof g); // function
console.log( typeof j); // number
console.log( typeof k); // string
因为typeof
检查对象和数组返回都是object
,如何区分?
var o = {};//对象
var a = [];//数组
//方法1
o instanceof Array // false
a instanceof Array // true
//方法2
Array.isArray( o ) // false
Array.isArray( a ) // true
//方法3
数值类型
与数值相关的全局方法:
- parseInt() 将字符串转换数值整型
var a = '100px';
var b = '100 200';
var c = '¥100';
var d = '';
var e = '2e3';
console.log( parseInt(a) );// 100
console.log( parseInt(b) );// 100
console.log( parseInt(c) );// NaN
console.log( parseInt(d) );// NaN
console.log( parseInt(e) );// 2
- parseFloat() 将字符串转换数值浮点型
- number() 将字符串转换为数值
var a = '100px';
var b = '100 200';
var c = '¥100';
var d = '';
var e = '2e3';
var f = '200.67';
console.log( Number(a) ); // NaN
console.log( Number(b) ); // NaN
console.log( Number(c) ); // NaN
console.log( Number(d) ); // 0
console.log( Number(e) ); // 2000
console.log( Number(f) ); // 200.67
-
isNaN
:判断是否是非数字,返回真与假
isNaN
它会隐性的将字符串转为数字,然后判断它是否是非数字
var a = '10';
var b = '十';
console.log( isNaN(a) );//false
console.log( isNaN(b) );//true
数值实例的方法
toFixed
将数值保留指定的小数位数,支持四舍五入。
var price = 100.679;
console.log( (200).toFixed(2) ); //正整型要加括号,不然会报错
console.log( 120.679.toFixed(2) ); //浮点不需要
console.log( '120.679'.toFixed(2) ); //报错,因为toFixed是数值的方法,不是字符串的方法
console.log( price.toFixed(2) );//100.68
给数值实例扩展方法
//扩展方法1
Number.prototype.CNY = function( len ){
return '¥'+this.toFixed( len );
}
var num = 100;
console.log( num.CNY( 2 ) );
//扩展方法2
Number.prototype.add = function( n ){
return this + n;
}
var a = 1;
console.log( a.add(2).add(5) );
隐式数据类型转换有那些?
console.log( 1 == '1' ); //true
console.log( 1 - '1' ); //0
console.log( 2 - true ); //1
console.log( 2 - [] ); //2
console.log( 2 - '' ); //2
字符串类型
字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。
var a = 张三; //错误,必须加引号
var a = '张三';
转义符
常用转义符
-
\n
:换行符 -
\r
:回车键 -
\'
:单引号 -
\"
:双引号 -
\\
:反斜杠 -
\t
:制表符
字符串与数组
- 数组和字符串 都有长度,也有下标(索引值)
- 数组的长度可读写,而字符串只可读,不可写。
- 字符串不可以通过索引值方式改变成员的值。
- 字符串是类数组对象
//数组
var arr = ['你','今','天','心','情'];
//类数组对象
var obj = {
0: '你',
1: '今',
2: '天',
3: '心',
4: '情',
length: 5
}
//类数组对象
var str = '你今天心情';
console.log( arr[1], obj[1] );
arr.length = 10;
obj.length = 10;
console.log( arr.length, obj.length );
var arr = ['你','今','天','心','情'];
var str = '你今天心情';
arr[1] = '昨';//可以写入
str[1] = '昨';//字符串不可以写入
console.log( arr , str );
Base64 转码
var str = 'Hello World!';
//将ASCII编码转换为base64编码
console.log( btoa( str ) );//SGVsbG8gV29ybGQh
var base = 'SGVsbG8gV29ybGQh';
//将base64编码转换为ASCII编码
console.log( atob( base ) );//Hello World!
中文不能直接转为base64编码
//将中文转换为ASCII编码
var str = encodeURIComponent('你好,世界');
//将ASCII编码转换为base64编码
console.log( btoa( str ) );//JUU0JUJEJUEwJUU1JUE1JUJEJUVGJUJDJThDJUU0JUI4JTk2JUU3JTk1JThD
//将base64编码转换为ASCII编码
var base = atob('JUU0JUJEJUEwJUU1JUE1JUJEJUVGJUJDJThDJUU0JUI4JTk2JUU3JTk1JThD');
//将ASCII编码转换为中文
console.log( decodeURIComponent( base ) );//你好,世界
我们可以封装为两个函数,这样转码会方便多了
function b64Encode(str) {
return btoa(encodeURIComponent(str));
}
function b64Decode(str) {
return decodeURIComponent(atob(str));
}
b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"
7月16日
String对象
将其他数据流类型转换为字符串
String(true) // "true" 将布尔转换为字符串
String(12345) // "12345" 将数字转换为字符串
String([]) //'' 将数组转化为字符串,但功能很弱
String.fromCharCode
将一个或者多个unicode码点转换为好识别的字符串
String.fromCharCode() // ""
String.fromCharCode(97) // "a"
String.fromCharCode(104, 101, 108, 108, 111)
// "hello"
字符串的长度
'abc'.length
字符串长度只读,不可写。
String实例的方法
charAt 返回指定索引值的字符
var str='今天的天气怎么样?';
console.log( str[0], str.charAt(0) );//今 今
charCodeAt 返回指定索引值的unicode码点
'abc'.charCodeAt(1) // b 的nicode码点是 98
concat 拼接字符串,类似于加号。
连接过后产生新字符串
var a = '你好';
var b = '张三';
console.log( a + b );
console.log( a.concat(b) );
console.log( a.concat(b,'李四','王五') );
slice 从指定的位置,分割字符串。
位置计算规则
- 位置从0开始计算,大于等于起始位置,小于结束位置。
- 如果位置的值是负数,则倒着数,比如-1为倒数第1个,分割出一个新字符串。
- 省略结束位置,表示截取到末尾
语法
字符串.slice(起始位置, 结束位置);
slice
小示例
var str = '你今天的心情好吗?';
//1. 始终截取第1个字符串
console.log( str.slice(0,1) );
//2. 始终截取最后1个字符串
console.log( str.slice(-1) );
//3. 始终截取倒数3个字符
console.log( str.slice(-3) );
//4. 始终截取首尾单个字符串。
console.log( str.slice(0,1)+str.slice(-1) );
//5. 将字符串分割指定的段数。 你今、天的、心情、好吗、?
var total = str.length; //总字符数
var perPart = 5; //每段分2个字符
var totalPart = Math.ceil(total/perPart); //上舍入 总段数
for(var p=0;p<totalPart;p++){
var start = p * perPart;//4
var end = start + perPart;//6
console.log( str.slice( start, end ) );//2 4
}
substring 分割数组
跟slice
方法很相像。它的第一个参数表示子字符串的开始位置,第二个位置表示结束位置。
如果省略第二个参数,则表示子字符串一直到原字符串的结束。
注意:
substring
的参数不支持负数
substr 截取字符串
语法
起始位置支持负数,如果是负数,那么倒着数,比如-1就是倒数第一个。
字符串.substr(起始位置,截取字符的长度);
var str = '你今天的心情好吗?';
console.log( str.slice(4,6) );//起始位置 结束位置
console.log( str.substr(4,2) );//起始位置 截取长度
indexOf 查找字符第一次出现的位置(索引值)
如果指定的字符不存在,则返回-1
。
语法
字符串.indexOf('要查找的字符','起始位置,默认是0')
示例
var str = 'xianweb@qq@.com';
var index = str.indexOf('@')+1;//8
console.log(str.indexOf('@', index));//查找第二个@
lastIndexOf 查找字符最后一次出现的位置(索引值)
如果指定的字符不存在,则返回-1
。
var str = 'xianweb@qq@.com';
console.log(str.lastIndexOf('@') );//查找第二个@
示例
var url = 'http://www.baidu.com/product/index.html';
//1. 截取网址文件名部分 index.html
console.log( url.slice(url.lastIndexOf('/')+1) );
//2. 截取网址主机和域名部分 www.baidu.com
var index = url.indexOf('//')+2;
console.log( url.slice( index, url.indexOf('/', index ) ) );
var filename = 'images/banner.jpg';
//1. 提取出文件扩展名 jpg
console.log( filename.slice(filename.lastIndexOf('.')+1) );
split 将字符串按指定字符转换为数组
返回的是数组,split
支持''
空字符串参数,howmany
数值,返回所需数组最大长度。
语法
'苹果|桔子|香蕉'.split('|', howmany);//['苹果','桔子','香蕉']
示例
var filename = 'images/banner.jpg';
var arr = filename.split('.');
console.log(arr[arr.length-1]);
console.log( '苹果|桔子|香蕉'.split('|', 2) );//['苹果','桔子']
console.log('苹果桔子'.split('') );//['苹','果','桔','子']
toLowerCase toLocaleLowerCase 转换小写 转换本地小写
toLocaleLowerCase
通常是你自己在原型链取同名函数覆盖,自定义自己的转换规则
console.log( 'ASADSADW'.toLowerCase() );//asadsadw
console.log( 'ASADSADW'.toLocaleLowerCase() );//asadsadw
推荐使用:
toLowerCase
toUpperCase toLocaleUpperCase 转换小写 转换本地小写
toLocaleUpperCase
通常是你自己在原型链取同名函数覆盖,自定义自己的转换规则
console.log( 'asadsadw'.toUpperCase() );//ASADSADW
console.log( 'asadsadw'.toLocaleUpperCase() );//ASADSADW
推荐使用:
toUpperCase
repeat 将字符重复指定的次数 es6
//1. 替换手机中间部分为*号
var mobile = '18512345168';
var start = mobile.slice(0,3);
var end = mobile.slice(-4);
// console.log( start + '*'.repeat(4) + end );
//2.圆点自动补齐
var arr = ['abc','abcde','ssds','wewe','sds','fgf','fgf','fgf','fgf','fgf','fgf','fgf','fgf','fgf','fgf','fgf','fgf'];
//总长度
var total = 30;
//补齐符
var symbol = '.';
//自动补齐
for(var i=0;i<arr.length;i++){
var num = total - arr[i].length - String(i+1).length;
console.log( arr[i] + symbol.repeat(num) + (i+1) );
}
includes 查找是否包含某个字符串 es6
返回真和假
console.log('xianweb@qq.com'.indexOf('#'));//-1
console.log('xianweb@qq.com'.indexOf('@'));//7
console.log('xianweb@qq.com'.includes('#'));//false
console.log('xianweb@qq.com'.includes('@'));//true
replace 字符串替换
不使用正则替换,只能单次,并且区分大小写
语法
'字符串模板'.replace('被搜索的字符','用来替换的字符');
//示例
'hello'.replace('l','*');
//结果 he*lo
match、search 都是依赖使用正则表达式替换
localeCompare 比较两个字符的大小
字符串数字比较,
返回-1,前面的字符小于后面字符
返回0,前面的字符等于后面字符
返回1,前面的字符大于后面字符
var a = '1';
var b = '2';
console.log( a.localeCompare(b) ); // -1
var c = '1';
var d = '1';
console.log( c.localeCompare(d) ); // 0
var e = '2';
var f = '1';
console.log( e.localeCompare(f) ); // 1
字母比较
var a = 'a';
var b = 'b';
console.log( a.localeCompare(b) ); // -1
var c = 'a';
var d = 'a';
console.log( c.localeCompare(d) ); // 0
var e = 'b';
var f = 'a';
console.log( e.localeCompare(f) ); // 1
注意:中文是比较是采用
unicode
数字码比较,不是想要的效果。
Array数组对象
定义数组
- 构造函数方式定义
var arr = new Array();
arr[0] = '苹果';
arr[1] = '桔子';
console.log( arr );
- 构造函数参数赋值快速定义
var arr = new Array('苹果','桔子');
console.log( arr );
- 使用中括号简写定义(推荐)
var arr = ['苹果','桔子'];
console.log( arr );
数组的成员可以是任意数据类型
var arr = [
1,
true,
'苹果',
undefined,
null,
['张三'],
function(){
return 10;
},
{
id:10
}
];
数组的长度
数组的长度可读可写
数组.length
示例
var arr = [];
arr.length = 10;//写
console.log( arr.length );//读 10
注意: 当我们使用length设置长度,如果产生空位,空位的值是undefined
var arr = ['a','b','c','d'];
arr.length = 2;
console.log( arr ); // ["a", "b"]
console.log( arr[100] );// 读 undefined
console.log(arr.length );// 2
数组和数组不能直接用加号相加,这样数组会自动转换为字符串
var arr1 = ['a','b'];
var arr2 = ['c','d'];
//隐式转换为字符串 ['a','b'] => a,b
console.log( arr1 + arr2 ); // a,bc,d
var str = '苹果,桔子,香蕉';
var arr = str.split(','); // ['苹果','桔子','香蕉']
console.log( arr );
console.log( arr + '' ); // 苹果,桔子,香蕉
当给数组的length设置为0,那么就相当于清空数组。
//清空数组
console.log( ['苹果','桔子','香蕉'].length=0 );//[]
多维数组
如果数组的成员还是数组,就形成了多维数组。
var a = ['苹果','桔子']; //一维数组
var b = [
['苹果','桔子'],
['青菜','肉']
];
//二维数组
//数组和对象相接口,非常类似于数据库记录集,类似于一个标准表格数据。
var data = [
{ id: 1, title: '标题1', author:'张三' },
{ id: 2, title: '标题2', author:'张三' },
{ id: 3, title: '标题3', author:'张三' }
]
数值键名会自动转换为字符串
//类数组对象
var obj = {
0: '苹果',
'1': '桔子',
length: 2
}
console.log( obj[0], obj[1], obj['1'] );
数组的读写删操作
数组读取
var arr = ['苹果','桔子'];
console.log( arr[1] );
数组写入新成员
var arr = ['苹果','桔子'];
arr[2] = '香蕉'; //写入一个成员
console.log( arr );// ["苹果", "桔子", "香蕉"]
delete
数组删除成员
var arr = ['苹果','桔子','香蕉'];
delete arr[1];
console.log( arr );// ['苹果',empty,'香蕉']
注意:
delete
删除数组成员并不会改变数组长度,而只是形参一个空位。
in 运算符
检查某个键名是否存在,适用于对象,也适用于数组。
var arr = ['苹果','桔子','香蕉'];
console.log( 0 in arr );//true
console.log( 5 in arr );//false
for...in 循环和数组的遍历
var arr = ['苹果','桔子','香蕉'];
//for 循环
for(var i=0;i<arr.length;i++){
console.log( arr[i] );
}
//while 循环
var i=0;
while(arr[i]){
console.log(arr[i]);
i++;
}
//do while 循环
var i=0;
do{
console.log(arr[i]);
i++;
} while( i < arr.length );
//for in 循环 (不推荐)
for(var i in arr){
console.log(arr[i]);
}
// forEach 高阶函数
arr.forEach( function( a,i,arr ){
console.log(a,i,arr);
})
2019-7-17
forEach循环
forEach
不一定是数组特有的方法 不会循环空成员,比如:
var arr = [1,,,2,3,undefined];
//上面的数组用forEach循环,只会输出1,2,3,undefined
forEach
没有返回值,也就是内部加return
没有返回值。
类数组对象转换为真正的数组对象
语法
var arr = Array.prototype.slice.call(类数组对象);
示例
//类数组对象
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
//类数组转化为真正的数组
var arr = Array.prototype.slice.call(obj);
//因为已经数组了,所有使用forEach无妨
arr.forEach(function( item ){
console.log( item );
})
因为字符串也是类数组,同样可以用上面的方法转成真正的数组
var str = '今天的天气不错';
var arr = Array.prototype.slice.call( str );
//输出 ["今", "天", "的", "天", "气", "不", "错"]
Array.isArray 检测是否是数组
var arr = ['a','b'];
console.log( Array.isArray(arr) );//true
对象
什么是对象?简单说,对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。
对象是变量的集合(容器)
键值可以是任何数据类型
对象的属性之间用英文逗号分割
书写对象过程中常见问题
对象所有的键名都是字符串,所以加不加引号都可以,因为系统内部会转换为字符串
es6
中引入了一种数据类型,叫symbol
,它确保键名是唯一的,也可以使用symbol
作为键名。
//问题1:尾部原则上不需要加英文逗号,但现代浏览器都能忽略
var obj = {
foo: 'Hello',
bar: 'World',
};
//问题2:键名和键值之间是英文冒号
var obj = {
foo= 'Hello',
bar= 'World',
};
//问题3:属性之间用英文逗号分割
var obj = {
foo: 'Hello';
bar: 'World';
};
//问题4:使用了中文的逗号
var obj = {
foo: 'Hello',
bar: 'World'
};
变量是传值传递,数组和对象因为是引用类型,所以它们是传址传递
//1.变量 => 传值传递
var a = 10;
var b = a;//10
a = 20;
console.log( a, b );// a = 20 b = 10
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//2. 对象 => 传址传递
var c = {
name: '张三'
}
var d = c;
c.name = '李四';//对象写入
console.log( c, d );
//c = { name:'李四' }
//d = { name:'李四' }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//3. 数组 => 传址传递
var a = ['苹果','桔子'];
var b = a;
a[1] = '香蕉';//数组写入
console.log( a, b );
//a = ['苹果','香蕉']
//d = ['苹果','香蕉']
表达式还是语句?
当对象的大括号{
在首行首字母位置,如下,js引擎解析会产生歧义,为了避免下面的歧义,js规定,大括号出现在首行首字母位置,一律认为是语句,如果要解析为表达式,则需要用圆括号包裹对象即可。
//会被认为是语句
{
name:'张三'
}
//会被认为是表达式
({
name:'张三'
})
//表达式
var obj = {
name:'张三'
}
eval函数
eval 函数会将字符串的内容当成表达式解析,注册改函数容易引起安全隐患,和性能开销比较大。
//1. eval 四则运算
var str='1*5+5';
console.log( str, eval( str ) );
//2. eval 直接解析变量
var a = 10;
var str = 'a=30;';
console.log( str, eval( str ) );
//3. eval 直接解析数组引用
var a = ['苹果','桔子'];
var str = 'a[1]';
console.log( str, eval( str ) );
因为eval会带来安全问题和性能开销比较大,通常一些框架会屏蔽此函数,具体如下:
window.eval = null;
对象属性的操作
读取属性
- 通常点的形式读取
var obj = {
name: '张三',
'first-name': '李四',
1: 'abc'
}
console.log(obj.name);//张三
- 通常中括号的形式读取
var obj = {
name: '张三',
'first-name': '李四',
1: 'abc'
}
console.log(obj['name']);//张三
console.log(obj['first-name']);//李四
console.log(obj[1]);//abc
当键名是变量时,那么点调用的方式无效,应该使用中括号
var str = 'name';
var obj = {
name: '张三',
age: 20
}
str = 'age';
console.log( obj[str] );// 20
console.log( obj.str );//undefined,需要用[]
属性的赋值
点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。
// 声明时直接填入属性
var person1 = {
name: '张三',
age: 20
}
console.log( person1 );
// 先声明一个对象,后填入属性
var person2 = {};
person2.name = '张三';
person2['age'] = 20;
console.log( person2 );
//对象比较是比较内存地址,不是值
console.log( person1 == person2 );//false
对象比较是比较内存地址,如下
// 声明时直接填入属性
var a = {
name: '张三',
age: 20
}
var b = a;//b等于a相当于b的内存地址指向了a
console.log( a == b ); //true
中括号包裹键名,会起到解析为变量的作用
// 不加中括号
var str = 'name';
var a = {
str:'张三',
age: 20
}
console.log( a );//{ str:'张三',age:20 }
// 加中括号,会解析为变量
var str = 'name';
var a = {
[str]:'张三',
age: 20
}
console.log( a );//{ name:'张三',age:20 }
变量取名慎用
name
,在某些情况下会产生冲突。
Object.keys查看所有属性
Object.keys
方法会将数组中所有的键名,放入到一个新数组中,返回数组。
当键名是symbol
命名时,Object.keys
会跳过symbol
命名属性
var str = Symbol();
var a = {
[str]: '张三',
age: 20
}
var keys = Object.keys( a );
console.log( keys );//['age']
//采用symbol数据类型命名的键名调用
var str = Symbol();
var a = {
[str]: '张三',
age: 20
}
console.log(a[str]);//张三
delete
命令删除对象属性
var str = Symbol();
var a = {
[str]: '张三',
age: 20
}
delete a[str];//删除symbol类型键名
delete a.age;//删除string类型键名
console.log( a );//{}
注意,删除一个不存在的属性,delete
不报错,而且返回true
。
var obj = {};
console.log( delete obj.name);//true
只有一种情况,delete命令会返回false,那就是该属性存在,且不得删除。
//1. 创建新对象创建新属性
var obj = Object.defineProperty( {},'name', {
value: '张三',
configurable: true
})
console.log( delete obj.name, obj ); //false
//2. 在原有对象基础上扩展新属性
var person = {
name: '张三'
}
var obj = Object.defineProperty( person, 'age', {
value: 56, //键值
configurable: true, //configurable表示是否能被delete删除,false不能删除
enumerable: true //enumerable表示是否能被Object.keys枚举,true可枚举
})
console.log( delete person.age, Object.keys(obj) );
delete
命令只能删除对象本身的属性,无法删除继承的属性
var obj = {};
delete obj.toString // true
obj.toString // function toString() { [native code] }
in 运算符
in
运算符用于检查对象是否包含某个属性
in
运算符 继承的属性 也可以检测到,返回true
in
运算符 是浅查找属性,只支持一级属性验证。
var person = {
name:'张三',
info: {
xueli: '本科'
}
}
console.log( 'name' in person ); //true
console.log( 'xueli' in person ); //false
console.log( 'xueli' in person.info ); //true
var obj = {
name:'张三'
}
Object.defineProperty( obj, 'age', {
value: 30,
enumerable: false
})
console.log( obj );
console.log( 'name' in obj ); //true
console.log( 'toString' in obj ); //true
console.log( 'age' in obj );// true
for in 循环对象
-
for in
循环会跳过继承属性,比如toString
-
for in
循环会跳过不可枚举属性,比如设置enumerable: false
var obj = {
name:'张三'
}
Object.defineProperty( obj, 'age', {
value: 30,
enumerable: true
})
for(var k in obj){
console.log( k, obj[k] );
}
将对象的键值提取出来,装入一个新数组,模仿Object.keys
功能
var index = 0;
var arr = []
for(var key in info){
arr[index] = info[key];
index++;
}
console.log( arr );
经典面试题
//查找字符重复的次数
var str = '一d你de你sqssd';
//对象方式
var info = {};
for( var i=0; i<str.length; i++ ){
var val = str[i];
if( val in info ){
info [ val ] ++ ;
}else{
info [ val ] = 1;
}
}
console.log( info );//{一: 1, d: 3, 你: 2, e: 1, s: 3, …}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~···
//查找重复最多的次数
var index = 0;
var firstVal = 0;
for(var key in info ){
if( index == 0 ){
firstVal = info[key];
}else{
if( firstVal < info[key]){
firstVal = info[key];
}
}
index++;
}
console.log( firstVal );// 3
数组的方法
实例方法
变异和非变异的理解
- 变异的方法:破坏了原始数组
- 非变异的方法:不会破坏原始数组,产生新数组
-
valueOf()
数组原始值toString()
将数组转化为字符串
var arr = ['苹果','桔子'];
console.log( arr.valueOf() ); // [1, 2, 3]
console.log( arr.toString() ); // 1, 2, 3
console.log( arr+'' ); // 隐式转换 1, 2, 3
console.log( arr.join(',') );// 1, 2, 3
-
join()
将数组按指定的字符转换为字符串
返回新的字符串,不会破坏原始数组,非变异方法。
如果不提供参数,默认用逗号分隔。
var arr = ['苹果','桔子'];
console.log( arr.join('') ); //苹果桔子
console.log( arr.join('@') ); //苹果@桔子
console.log( arr.join() ); //苹果,桔子
var str = Array.prototype.join.call('hello', '-');
console.log( str );//h-e-l-l-o
-
push()
向数组的尾部追加成员
返回数组最新的长度,该原始数组已经被添加新成员,是变异的方法。
var arr = ['苹果','桔子'];
arr[2] = '菠萝';
var result = arr.push('香蕉'); //执行过后返回数组最新的长度
console.log( result ); // 4
console.log( arr ); // ["苹果", "桔子", "菠萝", "香蕉"]
var arr = ['苹果','桔子'];
arr.push('香蕉','菠萝'); //一次性追加2个
arr.push( ['生菜','西红柿'] ); //追加一个数组
console.log( arr );// ['苹果','桔子','香蕉','菠萝', ['生菜','西红柿'] ]
-
unshift()
向数组的开头追加成员
返回数组最新的长度,该原始数组已经被添加新成员,是变异的方法。
和 上面的push
方法几乎一样,只是插入成员的位置不同。
var arr = ['苹果','桔子'];
arr.unshift('香蕉','菠萝'); //一次性追加2个
console.log(arr);//["香蕉", "菠萝", "苹果", "桔子"]
-
pop()
删除数组最后一个成员
返回被删除成员的值,该方法会破坏原始数组,是变异的方法。
var arr = ['苹果','桔子'];
var result = arr.pop();
console.log( result );// 桔子
console.log( arr );// ['苹果']
-
shift()
删除数组开头第一个成员
返回被删除成员的值,该方法会破坏原始数组,是变异的方法。
var arr = ['苹果','桔子'];
var result = arr.shift();
console.log( result );// 苹果
console.log( arr );// ['桔子']
concat()
用于多个数组的合并,合并出一个新数组,不会破坏原始数组,是非变异的方法
var a = ['苹果','桔子'];
var b = ['芒果','西瓜'];
var arr = a.concat( b );
console.log( arr );// ['苹果','桔子','芒果','西瓜']
push()
和 concat()
的区别:
-
push
返回数组新长度,concat
返回新数组 -
push
变异的方法,concat
非变异的方法 -
push
添加的是数组,会产生多维数组,concat
不会产生多维数组 -
reverse()
反转数组
反转数组,返回已经破坏过后的原始数组,是变异的方法
var arr = [1,2,3];
arr.reverse();
console.log( arr ); // [3,2,1]
示例
//分步操作
var str1 = '今天的天气不错';
var arr = str1.split('');
arr.reverse();
var str1 = arr.join('');
console.log( str1 );
//链式操作
var str2 = '今天的天气不错'.split('').reverse().join('');
console.log( str2 );
-
splice()
集删除、添加、修改功能的数组方法
该函数集删除、添加、修改功能的数组方法,会破坏原始数组,变异的方法。
起始位置,数值,支持负数,表示从后往前数。
删除的个数,数值,必填,如果设置为0,表示不删除。
返回被删除的数组
语法
数组.splice(起始位置,删除的个数, 新成员值1,新成员值2,....);
splice()
删除操作
//删除操作
var arr = ['苹果','桔子','芒果'];
arr.splice(1,1);
console.log( arr );
//1. 清空数组 splice
var arr1 = ['苹果','桔子','芒果'];
arr1.splice(0);//第2个参数省略,代表数组最大的长度
console.log(arr1);
//2. 始终删除第一个成员 splice
var arr2 = ['苹果','桔子','芒果'];
arr2.splice(0,1);
console.log(arr2);
//3. 始终删除最后一个成员 splice
var arr3 = ['苹果','桔子','芒果'];
arr3.splice(-1,1);
console.log(arr3);
//4. 始终只取数组最后两个成员 splice
var arr4 = ['苹果','桔子','芒果'];
arr4.splice(0, arr4.length-2);
console.log(arr4);
splice()
添加操作
注意:添加是在起始位置的前面追加
//添加操作
//1. 在桔子后追加香蕉1个成员
var arr1 = ['苹果','桔子','芒果'];
arr1.splice( 2, 0, '香蕉' );
console.log( arr1 );
//2. 在苹果后面追加火龙果、樱桃2个成员
var arr2 = ['苹果','桔子','芒果'];
arr2.splice( 1, 0, '火龙果','樱桃' );
console.log( arr2 );
//3. 在芒果后面追加数组['哈密瓜','西瓜']
var arr3 = ['苹果','桔子','芒果'];
arr3.splice( arr3.length, 0, ['哈密瓜','西瓜'] );//类似push方法
console.log( arr3 );
splice
修改操作,采用先删后加原则
//1. 在桔子修改为香蕉
var arr1 = ['苹果','桔子','芒果'];
arr1.splice(1,1,'香蕉');
console.log( arr1 );
//2. 在桔子修改为香蕉,芒果修改为西瓜
var arr2 = ['苹果','桔子','芒果'];
arr2.splice(1,2,'香蕉','西瓜');
console.log( arr2 );
-
slice()
分割数组
slice
按照起始位置和结束位置分割出一个新数组,它不会破坏原始数组,是非变异的方法,返回新数组。
起始位置,数值,可以是负数,表示从后开始算,-1 表示倒数第一个
结束位置,数值,可以是负数,表示从后开始算,-1 表示倒数第一个
省略结束位置,表示到数组末尾(相当于数组的长度)。
语法
数组.slice(起始位置,结束位置)
示例
var arr = ['苹果','桔子','香蕉','菠萝','西瓜'];
//1. 提取第一个成员
console.log( arr.slice(0,1) );
//2. 提取第桔子和香蕉
console.log( arr.slice(1,3) );
//3. 始终提取最后一个成员
console.log( arr.slice(-1) );
//4. 始终提取除第一个和最后一个成员
console.log( arr.slice(1,-1) );
//5. 始终提取最后两个成员
console.log( arr.slice(-2) );
示例求学生三门成绩的总分、平均分、最低分、最高分
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
padding: 20px;
}
table{
border-collapse:collapse;
border: 1px solid #ccc;
}
th,td{
padding: 10px;
}
tbody tr:nth-child(odd) td{
background-color: #eee;
}
</style>
<script>
var data = [
{ id: 1, name:'张三', score: [ 78, 88, 75] },
{ id: 2, name:'李四', score: [ 66, 79, 85] }
];
var temp = `<table cellspacing="0" border="1">
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>语文</th>
<th>数学</th>
<th>外语</th>
<th>总分</th>
<th>平均分</th>
<th>最低分</th>
<th>最高分</th>
</tr>
</thead>
`;
for(var i=0;i<data.length;i++){
var score = data[i].score;
var sum = score.reduce( function( prev, next ){
return prev + next;
});//总分
var min = Math.min.apply( null, score );//最低分
var max = Math.max.apply( null, score );//最高分
var avg = (sum/3).toFixed(1);//平均分
temp += `
<tbody>
<tr>
<td>${data[i].id}</td>
<td>${data[i].name}</td>
<td>${score[0]}</td>
<td>${score[1]}</td>
<td>${score[2]}</td>
<td>${sum}</td>
<td>${avg}</td>
<td>${min}</td>
<td>${max}</td>
</tr>
</tbody>
`;
}
temp += '</table>';
document.write( temp );
var arr = [2,3,5,6,8,9];
var num = Math.max.apply( null, arr );
console.log( num );
</script>
分页四要素
- 当前页
page
- 总个数
total
- 每页多少个
perpage
- 总页数
totalpage
sort()
对数组成员进行排序,默认是按照字典顺序排序,排序后,原数组将被改变,变异的方法。
//数字排序
var arr = [ 2,6,1,9, 4];
arr.sort();
console.log( arr ); // [1, 2, 4, 6, 9]
//数字排序不正确,是按字符串排序
var arr = [ 2, 6, 1, 9, 4, 12, 24];
arr.sort();
console.log( arr ); // [1, 12, 2, 24, 4, 6, 9]
//字符串排序
var arr = [ 'b', 'a', 'c', 'd', 'ab', 'bc'];
arr.sort();
console.log( arr ); //["a", "ab", "b", "bc", "c", "d"]
以上排序有局限性,比如数字它是字符来排序的,而且也不方便升序、降序切换
我们可以通过设置一个回调函数使得排序更加精确
语法
数组.sort( function( prev, next ){
return prev - next;
})
数值排序示例
//数值排序
var arr = [ 2, 6, 1, 9, 4, 12, 24];
var flag = -1;// 1 为升序 -1 降序
arr.sort( function( a, b ){
return ( a - b ) * flag;
});
console.log( arr );
字符串排序
//字符串排序
var arr = [ 'b', 'a', 'c', 'd', 'ab', 'bc' ];
var flag = 1; // 1 为升序 -1 降序
arr.sort( function( a, b ){
return a.localeCompare( b ) * flag;
})
console.log( arr );
数组也可以用来替代条件语句输出
var day = new Date().getDay();//0 - 6
var week = ['日','一','二','三','四','五','六'];
console.log('今天是星期' + week[day] );
map()
将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回,它是非变异的方法。
var arr = [ 1, 2, 3, 4, 5];
var newArr = arr.map(function( item ){
return item * 2;
})
console.log( newArr );// [ 2, 4, 6, 8, 10 ]
//取出偶数成员
var arr = [ 1, 2, 3, 4, 5];
var newArr = arr.map(function( item ){
if(item % 2 == 0) {
return item;
}
})
console.log( newArr );//[undefined, 2, undefined, 4, undefined]
//map中this指向第二个参数,下图也就是arr数组
var arr = ['a', 'b', 'c'];
var newData= [0, 2].map(function ( item ) {
return this[ item ];
}, arr);
console.log( newData ); // ['a','c']
forEach()
与map
方法很相似,也是对数组的所有成员依次执行参数函数,forEach
方法不返回值,只用来操作数据。
示例
var arr = [ 1, , 3, , 5];
arr.forEach(function( item, index, arr ){
console.log( item, index, arr );
})
forEach
和 map
的区别
-
forEach
没有return
返回值,它会跳过空位 -
map
有return
返回值,它会跳过空位
filter()
方法用于过滤数组成员,满足条件的成员组成一个新数组返回,非变异的方法。
//查找出不及格的分数
var score = [ 50, 70, 58, 62, 80];
var newScore = score.filter( function(item){
return item < 60;
})
console.log( newScore );//[50, 58]
//也可以利用排除法删除
var arr = [ 50, 70, 58, 62, 80];
arr = arr.filter( function(item){
return item != 62;
})
console.log( arr );//[ 50, 70, 58, 80];