JavaScript基础
数据类型
数值型:number(凡是数字都是数值型,不区分整数和小数)
字符串:string(凡是引号包裹起来的内容全部都是字符串)
布尔:bool(true、false)
对象类型:object(特殊取值null)
未定义型:undefined
javascript一切皆对象
object对象
Date对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var now=new Date(); console.log(now.toLocaleString( ));
|
Math对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| var num = 100.3; var ret = num.toFixed(2); console.log(num); console.log(ret);
console.log( Math.abs(num) );
var num = 10.3; console.log( Math.ceil(num) );
var num = 10.3; console.log( Math.floor(num) );
console.log( Math.max(3,56,3) );
console.log(Math.pow(3, 2)); console.log( 3**2 );
console.log(Math.random());
console.log( Math.random() * 10 );
console.log( Math.round( Math.random() * 10 ) );
|
Function对象
任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。
局部变量,是在函数内部声明,它的生命周期在当前函数被调用的时候, 当函数调用完毕以后,则内存中自动销毁当前变量.
全局变量,是在函数外部声明,它的生命周期在当前文件中被声明以后就保存在内存中,直到当前文件执行完毕以后,才会被内存销毁掉。
1 2 3 4 5 6 7 8 9
| var name = "zhangsan"; name = "张三"; console.log(name);
age = 18
var gender = "man" var gender = "women" console.log(gender)
|
函数内部直接使用变量,则默认调用了全局的变量
使用变量的时候,解释器会在当前花括号范围值搜索是否有关键字var 或者 let 声明了变量,如果没有,则一层一层往外查找,如最终查找不到,则直接报错!
变量名 is not define!
1 2 3 4 5 6 7 8 9
| var num = 10; function func(){ num = 20; console.log("函数内部num:",num) } func(); console.log("全局num:",num);
|
匿名函数
匿名函数,即没有变量名的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| var foo = function () { console.log("这是一个匿名函数!") };
(function (x,y) { console.log(x+y); })(2,3)
function bar() {
return function () { console.log("inner函数!") } }
bar()()
|
闭包函数
闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量(外部非全局)的函数。
一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行。
分别编写两个js脚本,在运行时, 在同一html内执行。他们拥有相同的作用域。 此时的变量不安全,造成全局变量污染。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <script>
var key = "123456"
function foo(){ console.log(key) }
</script>
<script>
var key = "abcdefg"
function bar(){ console.log(key) }
</script>
|
1 2
| <script src="test01.js"></script> <script src="test02.js"></script>
|
在函数内和代码块内声明的变量,尤其是函数内。
声明出来的变量它是一个局部变量. 外界是无法进行访问的,即函数是可以开辟独立的作用域环境的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <script>
var f = (function () { let key = "123456"
function foo() { return key }
return foo })()
</script>
<script>
var b = (function () { let key = "abcdefg"
function bar() { return key }
return bar })()
</script>
|
1 2 3 4 5 6
| <script src="test01.js"></script> <script src="test02.js"></script> <script> console.log(f()) console.log(b()) </script>
|
prototype 原型对象
prototype(原型对象)就是一个容器,存放公共的方法给对象使用,对象可以直接访问原型对象中的方法和属性,类似Python的类对象
原型对象和函数之间的关系
每个函数都会有一个prototype
属性,指向原型对象.
每个原型对象都会有一个constructor
属性,指向函数.
总结:每个函数与原型对象之间的关系是互相引用
.
对象和原型对象和函数之间的关系
call和apply方法
call,apply都属于Function.prototype的一个方法,它是JavaScript引擎内在实现的,因为属于Function.prototype,所以每个Function对象实例(就是每个方法)都有call,apply属性。
1 2 3
| foo.call(this, arg1,arg2,arg3) foo.apply(this, arguments) this.foo(arg1, arg2, arg3);
|
window对象
window 是客户端浏览器对象模型的基类,window 对象是客户端 JavaScript 的全局对象。一个 window 对象实际上就是一个独立的窗口,对于框架页面来说,浏览器窗口每个框架都包含一个 window 对象。
在客户端浏览器中,window 对象是访问 BOM 的接口,如引用 document 对象的 document 属性,引用自身的 window 和 self 属性等。同时 window 也为客户端 JavaScript 提供全局作用域。
1 2 3 4 5 6 7 8 9 10 11
| <script>
var username = "yuanhao"; function f() { console.log(username); }
console.log(window.username); window.f();
</script>
|
window 对象定义了 3 个人机交互的方法
1 2 3
| alert() # 确定提示框 confirm() # 选择提示框 prompt() # 输入提示框
|
使用 window 对象可以访问客户端其他对象
- window:客户端 JavaScript 顶层对象。每当 或
- navigator:包含客户端有关浏览器信息。
- screen:包含客户端屏幕的信息。
- history:包含浏览器窗口访问过的 URL 信息。
- location:包含当前网页文档的 URL 信息。
- document:包含整个 HTML 文档,可被用来访问文档内容及其所有页面元素。
window 对象包含 4 个定时器专用方法
方法 |
说明 |
setInterval() |
按照执行的周期(单位为毫秒)调用函数或计算表达式 |
setTimeout() |
在指定的毫秒数后调用函数或计算表达式 |
clearInterval() |
取消由 setInterval() 方法生成的定时器 |
clearTimeout() |
取消由 setTimeout() 方法生成的定时器 |
ES6新语法
var、let以及const
ES6 中引入了关键字 let 和 const 作为 var 的替代。与关键字 var 不同,这两个关键字具有块作用域。在块中声明它们时,它们只能在该块 {} 内访问。
1 2 3 4 5 6 7 8 9 10
|
for (let i=0;i<10;i++){ console.log(i) } console.log(i)
|
实际运行的时候和我们写代码的顺序可能会不一样,把变量提前到代码块第一部分运行的逻辑被称为变量提升
1 2 3 4 5 6
| function fn(){ var name; console.log(name); name = 'yuan'; } fn()
|
ES6新语法用let就可以避免此问题,用let声明变量是新版本javascript提倡的一种声明变量的方案
1 2 3 4 5
| function fn(){ console.log(name); // 直接报错, let变量不可以变量提升. let name = 'yuan'; } fn()
|
箭头函数
ES6中简化了函数的声明语法
1 2 3 4 5 6 7 8 9 10 11 12
| var f = v => v var f = () => 5
var sum = (num1, num2) => num1 + num2
var sum = (num1, num2) => {return num1 + num2}
let getUser = id => {id: id, name: "zhang"}
let getUser = id => ({id: id, name: "zhang"})
|
1 2 3 4 5 6 7 8 9 10 11
| var f = function(v) { return v }
var f = function() { return 5 }
var sum = function(num1, num2) { return num1 + num2 }
|
对象简写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var name = "zhang" var age = 22
function run() { console.log(this.name + " running") }
p1 = { name, age, eat: function () { console.log(this.name + " is eating") }, run: run, }
p1.eat() p1.run()
|
ES6格式化
S6中允许使用反引号 ` 来创建字符串,
此种方法创建的字符串里面可以包含由美元符号加花括号包裹的变量 ${vraible}。
1 2
| var num = Math.random() console.log(`生成一个随机数:${num}`)
|
eval
eval() 函数计算 JavaScript 字符串,并把它作为脚本代码来执行。
如果参数是一个表达式,eval() 函数将执行表达式。如果参数是Javascript语句,eval()将执行 Javascript 语句。
1 2 3
| eval(string)
eval('[1,2,3,4,5].map(x=>x*x)')
|
http://tools.jb51.net/password/evalencode
Hook函数
在 JS 逆向中,我们通常把替换原函数的过程都称为 Hook。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function foo() { console.log("foo功能...") return 123 } foo()
var _foo = foo
foo = function () { console.log("截断开始...") debugger; _foo() console.log("截断结束...") }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function foo(a, b, c, d, e, f) { console.log("foo功能...") console.log(a, b, c, d, e, f) return 123 }
var _foo = foo
foo = function () { console.log("截断开始...") _foo.apply(this,arguments) console.log("截断结束...") }
foo(1,2,3,4,5,6,7)
|
案例1: Hook eval
1 2 3 4
| console.log("程序开始")
window["e"+"v"+"a"+"l"]("console.log('eval yuan')") console.log("程序结束")
|
1 2 3 4 5 6 7 8
| var _eval = eval
eval = function (src) { console.log("eval截断开始...") debugger; _eval.apply(this, src) console.log("eval截断结束...") }
|
案例2: Hook JSON.stringify
JSON.stringify() 方法用于将 JavaScript 值转换为 JSON 字符串,在某些站点的加密过程中可能会遇到,以下代码演示了遇到 JSON.stringify() 时,则插入断点:
1 2 3 4 5 6 7 8
| (function() { var stringify = JSON.stringify; JSON.stringify = function(params) { console.log("Hook JSON.stringif:::", params); debugger; return stringify(params); } })();
|
案例3: Hook JSON.parse
JSON.parse() 方法用于将一个 JSON 字符串转换为对象,在某些站点的加密过程中可能会遇到,以下代码演示了遇到 JSON.parse() 时,则插入断点:
1 2 3 4 5 6 7 8
| (function() { var parse = JSON.parse; JSON.parse = function(params) { console.log("Hook JSON.parse::: ", params); debugger; return parse(params); } })();
|
案例4: Hook Cookie
一般使用Object.defineProperty()来进行属性操作的hook。那么我们了解一下该方法的使用。
1 2 3 4 5 6
| Object.defineProperty(obj, prop, descriptor)
// 参数 obj:对象; prop:对象的属性名; descriptor:属性描述符;
|
一般hook使用的是get和set方法,下边简单演示一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var people = { name: '张三', };
Object.defineProperty(people, 'age', { get: function () { console.log('获取值!'); return count; }, set: function (val) { console.log('设置值!'); count = val + 1; }, });
people.age = 18; console.log(people.age);
|
通过这样的方法,我们就可以在设置某个值的时候,添加一些代码,比如 debugger;,让其断下,然后利用调用栈进行调试,找到参数加密、或者参数生成的地方,需要注意的是,网站加载时首先要运行我们的 Hook 代码,再运行网站自己的代码,才能够成功断下,这个过程我们可以称之为 Hook 代码的注入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| (function(){ 'use strict' var _cookie = ""; Object.defineProperty(document, 'cookie', { set: function(val) { console.log(val); debugger _cookie = val; return val; }, get: function() { return _cookie; }, }); })()
|