JS 学习笔记

Sherry 发布于 2025-03-27 54 次阅读 文章 最后更新于 2025-03-27 8216 字



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方法
})()

JavaScript常用的Hook脚本-CSDN博客

一般混淆后的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等
  • 代码混淆:变量混淆、常量混淆、控制流扁平化、调试保护等

加密实现

  1. eval加密(将js代码当作eval的参数进行执行)
  2. Emscripten
  3. 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相关逻辑
  • 分析加密
  • 补全加密逻辑
  1. 样例一:
    遇到混淆代码可以通过xhr断点,或者查看发起者,之后在通过堆栈来分析出混淆解除之后的代码,遇到一些无厘头的加密(例如颜文字),可以通过删除最后一个表情之后进行控制台输出从而达到解混淆,或者删除最后一个表情后加上toString()方法来输出字符串。

  2. 样例二:

    两行代码完全等价

  3. 样例三:

  4. 样例四:

  5. 样例五: