一. Javascript基本介绍
Javascript 简称JS,是一门独立的编程语言,是可以运行在浏览器上的脚本;名称上有Java,但是它与Java没有任何关系的。
在HTML中引入JS的方法:
方案一, 直接在<script>标签中引入编写js代码
方案二, 将js代码写在js文件中, 然后通过script标签的src属性进行引入
两种方式运行出的效果是一致的. 但是需要各位注意一点, HTML程序在执行的时候是从上到下进行渲染的. (代码也是从上到下执行的)
在js中使用// 来表示单行注释. 使用/* */表示多行注释.
二. Javascript基本数据类型
常见的两行JS代码
console.log('开始学习了'); // 在控制台打印,相当于python中的print
let a = '1002';
console.log(typeof a); //打印变量a的数据类型
1、主要是以下几种数据类型
number 数字, 不论是整数还是小数, 数据类型都是number
string 字符串, 这个没啥可聊的. 就是很单纯的字符串
boolean 布尔值, 只有两个, true和false. 注意不是大写T和F.
object 对象, 这个比较特殊. 你可以理解为所有被new出来的东西都是对象
undefined, 这个表示未定义. 所有没有被定义过的东西默认都是该类型 类似像空一样的东西
2、定义变量
JS中,要使用一个变量要先定义变量,关键词是 var 或者 let,可以定义变量名称,不赋值。要注意一行代码同时创建多个变量的情况。
var 变量名; // 创建变量, 此时该变量除了被赋值啥也干不了.
let 变量名; // 创建变量, 此时该变量除了被赋值啥也干不了.
var 变量名 = 值; // 创建一个变量, 并且有值.
var 变量名 = 值1, 变量名2 = 值2, 变量名3 = 值3.....; // 一次创建多个变量.并都有值
var 变量名1, 变量名2, 变量名3 = 值3; // 创建多个变量. 并且只有变量3有值
3、JS中的运算符
JS中的运算符和Python几乎一致. 但有些特殊的.
and, or, not 到了js中注意,换成了&&, ||, !, 其含义和概念是一致的.
var a = 10, b = 20, c = 30 ;
console.log(a > b && b > c); // false
console.log(!(a > b)) // 注意括号
4、JS 中的 == 和 ===,
== 只是判断值是否一致,
=== 会判断数据类型和数据是否都一致.
var a = "123";
var b = 123;
console,log(a == b); // true
console.log(a === b); // false
5、数据类型及进制转换
字符串转换成数字,使用parseInt(字符串),parse英文翻译是“解析”的意思
let a = '1002';
console.log(typeof a);
let b = parseInt(a);
console.log(typeof b); //输出 number
数字转换成字符串
方法1:数字.toString(),参数不填是默认是十进制
方法2: 数字 + ""
var a = 10;
var b = a.toString(16); //输出是16进制数字对应的字符串,10对应16进制是a,
console.log(b);
console.log(typeof b);
//方法2
b = a+""; //b就是字符串了
进制转换
parseInt 的结果是十进制,参数中要说明要转换的参数是多少进制的
toString() 要说明转换成多少进制的
var a = 10;
// 16进制的数字是多少
var x = a.toString(16); // a,字符串类型
console.log(x, typeof x) //a string
// AB的十进制是多少
var d = parseInt("AB", 16); // parseInt的结果是十进制,参数中要说明要转换的参数是多少进制的 171
console.log(d, typeof d) //171 number
6、JS中的++与--
a++; 就是a = a + 1
++a; 就是a = a + 1
a--; 就是a = a - 1
--a; 就是a = a - 1
重点概括:
- 不论是a++还是++a. 目的都是让a自增1.
a++这个表达式整体运算出来的结果等于 a
++a这个表达式整体运算出来的结果等于 a + 1
表达式执行完成后,a自增1
a = 10
b = a++ //a++表达式运算结果为a,就是10,所以b=10;运算完成后,a自增1,那么a=11
console.log(b) // 10
console.log(a) // 11
a = 10
b = ++a //++a表达式运算结果为a+1,就是10+1,所以b=11;运算完成后,a自增1,那么a=11
console.log(b) // 11
console.log(a) // 11
以下逻辑比较奇怪,一般不会这么使用
a = 10;
a = a++; //a=a,也就是a=10,运算完成后a自增1,所以a又变成了11,但是最终赋值的时候,还是按照之前计算的a=a++,而由于是先计算a++,所以a++的值是a=10,a=11只是短暂的瞬间
console.log(a); // 10
a = 10;
a = ++a; //a=a+,也就是a=11,运算完成后a自增1,所以a短暂瞬间变成了12,a=12,但是赋值是最后运算的,而++a是最初运算的,值是11
console.log(a) // 11
剖析:
a = 10;
a = a++;
console.log(a); // 10
第一步:a = 10
第二步:1)先计算a++,表达式的值是a,也就是10;
2)a自增1,而原来a=10,所以,此时a==11;
3)最终赋值,a = a++,记住,这一步只是赋值,而不再进行对a进行任何计算,a++之前已经计算好了,表达式的值就是10,所以,赋值这步的结果就是把之前计算好的a++的值赋值给a,所以,a==10。(在上一步a通过自增已经从10变成11了,但是最后这步又对a重新进行赋值了)
第三步:打印a的值,所以打印的结果是a=10
第二部分代码:
a = 10;
a = ++a;
console.log(a); // 11
第一步:a = 10
第二步:1)先计算++a,表达式的值是a+1的值,也就是++a == 11;
2)a自增1,而原来a=10,所以,此时a==11;
3)最终赋值,a = ++a,记住,这一步只是赋值,而不再进行对a进行任何计算,++a之前已经计算好了,表达式的值就是11,所以,赋值这步的结果就是把之前计算好的a++的值赋值给a,所以,a=11;
第三步:打印a的值,所以打印的结果是a=11
7、字符串操作
s.split() 字符串切割
let s = "刘德华_张学友_黎明_郭富城";
let res=s.split('_');
console.log(res); // [ '刘德华', '张学友', '黎明', '郭富城' ]
console.log(typeof res); // object
s.substr(start, len) 字符串切割, 从start开始切, 切len个字符
let s = "刘德华_张学友_黎明_郭富城"
let res = s.substr(4, 3); // 从索引为4的位置开始切,切取长度为3
console.log(res); // 张学友
s.substring(start, end) 字符串切割, 从索引start切割到索引end,取左不取右
let s = "刘德华_张学友_黎明_郭富城"
let res1=s.substring(0,3)
console.log(res1) //刘德华
(重点)s.length 字符串长度
let s = "刘德华_张学友_黎明_郭富城"
console.log(s.length)
s.charAt(i) 第i索引位置的字符
let s = "刘德华_张学友_黎明_郭富城"
console.log(s.charAt(0)) //刘
(重点)st.charCodeAt(索引),对应索引的字符在ASCII码中的字符编码
let st='nameAge天空'
let res=st.toUpperCase()
console.log(st.charCodeAt(3)); //索引3对应的字符是e,在ASCII编码中对应是101
把ASCII字符编码转换成字符
let as = String.fromCharCode(101)
console.log(as); //输出字符是e
s.indexOf('xxx')返回xxx的第一个索引位置, 如果没有xxx. 则返回-1
let s = "刘德华_张学友_黎明_郭富城华"
let res=s.indexOf('华')
console.log(res); //结果是2,返回的是,第一个“华”的索引
console.log(s.indexOf('哈')) //没有'哈'这个字符,所以返回-1
s.lastIndexOf("xxx") 返回xxx的最后一次出现的索引位置,如果没有xxx. 则返回-1
let s = "刘德华_张学友_黎明_郭富城华"
let res=s.lastIndexOf('华')
console.log(res); //结果是14,返回的是,最后一个“华”的索引
s.includes("xxx") 判断xxx是否出现在s中. 在就返回 true,不在就返回 false;相当于是python中的in
let s = "刘德华_张学友_黎明_郭富城华"
console.log(s.includes('刘德华'));//返回true
s.toUpperCase() 把字符串中所有小写字母转换成大写字母
let st='nameAge天空'
let res=st.toUpperCase()
console.log(res); // NAMEAGE天空
s.startsWith("xxx") 判断是否以xxx开头
let st='nameAge天空'
let res=st.toUpperCase()
console.log(res)
console.log(st.startsWith('n')) ;// true
console.log(st.startsWith('an')) ;// false
关于null和undefined. null可以理解为变量创建了,但是值为空. undefined就是没有定义变量。
练习:提取json字符串
s = "callback_jsonp({'name': '刘德华', 'age': 18, zhiye: {'one': '歌手'}})";
let start = s.indexOf('{')
let end = s.lastIndexOf('}')
let ret = s.substring(start, end+1)
console.log(ret)
二. JS条件语句
注:如果代码块1中的内容只有一行. 则可以省略外面的大括号(一些逆向工程里会有)
// 语法
if(条件1){
代码块1
}
// 解读: 当`条件1`成立时, 执行代`码块1`中的内容, 如果`条件1`不成立. 则不执行该`代码块1`中的内容
例子
let a = 10;
if(a>1){
console.log('条件成立');
};
if (a>1) console.log('如果大括号中的内容只有一行. 则可以省略外面的大括号');
双条件分支
// 语法
if(条件1){
代码块1
} else {
代码块2
}
// 解读: 当`条件1`成立时, 执行`代码块1`中的内容, 如果`条件1`不成立. 则执行`代码块2`中的内容
例子
let b=10;
if (b>20){
console.log('条件为真是执行');
}else {
console.log('条件为假是执行');
}
多条件分支
// 语法
if(条件1){
代码块1
} else if(条件2) {
代码块2
} else if(条件3) {
代码块3
} ... {
代码块n
} else {
代码块else
}
// 解读: 当`条件1`成立时, 执行`代码块1`中的内容, 如果`条件2`不成立. 则执行`代码块2`中的内容...如果都不成立, 最终执行`代码块else`中的内容.
例子
let c = 85;
if (c>=85){
console.log('优秀')}
else if(c>=75){
console.log('良好')}
else if(c>=60){
console.log('及格')}
else {
console.log('不及格')}
switch语句. 也是一种多分支,在JS中常用于混淆,打乱case的执行顺序。
switch(变量){
case 值1:
代码块1
break // 可选
case 值2:
代码块2
break // 可选
case 值3:
代码块3
break // 可选
default: // 可选
default代码块
}
/*
解读:
执行时,
switch会判断变量的值是否是`值1`,
如果是, 则执行代码块1以及代码块1中的break,
如果不是, 则继续判断`值2`...
如果前面的`值`都没有和`变量`相等的.则执行`default代码块`.
注意,
每一个`case`中都可以选择`break`, 也可以不选择`break`, 需要注意的是, 如果不写`break`.
那么就会形成`case穿透`现象.
例, `变量`的值如果和`值1` 相等. 并且case1中没有写`break`,
则在执行的时候. 会执行完`case1`中的代码.
然后会自动穿透到`case2`中去执行里面的代码, 而不经过case2中的数据的验证.
*/
例子
let t=10;
switch (t){
case 1:
console.log('我是1');
console.log('我就是1');
break;
case 2:
console.log('我是2');
console.log('我就是2');
break;
case 3:
console.log('我是3');
console.log('我就是3');
break;
default:
console.log('我是默认');
}
case穿透现象的利用
let month=5
switch (month){
case 1:
case 2:
case 3:
console.log('第一季度');
break;
case 4:
case 5:
case 6:
console.log('第二季度');
break;
case 7:
case 8:
case 9:
console.log('第三季度');
break;
case 10:
case 11:
case 12:
console.log('第四季度');
break;
default:
console.log('输入的月份要在1-12之间')
}
三. JS中的循环语句
在js中有三种循环语句. 首先是while循环. 它的逻辑和python中的while几乎一模一样, 就是符号上有些许的区别.
// 语法
while(条件){
循环体 -> 里面可以有break和continue等关键字
}
/*
判断`条件`是否为真, 如果`真`, 则执行`循环体`.执行完`循环体`, 会再次判断`条件`....
并且在循环中也可以使用`break`和`continue`等关键字来控制循环的走向.
*/
// 语法
do{
循环体
} while(条件);
/*
解读:
先执行`循环体`, 然后判断`条件`是否成立, 如果成立.在来一次.
注意, 由于do..while是先执行的`循环体`. 所以, 不论条件如何, 至少执行一次`循环体`
*/
例子
let a=10;
do{
console.log(a);
a++;
} while (a<=10)
// 语法: for的第一种语法
for(表达式1; 表达式2; 表达式3){
循环体
}
表达式1
while 表达式2:
循环体
表达式3
/*
解读:
for循环和我们python中的循环是完全不一样的. 解读起来会有点儿麻烦.
首先, 在执行的时候, 先执行`表达式1`,
然后, 判断`表达式2`得到的结果是否真, 如果`真`, 则执行循环体,
再然后, 执行`表达式3`,
再然后, 判断`表达式2`执行的结果是否为`真`, 如果`真`, 则执行`循环体`
再然后, 执行`表达式3`
.....
直到, `表达式2`得到的结果是`假`, 则跳出循环
*/
// 看起来很绕. 我们用for循环来跑一个1~99
for(var i = 1; i < 100; i++){
console.log(i);
}
/*
首先, i = 1,
然后, 判断 i < 100 成立
打印i
在然后, i++, i变成2
再然后, 判断 i < 100 还是成立
打印i
再然后, i++, i变成3
再然后, 判断 i< 100 还是成立
打印3....
....
当i = 100了. i < 100不成立. 程序结束
*/
// for循环的固定逻辑也就这样了
for(变量声明; 条件判断; 改变变量){
循环体
}
// for的第二种用法
var a = [11,22,33,44,55,66]
for(let i in a){
console.log(i + "_" + a[i])
}
// 这种写法非常类似python中的for循环. 但是要注意. 这里的`i`拿到的仅仅是 `数组a`的索引信息.
// 如果需要数据 a[i]
四.JS中的数组和对象(重点)
在JS中创建数组. 直接[ ]即可. 也可以用new Array(). 效果都是一样的.
在JS中 new 出来的东西,数据类型都是object;在JS中 创建空对象的时候,可以不写()
// 定义数字的两个方法
let a1=['刘德华', '张学友', '黎明', '郭富城'];
console.log(a1, typeof a1); // [ '刘德华', '张学友', '黎明', '郭富城' ] object
// 在JS中 new 出来的东西,数据类型都是object
let a2=new Array('刘德华', '张学友', '黎明', '郭富城');
console.log(a2, typeof a2); // [ '刘德华', '张学友', '黎明', '郭富城' ] object
// 在JS中 创建空对象的时候,可以不写()
let a3=new Array;
console.log(a3, typeof a3); //[] object
数组的常用操作
arr.push(data); // 在数组后面添加数据
// 在JS中 创建空对象的时候,可以不写()
let a3=new Array;
console.log(a3, typeof a3); //[] object
a3.push('下雨天')
a3.push('无名火', '666')
console.log(a3 ); //[ '下雨天', '无名火', '666' ]
arr.length; // 数组长度
let res=a3.length
console.log(res)
arr.pop(); // 删除数据, 从后面删除, 并返回被删除的内容
let a3=[ '下雨天', '无名火', '666' ]
let del = a3.pop()
console.log(del) //666
console.log(a3) // [ '下雨天', '无名火' ]
arr.shift() // 删除数据, 从前面删除, 并返回被删除的内容
let a=[ '下雨天', '无名火', '666' ]
let del = a.shift()
console.log(del) // 下雨天
console.log(a) // [ '无名火', '666' ]
arr.unshift(xxx); // 在数组之前增加数据
let b=[ '下雨天', '无名火', '666' ]
let add = b.unshift('刘德华', '张学友') // 返回的是数组的长度;也可以不用变量接收
console.log(add) // 5,返回的是数组的长度
console.log(b) // [ '刘德华', '张学友', '下雨天', '无名火', '666' ]
arr.flat(); // 扁平化处理数组
let arr=[1, 2, 3, [4, 5, 6]]
arr = arr.flat()
console.log(arr)
arr.slice(开始索引,结束索引);切片功能,取左不取右;和python一样
let arr=[0, 1, 2, 3, 4, 5, 6]
let res = arr.slice(1,3)
console.log(res)
arr.join("连接符"); // 使用连接符将arr中的每一项拼接起来. 和python中的 "".join()雷同
let name=['刘德华', '张学友', '黎明', '郭富城'];
let res = name.join('-')
console.log(res); // 刘德华-张学友-黎明-郭富城
arr.forEach中的每一项循环出来. 分别去调用function函数, 会自动的将数据传递给函数的第一个参数,第二个参数是数组的索引,第三个参数就是数组本身arr
let arr=[11, 22, 33, 44, 55, 66]
arr.forEach(function fn(a,b,c){
console.log(a, b, c, a+b);
})
在JS中创建一个字典(也属于对象,object类)非常容易. 和python中的字典几乎一样,JS中的字典的key可以加引号,也可以不加。
var p = {
name: "刘德华",
age: 18,
wife: "朱丽倩",
sin: function(){
console.log("唱歌")
}
};
重点:
把对象变成json字符串: JSON.stringify()
把字符串变成对象: JSON.parse()
let p = {
name: "刘德华",
age: 18,
wife: "朱丽倩",
sin: function(){
console.log("唱歌")
}
};
console.log(typeof p, p)
// 把字典对象转换成json字符串
let json_str=JSON.stringify(p)
console.log(typeof json_str, json_str) // string {"name":"刘德华","age":18,"wife":"朱丽倩"}
// 把json字符串转换成字典对象
let dic = JSON.parse(json_str)
console.log(typeof dic) // object
(重点)使用对象(数组、字典)的两种方法:
方法1:对象.key
方法2:对象['key']
console.log(p.name, p['age'])
p.sin()
从上述内容中几乎可以看到. JS对象的使用几乎是没有门槛的. 十分灵活
for(var n in p){
if(typeof(p[n]) != 'function'){
console.log(p[n])
}
}
五. JS中的函数(重点)
// 函数:标准函数,有函数名,有参数
function fn(a,b){
return a+b;
}
let res1 = fn(3, 4)
console.log(res1)
// 函数名可以是特殊符号,如 $、_
function $(){
console.log('函数名称是$')
}
// 调用函数
$()
function _(){
console.log('函数名称是_')
}
// 调用函数
_()
// 赋值,内存地址复制,函数运行的时候不是依赖函数的名字,而是函数的地址
sdgjksfldfgkjdsfh = _
sdgjksfldfgkjdsfh()
扩展一下
数组的元素是函数
let arr=[function (){
console.log(123)}, function (){console.log(456)}, function (){console.log(789)}]
arr[0]()
// for循环运行函数
for (let i=0;i<arr.length;i++){
arr[i]()
}
JS中的函数可以没有函数名,也可以自运行.
注意:JS中只要能够形成 xxx() 并且xxx是一个函数的话就可以执行。
自运行函数
(function gn(){
console.log('我要自己运行');
})();
(function (){
console.log('我是一个函数,我没有函数名,我自己运行')})()
带参数
// 带参数
(function (a, b){
let sum=a+b;
console.log('我是一个函数,我没有函数名,我自己运行 结果是:', sum)})(3, 4)
自运行函数带返回值,需要用变量接收
// 带返回值的自运行函数
let new_arg = (function (a, b){
let sum=a+b;
return sum
})(3, 4)
console.log(new_arg)
自运行函数使用window中参数值的两种方法
window是HTML中的顶级作用域,作用于全局,是所有作用域的根。window中的方法可以直接使用,也就是可以直接省略window。如
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script> // 方法1:
(function () {
window.name = '刘德华';
})();console.log(name);
// 方法2:
(function (a) {
a.age = 18;
})(window)
console.log(window.age)
</script>
</head>
<body>
</body>
</html>
注意:JS文件的时候,不可以直接使用window,因为window只是HTML中的顶级作用域,直接运行下面JS代码会报错,提示 window 没有定义。所以,在逆向扣代码的时候,要注意
(function () {
window.name = '刘德华';
})()
console.log(name)
this的用法
字典对象可以使用this来调用对象本身的参数
let dic={
name:'刘德华',
age: 18,
song: function (){
console.log(this.name+'唱了一手歌')},
today: function (){
console.log('今天');
this.song();
}
}
JS中return多个值时,前面的表达式也会执行,但只返回最后一个
function fn(){
let a=2;
let b=3;
return a++, a*b, a+b
}
console.log(fn())
执行顺序的时候,先执行a++,再执行a*b,最后执行并返回a+b的值