tags:
- js编程
- 前端
created: 2024-05-22
[!tip]
弱类型语言,严格区分大小写
引入JS
内部引用
<script>
alert("hello,world");
<script>
外部引用
<script src="JavaScript/texthello.js"></script>
弹窗
alert()
数据类型
快速入门
[!tip]
变量
所有变量生成都是var 变量名 = 变量值[!note]
number(js不区分小数跟整数)
123 //整数
123.1 //浮点数
1.123e3 //科学计数法
-99 //负数
NaN //not a number
Infinity //表示无限大
[!note]
字符串
'abc'
[!note]
布尔值
true,false
[!note]
逻辑运算
&& 两个都为真,结果为真
|| 一个为真,结果为真
!真即假,假即真
[!note]
比较运算符 (js中坚持使用= = = 来判断)
= 赋值
== 等于(类型不一样,值一样,也会判断为true)
=== 绝对等于(类型一样,值一样,结果true)
须知
- (NaN= = =NaN 与所有的数值都不想等,包括自己)
- 只能用过isNaN(NaN)来判断这个数是否是NaN
浮点数问题:
conso1e.1og((1/3)===(1-2/3))
尽量避免使用浮点数进行运算,存在精度问题!
Math.abs(1/3-(1-2/3))<0.00000001
[!note]
null和undefined
- null 空
- undefined 未定义
[!note]
数组(超坐标显示undefined)
var arr [1,2,3,4,5,'hello',null,true]
[!note]
对象(对象是大括号,数组是中括号,每个属性中间使用逗号隔开)
var person{
name:"qinjiang",
age:18,
tags:['js','java','web','...']
}
取对象的值
person.name
>"qinjiang
person.age
>3
严格检查模式
[!tip]
局部变量建议都是用 let 定义
'use strict' //开头加入,必须写在第一行
字符串
- 正常字符串我们使用单引号,或者双引号包裹
-
注意转义字符\
'
\n
\t
\u#### Unicode字符
\x41 Ascii字符
- 多行字符串编写
var str = ` //飘号键
nihao
你好
`
- 模板字符串
let name = 'Sherry';
let age = 18
let msg = `你好呀!${name}` //模板
- 字符串长度
console.log(str.length)
-
字符串可变性,不可变
-
字符串大小写转化
//这里是方法不是属性
console.log(student.toUppercase())
console.log(student.toLowercase())
- 获取字符所在位置
console.log(student.indexOf('str'))
- 截取字符串
console.log(student.subString(m,n))
数组
-
Array可以包含任意的数据类型
-
数组长度
array.length
//注意:加入给array.length赋值,数组大小就会发生变化,如果赋值过小,元素就会丢失
- 获取对应元素索引
array.indexOf(x)
- 截取数组
array.slice(m,n) //返回一个新数组,类似subString
- 放入抛出元素
array.push(x) //压入到尾部
array.pop(x) //弹出尾部的一个元素
array.unshift(x) //往头部添加元素
array.shift(x) //弹出头部的一个元素
- 排序数组
array.sort()
- 元素反转
array.reverse()
- 拼接数组
array.concat([1,2,3]) //返回一个新数组,并没有修改数组
- 添加连接符
array.join('-') //参数为连接符
- 多维数组
array=[[1,2],[3,4],["5","6"]]
对象
[!tip]
js中所有的键都是字符串,值是任意类型
- 若干个键值对
var person{
name:"Sherry",
age:18,
emai1:"3193871709@qq.com"
}
- 使用一个不存在的对象属性,不会报错!
-
动态删减属性
delete person.name
- 动态的添加
person.score = 99
- 判断属性值是否在这个对象中!
'age' in person
//继承
'toString' in person
- 判断一个属性是否是这个对象自身拥有hasOwnProperty()
person.hasownProperty('tostring')
false
person.hasownProperty('age)
true
- 合并对象
v1={"k1":123}
v2={k2:99,k3:888}
objects.assign(v1,v2)
conso1e.1og(v1) //{k1:123,k2:99,k3:888}
流程控制
- if判断
var age 3;
if(age>3){ //第一个判断
alert("haha");
}e1se if(age<5){ //第二个判断
alert("kuwa");
e1se{ //否则
alert("kuwa~);
}
- while循环
while(age<100){
age age 1;
console.log(age)
}
do{
age age 1;
console.log(age)
}while(age<100)
- for循环
for(1eti=0;i<100;i++){
console.log(i)
}
- forEach循环
age.forEach(function(value){
consoLe.log(value)
})
- for ... in
//for(var index in object){}
for(var num in age){
if (age.hasownProperty(num)){
conso1e.1og("存在")
console.log(age [num])
}
}
- for ... of
var arr [3,4,5]
for (var x of arr){
console.log(x)
}
Map和Set
ES6的新特性~
- Map用法
//Es6 Map
//学生的成绩,学生的名字
//var names=["tom","jack","haha"];
//var scores=[100,90,80];
var map new Map([['tom',100],[jack',90],['haha',80]]);
var name=map.get('tom');//通过key获得value
map.set('admin',123456);//新增或修改
map.delete('tom');//删除
console.log(name);
- set用法(无序不重复的集合)
var set = new Set([3,1,1,1,1]);//set可以去重
set.add(2);//添加
set.delete(1);//删除
console.log(set.has(3));//判断是否存在元素
iterator
- 遍历map
var map new Map([["tom",100],["jack",90],["haha",80]]);
for (let x of map){
console.log(x)
}
- 遍历set
var set new set([5,6,7]);
for (let x of set){
console.log(x)
}
函数
定义函数
[!note]
定义方式一
function 函数名(参数){
函数体;
}
一旦执行到return代表函数结束,返回结果!
[!note]
定义方式二
var 函数名 = function(参数){
函数体;
}
function(参数){...}这是一个匿名函数。但是可以把结果赋值出来
[!tip]
方式一和方式二等价!
[!note]
定义方式三(es6)
const test2 = () => {
console.log("Sherry")
}
[!note]
规避不存在参数
var abs function(x){
//手动抛出异常来判断
if (typeof x!=='number')
throw 'Not a Number';
if(x>=8){
return X;
}else{
return -X;
}
}
[!note]
参数多个处理,arguments是一个)S免费赠送的关键字。arguments代表传递进来的所有参数是一个列表
var abs function(x){
console.log("x=>"+x);
for (var i=0;i<arguments.length;i++){
console.log(arguments [i]);
}
if(X>=0){
return X;
}elsef
return -X;
}
}
[!tip]
问题:arguments包含所有的参数,我们有时候想使用多余的参数来进行附加操作。需要排除已有参数
rest获取除了已经定义的参数之外的所有参数·
function aaa(a,b,...rest){
console.log("a=>"+a);
console.log("b=>"+b);
console.log(rest);
}
rest参数只能写在最后面,必须用...标识。
变量作用域
[!note]
假设在函数体中声明,则在函数体外不可以使用~(非要想实现的话,后面可以研究一下闭包)
function Sherry(){
var x 1;
X=X+1;
}
x = x + 2;
//Uncaught ReferenceError:x is not defined
[!note]
如果两个函数使用了相同的变量名,只要在函数内部,就不冲突
function Sherry(){
var x 1;
X=X+1;
}
function Sherry2(){
var x ='A';
X=X+1;
}
[!note]
内部函数可以访问外部函数的成员,反之则不行
function Sherry(){
var x 1;
//内部函数可以访问外部函数的成员,反之则不行
function Sherry2(){
var y x +1;/2
}
var z y 1;
//Uncaught ReferenceError:y is not defined
}
[!note]
假设,内部函数变量和外部函数的变量,重名!
假设在javaScript中函数查找变量从自身函数开始~,由"内"向"外查找,假设外部存在这个同名的函数变量,则内部函数会屏蔽外部函数的[!note]
提升变量的作用域
function Sherry(){
var x = "x"+y;
console.log(x);
var y = "y";
}
结果:xundefired
说明:js执行引擎,自动提升了y的声明,但不会提升y的赋值
function Sherry2()
var y;
var x ="x"+y;
console.log(x);
y ='y';
}
[!tip]
这个是在avaScript建立之初就存在的特性。养成规范:所有的变量定义都放在函数的头部,不要乱放,便于代码维护:
function Sherry2()
var x=1,
y=X+1,
z,i,a;//undefined
//之后随意用
}
[!note]
全局函数
//全局变量
X=1;
function f()
console.log(x);
}
f();
console.log(x);
[!note]
全局对象window(window代表浏览器)
var x ='XXX';
alert(x);
alert(window.x);
//默认所有的全局变量,都会自动绑定在window对象下;
alert()这个函数本身也是window对象
var x ='XXX';
window.alert(x);
var old_alert window.alert;
//old_alert(x);
window.alert function {
};
//发现a1ert()失效了
window.alert(123);
//恢复
window.alert old_alert;
window.alert(456);
Javascript实际上只有一个全局作用域,任何变量(函数也可以视为变量),假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域都没有找到,报错RefrenceError引用异常
[!note]
规范
由于我们所有的全局变量都会绑定到我们的window上。如果不同的s文件,使用了相同的全局变量,冲突~>如果能够减少冲突?
//唯一全局变量
var SherryApp ={
//定义全局变量
SherryApp.name ='Sherry';
SherryApp.add function (a,b){
return a b;
}
把自己的代码全部放入自己定义的唯一空间名字中,降低全局命名冲突的问题
[!note]
局部作用域 let
function aaa(){
for (var i=0;i<100;i++){
console.log(i);
conso1e.1og(i+1);//问题?i出了这个作用域还可以使用
aaa();
}
解决问题
function aaa(){
for (let i=0;i<100;i++){
console.log(i);
conso1e.1og(i+1);//改成let申明,即可变成局部变量
aaa();
}
[!note]
常量 const
const PI = 3.14 //只读变量
console.log(PI)
方法
[!note]
定义方法
方法就是把函数放在对象的里面,对象只有两个乐西:属性和方法
var Sherry={
name:'白鸽',
bitrh:2020,
//方法
age:function(){
//今年-出生的年
var now = new Date().getFullYear();
return now-this.bitrh;
}
}
Sherry.age()
拆开
function getAge(){
//今年-出生的年
var now = new Date().getFullYear();
return now-this.bitrh;
}
var Sherry = {
name:'白鸽',
bitrh:2000,
age:getAge
}
//kuangshen.age()ok
//getAge() NaN window
[!note]
控制this指向 apply(所有函数都有)
getAge.apply(Sherry,[])
//this指向Sherry对象,参数为空
对象
对象定义
let obj={x:100,y:200,z:300}
//本质是
let obj={'x':100,'y':200,'z':300}
//变量做键
let obj9={'xy':100,[b]:200,'z':300,};
属性遍历
Let obj={x:100,y:200,z:300};
for (const objKey in obj)
console.Log(objKey);
}
//输出x y z
对象方法定义
function test(){
console.lLog("Sherry");
return 100;
}
console.Log(test);
console.Log(test());
let obj={x:100,y:200,z:300,s:test}
obj.s() //调用
//匿名函数使用
let obj={x:100,y:200,z:300,s:function(){
return 0;
}}
//简化写法(属性名和值一样时)
//这里的s是方法相当于s:s
function s(){
console.log("Sherry");
return 100;
}
let obj={x:100,y:200,z:300,s}
//更简化方法
let x 100;
let obj ={
x,
y:200,Z:300,
test (a){ //相当于test:function(a){
console.log("Sherry "a);
return 100;
}
}
Date
标准对象
typeof 123
"number"
typeof '123'
"string"
typeof true
"boolean"
typeof NaN
"number"
typeof []
"object"
typeof {}
"object"
typeof Math.abs
"function"
获取当前时间
var now = new Date()
//resFunc {_innerDate: Wed May 29 2024 20:38:13 GMT+0800 (中国标准时间)}
基本使用
获取当前年份,月份,日,时,分,秒,星期几,时间戳
now.getFullYear();//年份
now.getMonth();//月份(0~11)
now.getDay(); //星期几
now.getHours();//时
now.getMinutes();//分
now.getSeconds();//秒
now.getTime();//时间戳
转换
console.1og(new Date(时间戳))//时间戳转为时间
now.toLocaleString()
//"2020/1/4上午10:49:35"
now.toGMTString()
//"sat,04Jan202002:49:35GMT"
Json
[!note]
在到JavaScript一切皆为对象、任何js支持的类型都可以用JSON来表示,
格式:
- 对象都用{}
- 数组都用[]
- 所有的键值对都是用key:value
转换
var user = {
name:"Sherry",
age:3,
sex:"男'
}
//对象转化为Json字符串{"name":"Sherry","age":3,"sex":"男"}
var jsonUser JSON.stringify(user);
//Json字符串转化为对象,参数为json字符串
var obj JSON.parse('{"name":"qinjiang","age":3,"sex":""}')
Ajax
- 原生的js写法xhr异步请求
- jQuey封装好的方法$("#name").ajax(" ")
- axios请求
调试
浏览器控制台中进行调试
控制台打印
console.log()
断点调试操作
面向对象编程
- 类:模板原型对象
- 对象:具体的实例
[!note]
原型继承
var user = {
name = "白鸽",
age=3,
run:function(){
console.log(this.name+"run...")
}
}
var Sherry = {
name = "Sherry",
}
Sherry.__proto__ = user //Sherry原型为user
[!note]
class继承
//定义一个学胜的类
class Student{
constructor(name){ //构造器
this.namename;
}
hello(){
alert('hello')
}
}
//定义一个学生的类
class Student{
constructor(name){ //构造器
this.name = name;
he11o(){
alert('hello')
}
}
}
class XiaoStudent extends Student{
constructor(name,grade){
super(name);
this.grade = grade;
myGrade(){
alert(T我是一名小学生')
}
}
var xigoming new Student("xiaoming");
var xigohong new XiaoStudent("xiaohong",1);
操作BOM对象(重点)
BOM:浏览器对象模型
window 对象
window 代表 浏览器窗口
[!note]
获取内部高宽和外部高宽
window.innerHeight(内部高度)
258
window.innerwidth(内部宽度)
919
window.outerHeight(外部高度)
994
window.outerwidth(外部宽度)
919
Navigator
Navigator,封装了浏览器的信息,父类是window
[!note]
浏览器信息获取
navigator.appName
"Netscape"
navigator.appVersion
"5.0 (Windows NT 10.0;Wow64)Applewebkit/537.36 (KHTML,like Gecko)Chrome/63.0.3239.132 Safari/537.36"
navigator.userAgent
"Mozilla/5.0 (windows NT 10.0;Wow64)Applewebkit/537.36 (KHTML,likeGecko)chrome/63.0.3239.132 Safari/537.36"
navigator.platform
"win32"
大多数时候,我们不会使用navigator对象,因为会被人人为修改
screen
屏幕信息
[!note]
获取屏幕宽高
screen.width
1920
screen.height
1080
location (重要)
location代表当前页面的URL信息
[!note]
获取当前页面URL信息
//以下为重点信息
//主机
host:"www.baidu.com"
//当前指向位置
href:"https://www.baidu.com/"
//协议
protocol "https:
//重新加载(刷新网页)
reload:f reload()
//设置新的地址
location.assign ('https://blog.kuangstudy.com/')
//刷新页面
location.reload();
document
document 代表当前页面,HTML DOM文档树
[!note]
获取设置title
//设置title
document.title
"百度一下,你就知道”
document.title='狂神说'
"狂神说"
[!note]
获取具体的文档树节点
<dl id="app">
<dt>Java</dt>
<dd>JavaSE</dd>
<dd>JavaEE</dd>
</d1>
<script>
var dl = document.getElementById('app');
</script>
[!note]
获取网页cookie
document.cookie
"__guid=111872281.88375976493059340.1578110638877.133;monit0r_count=1"
[!note]
劫持cookie原理
<script src = "aa.js"><script>
<!--恶意人员:获取你的cookie上传到他的服务器~-->
服务器端可以设置cookie:httpOnly
history
代表浏览器历史记录
[!note]
网页前进后退
history.back() //后退
history.forward() //前进
DOM对象(重点)
DOM:文档对象模型
[!tip]
核心:浏览器网页就是一个Dom树形结构!
- 更新:更新Dom节点
- 遍历dom节点:得到Dom节点
- 删除:删除一个Dom节点
- 添加:添加一个新的节点
操作节点
//对应css选择器
var h1 = document.getElementsByTagName('h1');
var p1 = document.getElementById('p1');
var p2 = document.getElementsByClassName('p2');
var documenttest = document.getElementsByClassName('documenttest');
//获取父节点下的所有子节点
var childrens= documenttest.children[index];
//获取父节点
var 父节点 = 子节点.parentElement;
// documenttest.firstChildren
// documenttest.lastChildren
更新节点
//转驼峰命名问题,属性使用字符串
//更新节点文本内容
名.innerText="content"
//更新节点超文本
名.innerHTML='<strong>123</strong>'
//更新节点样式
名.style.样式名 ='content'
删除节点
删除节点的步骤:先获取父节点,在通过父节点删除自己
父节点.remove(子节点)
//删除是一个动态过程
father.removechild(father.children [0])
注意:删除多个节点的时候,children是在时刻变化的,删除节点的时候一定要注意!
创建和插入节点
我们获得了某个DOM节点,假设这个dom节点是空的,我们通过innerHTML就可以增加一个元素了,但是这个DOM节点已经存在元素了,我们就不能这么干了!会产生覆盖!
[!note]
插入和追加
<p id="js">Javascript</p>
<div id="list">
<p id="se">JavaSE</p>
<p id="ee">JavaEE</p>
<p id="me">JavaME</p>
</div>
<script>
var js document.getElementById('js');
var list document.getElementById('list);
//追加到后面
list.appendChild(js)
</script>
//插入到后面
var ee document.getElementById('ee');
var js document.getElementById('js');
var list document.getElementById('list');
//要包含的节点.insertBefore(newNode,targetNode)
list.insertBefore(js,ee);
[!note]
创建
//创建一个p标签
var newp=document.createElement('p');
//.属性
newp.id 'newP';
newP.innerText 'Hello,Sherry';
//创建一个标签节点
var myScript document.createElement('script');
//设置属性
myScript.setAttribute('type','text/javascript')
//可以创建一个sty1e标签
var mystyle=document.createElement('style');//创建了一个空style标签
mystyle.setAttribute('type','text/css'):
mystyle.innerHTML='body{background-color:chartreuse;}';//设置标签内容
document.getElementsByTagName('head'[0].appendChild(mystyle)
、
操作表单
[!note]
获得提交信息
<form action="post">
<p>
<span>用户名:</span><inputtype="text"id="username">
</p>
<!--多选框的值,就是定义好的va1ue-->
<p>
<span>性别:</span>
<input type="radio"name="sex"value="man"id="boy">
<input type="radio"name="sex"value="women"id="girl">
</p>
</form>
<script>
var input_text = document.getElementById('username');
var boy_radio = document.getElementById('boy');
var girl_radio = document.getElementById('girl')
//得到输入框的值
input_text.value
//修改输入框的值
input_text.value ='123'
//对于单选框,多选框等等固定的值,boy_radio.value只能取到当前的值
boy_radio.checked;//查看返回的结果,是否为true,如果为true,则被选中~
girl_radio.checked=true;//赋值
</script>
[!note]
提交表单
//表单绑定事件
onsubmit = "return fun()"
//按钮提交事件
onclick = "fun()"
jQuery
[!tip]
公式:$('selecton').action()
[!note]
获取jQuery
<!--CDN引用-->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
//例子
//选择器就是css的选贼器
$('#test-jquery').click(function (){
alert('hello,jQuery');
})
jQuery事件
[!tip]
当网页元素加截完华之后,响应事件
//初始
$(document).ready(function (){
}
)
//简化
$(function(){
})
[!note]
鼠标事件
//单击
click()
//双击
dblclick()
//当鼠标指针穿过元素时,会发生 mouseenter 事件。
mouseenter()
//当鼠标指针离开元素时,会发生 mouseleave 事件。
mouseleave()
//当鼠标指针移动到元素上方,并按下鼠标按键时,会发生 mousedown 事件。
mousedown()
//当在元素上松开鼠标按钮时,会发生 mouseup 事件。
mouseup()
//悬停
hover()
[!note]
键盘事件
//键被按下
keypress()
//键按下的过程
keydown()
//键被松开
keyup()
[!note]
表单事件
//提交
submit()
//当元素获得焦点时,发生 focus 事件。
focus()
//当元素失去焦点时,发生 blur 事件。
blur()
操作DOM元素
[!note]
设置文字
//获取坐标
$('#mouseMove').text('x:'+e.pageX 'y:'+e.pageY);
[!note]
设置HTML
//使用属性
$('#id').html();
[!note]
设置CSS
//参数为键值对
$('#id').css({"key" :"value"})
//示例
$(document).ready(function (){
$("#p1").click(function (){
$("#p1").css({"color":"red"})
})
});
[!note]
显示和隐藏 (本质:display:none;)
//显示
$('#id').show()
//隐藏
$('#id').hide()
//切换(显示就是隐藏,隐藏就是显示)
$('#id').toggle();
[!note]
宽度和高度
$('#id').width()
$('#id').height()
[!note]
创建标签
$("<标签>")
[!note]
插入
//追加
$('#id').append()
//前插入
$('#id').before()
//后插入
$('#id').after()
[!note]
移除
$('#id').remove()
[!note]
添加标签
$("#view").append(newLi);
样式操作
- addClass
- removeClass
- hasClass
值操作
JS逆向
程序调试
函数调用栈先进后出
String的常用方法
[!tip]
对于对象进行操作
[!note]
获取字符
let str="Sherry";
console.log(str.charAt(2))
//e
[!note]
拼接字符
let str="Sherry";
let str1="Baige";
console.log(str.concat(str1))
//SherryBaige
[!note]
判断以什么字符开头或以什么字符结尾(返回布尔)
let str="Sherry";
console.log(str.startWith("Sh"))
console.log(str.endWith("ry"))
//true
//true
[!note]
搜索字符串首次出现位置或从后搜索
let str="Sherry";
console.log(str.indexOf("r"))
console.log(str.lastIndexOf("r"))
//3
//4
[!note]
判断是否包含字符(返回布尔)
let str="Sherry";
console.log(str.includes("S"))
//true
[!note]
对字符串进行格式化填充或从后往前填充
let str1="7";
let str2="17";
let str3="117";
console.log(str1.padStart(3,'0'));
console.log(str2.padStart(3,'0'));
console.log(str3.padStart(3,'0'));
console.log(str1.padEnd(3,'0'));
//007
//017
//117
//700
[!note]
重复字符串
let str="Sherry";
console.log(str.repeat(3))
//SherrySherrySherry
[!note]
分割字符串(起始,结束),不写结尾截取到最后
let str="Sherry";
console.log(str.slice(2,4))
//err
[!note]
截取字符串
let str="Sherry";
//从第四位开始截取两位
console.log(str.substr(4,2))
//ry
[!note]
截取字符串(从什么地方取到哪里截止,不包括截止)
let str="Sherry";
console.log(str.substring(3,5))
//rr
[!note]
转小写和转大写
let str="Sherry";
console.log(str.toLowerCase())
console.log(str.toUpperCase())
//sherry
//SHERRY
[!note]
删除前后空格,去掉前空格,去掉后空格
let str=" Sherry ";
console.log(str.trim())
console.log(str.trimStart())
console.log(str.trimEnd())
//Sherry
//Sherry
// Sherry
[!note]
转字符串
let str="Sherry";
console.log(str.toString())
//Sherry
正则表达式
[!tip]
创建正则表达式
//第一个参数是规则,第二个是模式
let reg = new RegExp("Sherry","i");
let reg = /Sherry/i
语法 | 描述 |
---|---|
i | 忽略大小写 |
m | 多行匹配 |
g | 全局匹配 |
s | dotAll模式,该模式下元字符,可以匹配换行 |
规则 | 描述 |
---|---|
字符类 | |
[abc] | 匹配 a、b 或 c 中的任意一个字符。 |
[^abc] | 匹配除了 a、b、c 之外的任意字符。 |
[a-z] | 匹配从 a 到 z 之间的任意一个小写字母。 |
[A-Z] | 匹配从 A 到 Z 之间的任意一个大写字母。 |
[0-9] | 匹配从 0 到 9 之间的任意一个数字。 |
元字符 | |
. | 匹配除了换行符之外的任意一个字符。 |
^ | 匹配输入字符串的开始位置。 |
$ | 匹配输入字符串的结束位置。 |
* | 匹配前面的表达式零次或多次。 |
+ | 匹配前面的表达式一次或多次。 |
? | 匹配前面的表达式零次或一次。 |
| | 用于匹配多个表达式中的一个。 |
() | 用于捕获分组。 |
限定符 | |
* | 匹配前面的表达式零次或多次。 |
+ | 匹配前面的表达式一次或多次。 |
? | 匹配前面的表达式零次或一次。 |
{n} | 匹配前面的表达式恰好 n 次。 |
{n,} | 匹配前面的表达式至少 n 次。 |
{n,m} | 匹配前面的表达式至少 n 次,但不超过 m 次。 |
转义字符 | |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\w | 匹配一个字母数字字符。等价于 [a-zA-Z0-9_]。 |
\s | 匹配一个空白字符,包括空格、制表符、换行符等。 |
. | 匹配一个点字符。 |
[!note]
简单使用
reg.test (str);
//检查Str是否符合规则,返回布尔值
reg.exec(str);
//获取str中第一个符合规则的内容
[!note]
通过多次循环,使用全局匹配,得到所有匹配内容
let str="a13123xia0j6554654ian456ba000ng879879";
let reg=/\d+/ig;
let retval=null;
while (retval=reg.exec(str)){
console.log(retval);
}
正则进阶
[!note]
万能匹配:
.* ?
[\s\S]*?
[!note]
捕获和不捕获,反向引用子表达式
()
(?:)
\数字
[!note]
零宽断言
xxx(?=.) 匹配的字符以..结尾,但是匹配结果里不包含
(?<=...)xxx 匹配的字符以..开头,但是匹配结果里不包含
[!note]
获取指定分组内容
let str='<a href="http://Sherry.vip">Sherry</a>';
const reg = /<a href="(?<url>.*?)">(?<text>.*?)<\/a>/;
const result = reg.exec(str);
console.log(result.groups.url);
console.log(result.groups.text);
//http://Sherry.vip
//Sherry
字符串的常用方法
[!note]
替换字符串(第一个参数支持正则),不然只替换一次
let str = "Sherry"
str.replace("err","aaa")
//Shaaay
[!note]
替换所有字符串
let str = "Sherry"
str.replaceAll("err","aaa")
[!note]
获取正则匹配结果
let str = "S111her43242342ry"
console.log(str.match(/\d+/g))
//[ '111', '43242342' ]
[!note]
获取正则匹配结果,返回可迭代对象,很多属性(三个.是对可迭代对象进行展开操作)
let str = "S111her43242342ry"
console.log(...str.matchAll(/\d+/g))
//[ '111', index: 1, input: 'S111her43242342ry', groups: undefined ] [ '43242342', index: 7, input: 'S111her43242342ry', groups: undefined ]
[!note]
获取字符串下标(可使用正则)
let str = "S111her43242342ry"
console.log(str.search(/\d+/g))
//1
[!note]
分割字符串(返回数组,不包含分割字符,可使用正则)
let str = "S111her43242342ry"; console.log(str.split(/\d/g))
//[
// 'S', '', '', 'her',
// '', '', '', '',
// '', '', '', 'ry'
//]
[!note]
获取字符Ascii码
let str = "Sherry" ;
for (let i = 0; i < str.length; i++) {
console.log(str.charCodeAt(i))
}
//53
//104
//101
//114
//114
//121
[!note]
Ascii转字符
let str = String.fromCharCode(53,104,101,114,114,121)
console.log(str)
//5herry
内置函数
[!note]
URL编码
console.log(encodeURIComponent("白鸽"))
//%E7%99%BD%E9%B8%BD
[!note]
Unicode编码
console.log(escape("白鸽"))
//%u767D%u9E3D
[!note]
转整数
console.log(parseInt("12323.5"));
//12323
[!note]
转小数
console.log(parseFloat("12323.5"));
//12323.5
[!note]
判断类型是否是NaN
console.log(isNaN("100.5"));
//false
[!note]
判断类型是否是有限数值
console.log(isFinite("100.5"));
//true
[!note]
判断类型是否是有限数值
console.log(Number.isInteger(100));
//true
模块化编程
[!note]
别人导入你的代码需要将你的变量以及函数进行导出
export function fun(){}
[!note]
导入(导入所有,取个别名叫fun)
import * as mm from "./demo.js"
mm.fun() //调用
[!note]
统一导出
let str = "Sherry";
function func(){
return str;
}
export {str,func};
[!note]
默认导出
let str "Sherry";
function func(){
return str;
}
export default{
xx:str,
yy:func
}
//使用
import * as mm from "./demo.js"
console.log(mm.default.xx)
console.log(mm.default.yy())
[!note]
default结构
let str "Sherry";
function func(){
return str;
}
export default{
xx:str,
yy:func
}
//使用
import {default as ss} from "./demo.js"
console.log(ss.yy());
[!note]
解构(也可以起别名)
import {str,func} from "./demo.js"
import {func as yy} from "./demo.js"
console.log(func());
console.log(yy());
[!note]
动态导入(then的意思是,等导包完毕在执行后面)
let x=200;
if(x===100){
import('./demo.js').then(module => {
module.func();
});
}
事件循环
原型链
[!tip]
每个函数都有一个prototype属性,这个属性指向原型对象,每个new出来的对象都有一个 _ _ proto _ _ 属性指向这个对象的原型,每个原型都有一个constructor属性指向该关联的构造函数,当读取实例的属性时,如果找不到就会查找与对象关联的原型中的属性,如果还查不到就会找原型的原型,一次类推
浏览器储存
储存方式 | 作用 | 储存大小与储存内容 |
---|---|---|
Cookies | 主要用于与服务端通信 | 储存量小 |
Local Storage | 储存量相较于Cookies更大 | 只能储存字符串 |
Session Storage | 只存在与当前Session,关闭浏览器就丢失了 | 其他与Local Storage一样 |
IndexedDB | 相当于浏览器上的SQL数据库 | 更大的储存空间 |
跨域
自执行
!function(){ //函数前加!
}();
(function(){ //整个函数括起来
}())
简易后台的搭建
[!tip]
步骤:
//1.express框架的安装
//先安装Node.js
//再运行npm i express
//2.后台代码基本框架
//引入模块
import express from 'express';
//创建应用对象
const app = express();
//创建路由规则
app.all('/register',(request,response)=>{
console.log(request.url);
//设置响应
response.setHeader('Access-Controll-Allow-Origin','*'); //允许跨域请求
response.send('register success');
});
//监听端口,启动服务
app.listen(8080,()=>{
console.log("后台启动完毕,监听在8080端口")
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sherry的测试案例</title>
<style>
*{
margin:0;
padding:0;
}
body{
position: relative;
height: 1000px;
}
#main{
position: absolute;
top: 300px;
left: 45%;
}
</style>
</head>
<body>
<div id="main">
<form action="http://Localhost:8080/register" method="get">
用户名:<input type="text" name="username" placeholder="请输入您的用户名" >
<br>
<span style="margin-right: 16px">密</span>码:<input type="password" name="pass" placeholder="请输入您的密码" maxlength="15">
<br>
性别:
<label><input type="radio" id="man" name="sex" value="man">男</label>
<input type="radio" id="women" name="sex" value="women"><label for="women">女</label>
<br>
兴趣:
<label><input type="checkbox" name="interest" value="chang">唱</label>
<label> <input type="checkbox" name="interest" value="tiao">跳</label>
<label><input type="checkbox" name="interest" value="rap">rap</label>
<br>
<input type="submit" value="提交">
</form>
</div>
</body>
</html>
Python调用JS
[!tip]
调用库
- PyV8
- Js2Py
- PyExecJS
- PyminiRacer
- Selenium
- Pyppeteer
PyExecJS使用
import execjs
print(execjs.get().name) #查看调用环境
#Node.js (V8)
[!note]
直接执行js
import execjs
e = execjs.eval('a=new Array(1,2,3)') #可以直接执行js
[!note]
编译js使用
import execjs
jstext = '''
function hello(str){return str;}
'''
ctx = execjs.compile(jstext) #编译js代码
a = ctx.call("hello","hello world!") #前面函数,后面参数
print(a)
问题:执行大型JS时会有点慢,特殊编码的输入或输出参数会出现报错的情况
Selenium使用
js = 'js代码'
result = browser.execute_script(js)
Pyppeteer使用
async def run():
browser = await launch({"headless":True})
page = await browser.newPage()
await page.goto('http://127.0.0.1:5002/')
script = get_text("base64","data")
text = await page.evaluate(script)
print(text)
return text
if name=='main_':
loop asyncio.get_event_loop()
loop.run_until_complete(run())
[!note]
页面加载前调用JS
result await page.evaluateOnNewDocument(js,*data)
开发者工具
网络面板
筛选域名 domain
筛选返回状态码 ststus-code
筛选set-cookie-domain
Sources面板
Console面板
骚操作
console.table将数据以表格形式展现
copy方法赋值,直接将值放在剪贴板上
$_ 打印最后一次计算的结果
$('')筛选DOM节点
$ $('')返回数组
$x(xpath)获取xpath内容
Hook
[!tip]
通用Hook
//==UserScript==
//@name HookBase64
//@namespace 生效域名
//@version 0.1
//@description 通用Hook
//@author Sherry
//@match 生效域名
//@grant none
//==/UserScript==
(function (){
'use strict'
function hook(object,attr){
var func = object[attr]
object[attr] = function (){
console.log('hooked',object,attr)
var ret func.apply(object,arguments)
debugger
return ret
}
}
hook(window,'btoa') //Hook对象,Hook方法
})()
一般混淆后的JS代码可以通过添加ajax断点来进行找到入口
[!note]
base64加密
window.btoa()
JS 注入 Hook
var my_parse = JSON.parse:
JSON.parse = function(params){
console.log("json_parse params:",params):
debugger
return my_parse(params);
};
查看上一条堆栈,定位解密函数
无线debugger处理
- 禁用所有断点
- 禁用某处断点
- 条件断点
- 中间人工具替换特征字符串
- reres替换本地修改过的文件
- 重写关键函数(未执行的时候)
- Function.prototype.constructor = function(){ }
必须在(function(){ }).constructor = Function 成立情况下生效 -
遇到自执行,将他置空后重新打开开发者工具
- eval是不是native'函数
快速定位加密参数生成代码
快速定位之搜索
- 中间人的全局搜索
- 开发者工具的全局搜索
快速定位之断点
- XHR
- DOM
- EVENT(事件断点)
- 自定义
快速定位之hook
[!tip]
注入时机:可以给script下断点,在加载JS代码的时候进行注入
- json
var my_stringify = JSON.stringify;
JSON.stringify = function (params){
console.log("Sherry",params);
return my_stringify(params);
};
var my_parse = JSON.parse;
JSON.parse = function (params){
console.log("Sherry",params);
return my_parse(params);
};
- cookie
var cookie_cache = document.cookie;
Object.defineProperty(document,'cookie',{
get:function(){
console.log('Getting cookie');
return cookie_cache;
},
set:function(val){
console.log('Setting cookie',val);
var cookie = val.split(";")[0];
var ncookie = cookie.split("=");
var flag = false;
var cache = cookie_cache.split(";")
cache = cache.map(function(a){
if (a.split("=")[0]===ncookie[0]){
flag = true;
return cookie;
}
return a;
})
cookie_cache = cache.join("; ");
if (!flag){
cookie_cache += cookie + "; ";
}
this.value = val;
return cookie_cache;
},
});
- window attr
var window_flag_1 ='t'; //window属性
var window_flag_2 ='ccc'; //window属性的属性
var key_value_map ={}
var window_value = window[window_flag_1];
Object.defineProperty(window,window_flag_1,{
get:function(){
console.log('Getting',window,window_flag_1,'=',window_value);
//debugger;
return window_value;
},
set:function(val){
console.log('Setting',window,window_flag_1,'=',val);
//debugger;
window_value = val;
key_value_map[window[window_flag_1]] = window_flag_1;
set_obj_attr(window[window_flag_1],window_flag_2);
},
});
function set_obj_attr(obj,attr){
var obj_attr_value = obj[attr];
Object.defineProperty(obj,attr,{
get:function(){
console.log('Getting',key_value_map[obj],attr,'=',obj_attr_value);
//debugger;
return obj_attr_value;
},
set:function(val){
console.log('Setting',key_value_map[obj],attr,'=',val);
//debugger;
obj_attr_value = val;
},
});
}
- eval/Function
window.__cr_eval = window.eval
var myeval = function (src){
console.log(src);
console.log("============ eval end ================")
return window.__cr_eval(src)
}
var _myeval = myeval.bind(null)
_myeval.tostring = window.__cr_eval.toString
Object.defineProperty(window,'eval',{value:_myeval })
window.__cr_fun = window.Function
var myfun = function (){
var args = Array.prototype.slice.call(arguments,0,-1).join(","),src = arguments[arguments.length -1]
console.log(src);
console.log("===========Function end==========")
return window.__cr_fun.apply(this,arguments)
}
myfun.tostring = function(){return window.__cr_fun+""}//小花招
Object.defineProperty(window,'Function',{value:myfun })
- websocket
WebSocket.prototype.senda = WebSocket.prototype.send;
WebSocket.prototype.send = function (data) {
console.info("Hook WebSocket", data);
return this.senda(data);
}
- and so on
快速定位之分析
- Elements Event Listeners(事件监听)
- Network type initator
- Console Log XMLHttpRequests(打印日志)
代码混淆
[!tip]
如何对JavaScript进行保护
- 代码压缩:去除空格、换行等
- 代码加密:eval、emscripten、NebAssembly等
- 代码混淆:变量混淆、常量混淆、控制流扁平化、调试保护等
加密实现
- eval加密(将js代码当作eval的参数进行执行)
- Emscripten
- WebAssembly
混淆技术
- 变量混淆
- 字符串混淆
- 属性加密
- 控制流平坦化
- 僵尸代码注入
- 代码压缩
- 反调试
- 多态变异
- 锁定域名
- 反格式化
- 特殊编码
混淆的开源项目:
- Uglify]S:https://qithub.com/mishoo/UglifylS2
- terser:https://github.com/terser/terser
- javascript-obfuscator(重点):https://github.com/javascript-obfuscator/javascript-obfuscator
- jsfuck:https://github.com/aemkei/jsfuck
- AAEncode:https://github.com/bprayudha/iquery.aaencode
- JEncode:https://github.com/ay86/jEncrypt
混淆的在线工具:
https://obfuscator.io/
https://www.sojson.com/jscodeconfusion.html
http://www.jshaman.com/protect.html
http://www.freejsobfuscator.com/
https://www.daftlogic.com/projects-online-javascript-obfuscator.htm
http://beautifytools.com/javascript-obfuscator.php
商业混淆服务:
https://javascriptobfuscator.com/
https://jscrambler.com/
http://stunnix.com/
混淆实现
混淆结果:
变量名混淆:
字符串混淆:
自我保护:
控制流平坦化:
僵尸代码注入:
- 僵尸代码:不会被执行的代码或对上下文没有任何影响的代码
- 注入之后可以对现有的JavaScript代码的阅读形成干扰。
对象键名替换:
禁用控制台输出:
调试保护:
域名锁定:
JSFUCK:
AAEncode:
JJEncode:
混淆代码处理
[!tip]
加密分析流程总结:
- 查看关键包-分析哪些参数是加密的
- 搜索参数
- 参数名=/参数名=/参数名:/参数名:
- 参数名
- 查看网络面板的Initiator(发起)
- xhr断点调试
- hook相关逻辑
- 分析加密
- 补全加密逻辑
-
样例一:
遇到混淆代码可以通过xhr断点,或者查看发起者,之后在通过堆栈来分析出混淆解除之后的代码,遇到一些无厘头的加密(例如颜文字),可以通过删除最后一个表情之后进行控制台输出从而达到解混淆,或者删除最后一个表情后加上toString()方法来输出字符串。
-
样例二:
两行代码完全等价
-
样例三:
-
样例四:
-
样例五:
Comments NOTHING