JavaScript (快速入门篇)
\(updata : 2022.1.15\)
学习的原文
\(① :\) 基本语法
\(JavaScript\) 每个语句以 ";" 结束 ,语块用{...} ; 但并不强制要求每句都加上 ";" , 负责执行代码的引擎会自动帮助添上的;(但有时候自动补全会违背本意,建议一定要加上);
"//" , "/**/" 的注释效果在这里同样适用;
\(② :\) 数据类型和变量
感觉 \(c\) 里面的类型在这里都有提 , 但有好多的细节不同;
比如既可以用 ' ' 又可以用 " " 来引用字符串 ;
比较用等于的时候不是 " == " , 而是 " === " , 原因廖雪峰老师也着重强调了 , "==" 会转化数据类型再比较,往往会有诡异的结果;而"===""只要数据类型不相同就返回 \(false\) , 数据类型相同再进行比较;
不过最令我吃惊的是在 \(JavaScript\) , 作为动态语言 \(var\) 的存在
var a = 12 ; true ; "ABC" //整形,布尔,字符均可;
var a = 12 ;
a = "ABC" //还能变化不同的类型
var a = [1,2,'ABC',null,true,undefined];
//同一数组里面也有不同的类型
//跟c一样,同下标来访问数组元素,例如 a[0] //1 ,a[2] // 'ABC';
//文章还提及另一种数组创建方式
new Array(1,2,3) //创建数组[1,2,3] , 强烈建议使用[];
var a = [1,[3,4,5],[6,7,8]];
//访问 4 的话 , a[1][1];
var xiaoming ={
name : '小明',
age : 18
}
//看上去像结构体 , 这里称作为对象;
//其中xiaoming称为对象变量 , name称为属性名 ,'小明'称为属性;
在这里我们看到了 \(var\) 的重要性,同一变量可以反复赋值,而且可以是不同类型的变量,但注意 \(var\) 只能申明一次;如果一个变量没有通过 \(var\) 申明就被使用,那它自动变为全局变量,同一页面的不同\(JavaScript\) 文件中都使用同一全局变量的话,造成变量的相互影响,产生难以调试的结果,建议在代码的第一行写下 'use strict' , 这样就开启了\(strict\) 模式,强制用 \(var\) 声明变量 , 否则报错.
同时我们注意到在举例时出现 \(null\) , \(undefined\) , \(null\) 代表一个空的值, \(undefined\) 代表未定义 , 之后在字符串,数组那块每当函数(应该是函数)调用超越范围时往往会出现 \(undefined\) ; 文章还提及了 \(NaN\) , 意为 not a number 当无法计算结果时候用的 , 这里注意 \(NaN\) 不与任何数相同 ,包括它自己 ,只能通过 isNaN()函数判断, isNaN(NaN) // true ; \(Infinity\)表示无限大;
还有一个很重要的一点就是变量名由英文大小写,数字,\(\$\) 和 \(\_\) 的组合,且数字不能开头;
\(③ :字符串\)
前面提及了字符串用 " " 或 ' ' 引用 ;
如果 ' 也是一个字符的话 ,用 " "括起来 ,例如 "I'm ok!".
那么如果既有 ' 又有 " , 这个时候我们就要用转义字符 '\' , 例如' I\'m \"小明\" ',就有了I'm "小明".的效果.
如果转义字符本身也要转义,\\即可,同样'\n'代表着换行;
文章还提及多行字符串
怎么输出
多行
字符串
测试
这三行的效果?
① console.log('多行') ; console.log('字符串') ; console.log('测试');
//console.log()每次输出自动换一行;
② console.log('多行\n字符串\n测试');
//主要利用到了'\n'的操作;
③ 利用反引号
console.log(`多行
字符串
测试`);
模板字符串
//把多个字符串相连,可以用 '+' 号;
//例如;
var name = 'xiaoming';
var age = 20;
var message = '你好, ' + name + ', 你今年' + age + '岁了';
console.log(message);
//当很多变量需要连接时,利用 `` 则会更加便捷
//同样上面那个例子:
var message = `你好,${name},你今年${age}岁了!`;
//我们称此为模板字符串;
操作字符串
s.length //表示一个函数返回值,返回字符串的长度,注意没有();
var s = "a b c";
s[0] // 'a' , s[1] // ' ' , s[2] //'b';
//注意当s[5]越界时返回的是undefined;
//原文特别强调了字符串是不可变的,对字符串的某个位置赋值不会错但没有用
//例如
var s = "cde";
s[0] = 'a';
console.log(s) ; //仍然为cde;
console.log(s[0]) ;//仍然为c;
//但是再整体赋值就可以整体改变;
s = "abc";
console.log(s);//s为abc;
s.toUpperCase();//同样是一个返回值,把一个字符串全部变成大写 ; 注意有();
s.toLowerCase();//返回值;把一个字符串全部变成小写;
s.indexOf('字符串') //, 类似于find函数 ,返回s中被找字符子串的首位置 , 不存在的话会输出-1;
s.substring(0,5) ; 返回s中[0,5),不包括5的字符子串 ; s.substring(7) , 从7开始到结束.
如果区间不存在,或者有一部分区间不存在 , 则不会输出不存在的部分;
\(④ :\) 数组
arr.length;//数组的长度
直接给长度赋值会导致原数组数组改变:少了的补 undefined ,多出的截去;
//var arr = [1,2,3] ; arr.length 由3->2->3 , arr为[1,2,empty],并不会恢复;
直接通过索引(下标)对数组赋值则会改变对应下标的值 , 这点与字符串是不一样的;
如果索引超过了原数组的大小 , 举个例子
var a = [1,2,3,4,5] ;
a[6] = 'x';
//此时a = [1,2,3,4,5,undefined,'x'];
//不过undefined的位置输出什么都没有;
与string类似 ,Array也可通过indexOf()来搜索指定元素的位置,二者是相通的;
slice()对应String的substring()版本 , 当括号内不带有任何参数时 , 它默认全体复制 ,话说substring()也有这个效果;
push()操作在数组的尾部添加 , unshift()在数组的头部添加;
二者会返回数组的实时长度 ;
push,unshift能一次增加多个元素;//arr.push(1,2) , arr.unshift(1,2,3);
pop()去除最后一个元素 , shift()去除开头元素;
二者都返回删除元素,如果没有元素还删除,就返回undefined;
arr.sort();//排序,从小到大;
arr.reverse();//反转;
接下来就是大家都说好的 splice()
arr.splice(1,2,'a','b');
从下标1开始删除2个元素 (别与slice的区间弄混了) , 再从下标1开始添加'a','b';
arr.splice(1,0,'a','b'); //只添加;
arr.splice(2,1);//只删除;
要注意slice与splice的区别 , slice是截取一段返回新的array(也就截取值)但对原数组并没有修改 , 而splice是在原数组上修改 , 返回删除值(好吧也就是截取值);
concat() //把一个Array与另一个Array连接起来,并返回一个新的Array(其实是接受到任意个元素和Array,将它们拆开再连接起来) ;
var a = [1,2,3] ,t = [7,8,9];
added = a.concat(t,['A','B','c'],1,2,3);//注意它是一个返回值;
join('字符串');//把当前Array的每个元素用指定的字符串连接起来,注意是返回值;
var a = [1,2,3] ;
var changed = a.join('-');
多维数组
var arr = [[1,2,3],[400,500,600],'-'];
注意[1,2,3]整体为第0维 , 以此类推;
arr[0][1] // 2;
arr[1][1] // 500;
arr[2] = '-';
目前多维数组配合splice在单维上仍有效,多维就有点尬;
//arr.splice(a[0][1],1,"A"),arr仍未变;
对象
是一种无序的集合数据类型 , 有\(c\)中的结构体的感觉,它由若干个键值组成;
var xiaoming={
name : '小明',
birth : 1990
}
//最后一个键值不用加',' ;
//上述对象声明一个'name'属性 , 值是'小明';
//一定是var xiaoming = {}; '='不能漏掉了.
xiaoming.name //'小明';
xiaoming.birth //1990;
属性名字含有特殊字符的时候,就必须用'' ,访问时用[]
'middle-school' : 'No.1 school'
xiaoming['middle-school'];
访问一个不存在的属性时会返回 undefined;
可自由的添加与删除(直接引用原文)
var xiaoming = {
name: '小明'
};
xiaoming.age; // undefined
xiaoming.age = 18; // 新增一个age属性
xiaoming.age; // 18
delete xiaoming.age; // 删除age属性
xiaoming.age; // undefined
delete xiaoming['name']; // 删除name属性
xiaoming.name; // undefined
delete xiaoming.school; // 删除一个不存在的school属性也不会报错
检验一个对象是否有某种属性时
用 in 或 hasOwnProperty()函数;
'name' in xiaoming // true;
但最好用后者 , 原文指出 in 判断的属性存在可能对象并没有,是他继承得到的;
xiaoming.hasOwnProperty('toString')//false
\(⑤ :\) 条件判断
这玩意就是 \(if\) , \(else if\) , \(else\) ,应该会.
\(⑥ :\) 循环
for(;;) // 与 $c$ 一样 ; $break$ 也可以用;
for 的 一个变体是for in , 用来遍历对象
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
console.log(key); // 'name', 'age', 'city'
}
同时 Aarry 也可以用for in
var a = [1,2,3,4];
for(var i in a){
console.log(a[i]);
}
原文强调了for...in对Array的循环是String而不是Number
while 与 do...while的用法则是与c一致的;
同样a[++i] , a[i++]的优先级照样适用;
\(⑦ : Map 与 Set\)
跟c++里面的stl中的map,set差不多.
map强调一种 "key-value" 的映射关系;
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
var m = new Map();
m.set('Adam', 67);
m.set('Adam', 88);
m.get('Adam'); // 88
我们注意到m.set(key,value) ;
get查询,delete删除时得用key为关键字查询/删除value;
同时注意delete在删除对象得属性时也出现过.
set则只存key,不存value,且没有重复的key;
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3
var s = new Set([1, 2, 3, 3, '3']);//注意Map是[]里面加[];
s; // Set {1, 2, 3, "3"},重复元素剔除;
s.add(4);
s; // Set {1, 2, 3, 4}
s.add(4);
s; // 仍然是 Set {1, 2, 3, 4}
var s = new Set([1, 2, 3]);
s; // Set {1, 2, 3}
s.delete(3);
s; // Set {1, 2}
\(⑧ : iterable\)
因为遍历 Map 与 Set 无法使用下标,为了统一集合类型,ES6标准引入了iterable类型 , 对array , Map , Set均适用
var a = [1,2,3];
var b = new Map([4,5,6]);
var c = new Set([1,'x'],[2,'y'],[3,'z']);
遍历时我们要用到 for...of... ( 与for...in...做区别 )
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for(var x of a){
console.log(x) ; // 'A','B','C';
//注意这里和for...in是有区别的 , 如果是for...in , 那么这里的x就是下标0,1,2;
}
for(var x of s){
console.log(x);//'A','B','C';
}
for(var x of s){
console(x[0] + '=' + x[1]); //1 = x , 2 = y ,3 = z;
}
这里与for...in做区别 , for...in遍历对象的属性名称,一个Array数组实际上也是一个对象,每个元素索引被看成一个属性
var a = ['A', 'B', 'C'];
a.name = 'Hello';//手动添加额外属性
for (var x in a) {
console.log(x); // '0', '1', '2', 'name'
}
但for...of只循环集合本身元素;
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
console.log(x); // 'A', 'B', 'C'
}
文章提及更好的遍历方法
iterable内置的forEach
var a = ['A','B','C'];
a.forEach(function (element,index,array){
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
console.log(element + ', index = ' + index);
/*A, index = 0
B, index = 1
C, index = 2*/
}); (一定注意这里是有回括号的);
//element,index,array仅仅是名称而已,可替换,原文应该是想规范变量,并且可适当舍弃参数.
var s = new Set(['A','B','C']);
s.forEach( function(element,sameElment,set){
console.log(element);//这个函数对set与array的参数是一样的(好吧,有一点不同),但set是没有索引的,前两个都是元素.
});
var t = new Map([1,'x'],[2,'y'],[3,'z']);
t.forEach( function(value,key,map){//参数前两者对应了value和key;
console.log(value);
});
前面说的舍弃参数,只能按从后往前的顺序舍弃.