js逆向-3- js语法基础&js反爬原理

一、前言

JavaScript 教程 | 菜鸟教程

  1. 基础数据类型:number、string、boolean、null、undefined、object
  2. 顺序、条件、循环、比较
  3. 函数
  4. 运算符

强烈的推荐一本书:JavaScript高级程序设计(第4版) (豆瓣)【前13章之前】

正向的根基决定了逆向的上限

二、自测

JavaScript 测验icon-default.png?t=N7T8https://www.w3school.com.cn/js/js_quiz.asp

三、原型链

3.1 定义一:

  1. 每个函数都有 prototype 和 __proto__
  2. 每一个对象/构造函数实例(这个也是对象)都有 __proto__
  3. 实例的 __proto__ 指向构造函数的 prototype。这个称为 构造函数的原型对象
  4. js 引擎会沿着 __proto__ -> prototype 的顺序一直往上方查找,找到window.Object.prototype 为止,Object 为原生底层对象,到这里就停止了查找,如果没有找到,就会报错或者返回 undefined
  5. 而构造函数的 __proto__ 指向 Function.prototype ƒ () { [native code] } 【构造器函数,但这个叫法 并不准确,它目前没有一个合适的中文名】
  6. __proto__是浏览器厂商实现的,W3C规范中并没有这个东西

3.2 定义二:

  1. JS 代码还没运行的时候,JS 环境里已经有一个 window 对象了。函数是对象【所有的默认方法都是window的属性,比如eval、function、document等,包括声明变量时。】
  2. window 对象有一个 Object 属性,window.Object 是一个函数对象
  3. window.Object 这个函数对象有一个重要属性是 prototype
  4. window.Object.prototype 里面有一堆属性
  5. 所有的实例函数__proto__都会 指向构造函数的 prototype
  6. constructor 是反向的 prototype

3.3 举例

四、函数进阶

首先:JS中所有事物都是对象,对象是拥有属性和方法的数据。所以函数也是对象

当创建一个函数的时候,发生了什么?

实际上,函数是Function类型的实例,此时可以把每一个创建出来的函数,当成是Function类型的实例对象,所以函数本身拥有的对象属性,来源于Function

Fn. Constructor 即为 Function

但是与此同时要注意:Function.prototype.proto === Object.prototype

可以理解为:构造器函数的构造函数是Object

也可以简单的理解:函数即对象

4.1 构造函数

  1. 在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。构造函数首字母一般大写
  2. 构造函数的执行过程

(1) 当以 new 关键字调用时,会创建一个新的内存空间,标记为 Person 的实例

(2) 函数体内部的 this 指向该内存,每当创建一个实例的时候,就会创建一个新的内存空间

(3) 给 this 添加属性,就相当于给实例添加属性

(4) 由于函数体内部的this指向新创建的内存空间,默认返回 this ,就相当于默认返回了该内存空间

 

4.2 声明式函数

声明式会导致函数提升,function会被解释器优先编译。即我们用声明式写函数,可以在任何区域声明,不会影响我们调用

function XXX(){}

4.3 函数表达式

函数表达式我们经常使用,而函数表达式中的function则不会出现函数提升。而是JS解释器逐行解释,到了这一句才会解释。因此如果调用在函数表达式之前,则会调用失败。

var k = function(){};k() // 可以正常调用

fn1();function fn1(){}//可以正常调用

fn2();var fn2 = function(){}//无法调用

4.4 匿名函数表达式

  1. (function(){alert("wertyui")})()
  2. !function(){alert("wertyui")}()
  3. ~function(){alert("wertyui")}()
  4. -function(){alert("wertyui")}()
  5. +function(){alert("wertyui")}()

目的是为了防止找到函数入口。匿名函数实际上是做了一个虚拟机。

五、面向对象

5.1 封装

封装:把客观事物封装成抽象的类,隐藏属性和方法,仅对外公开接口。

在ES6之前,是不存在class这个语法糖类的。所以实现大多采用原型对象和构造函数

私有属性和方法:只能在构造函数内访问不能被外部所访问(在构造函数内使用var声明的属性)

公有属性和方法(或实例方法):对象外可以访问到对象内的属性和方法(在构造函数内使用this设置,或者设置在构造函数原型对象上比如Cat.prototype.xxx)

静态属性和方法:定义在构造函数上的方法(比如Cat.xxx),不需要实例就可以调用(例如Object.assign())

在ES6之后,存在class这个语法糖类。当你使用class的时候,它会默认调用constructor这个函数,来接收一些参数,并构造出一个新的实例对象(this)并将它返回,因此它被称为constructor构造方法(函数)。

5.2 继承

继承:继承就是子类可以使用父类的所有功能,并且对这些功能进行扩展。

比如我有个构造函数A,然后又有个构造函数B,但是B想要使用A里的一些属性和方法,一种办法就是让我们自身化身为CV侠,复制粘贴一波。还有一种就是利用继承,我让B直接继承了A里的功能,这样我就能用它了。

  1. 原型链继承
  2. 构造继承
  3. 组合继承
  4. 寄生组合继承
  5. 原型式继承
  6. 寄生继承
  7. 混入式继承
  8. class中的extends继承

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

A instanceof B

实例对象A instanceof 构造函数B

检测A的原型链(proto)上是否有B.prototype,有则返回true,否则返回false

5.3 多态

class中的多态:extends、super

多态的实际含义是:同一操作作用于不同的对象上,可以产生不同的解释和不同的执行结果。

对于js多态的详细解释:https://juejin.cn/post/6844904126011146254

六、语法

6.1 this与new

this,是指当前的本身,在非严格模式下this指向的是全局对象window,而在严格模式下会绑定到undefined。

  • “use strict”----> 严格模式,减少js中不严谨的因素。
  • 相同的代码在两种模式下有可能会出现不同的结果。

this的5种绑定方式:

  1. 默认绑定(非严格模式下this指向全局对象, 严格模式下this会绑定到undefined)
var a = 10;function foo(){console.log(this.a)};foo();window.a;

"use strict";var a=10;function foo(){console.log("this1",this);console.log(window.a);console.log(this.a)};console.log(window.foo);console.log(‘this2’,this);foo()
  1. 隐式绑定(当函数引用有上下文对象时, 如 obj.foo()的调用方式, foo内的this指向obj)
  2. 显示绑定(通过call()或者apply()方法直接指定this的绑定对象, 如foo.call(obj))
  3. new绑定
  4. 箭头函数绑定(this的指向由外层作用域决定的)

6.2 call、apply、bind

  1. 都是对函数的操作,使用方式:函数.call
  2. 都是用来改变函数的 this 对象的指向的。
  3. 第一个参数都是 this 要指向的对象。
  4. 都可以利用后续参数传参。
  5. call 接受函数传参方式为:fn.call(this, 1, 2, 3)
  6. apply 接受函数传参方式为:fn.apply(this,[1, 2, 3])
  7. bind 的返回值为一个新的函数,需要再次调用: fn.bind(this)(1, 2, 3)

6.3 new的过程中到底发生了什么?

  1. 新生成了一个对象
  2. 链接到原型
  3. 绑定 this
  4. 返回新对象

七、一些常见非指纹built-in函数

unescape eg:unescape('%21')

Function 函数实例化方法

eval

Array

Object

Date

RegExp

indexOf

hasOwnProperty

decodeURIComponent encodeURI encodeURIComponent

Math 、round 、 random、parseInt 等强制转换

shift、pop、push、unshift

slice、splice、split、substring、substr、concat

String 、 fromCharCode、 charCodeAt

atob 、btoa、Uint8Array、 ArrayBuffer、 Int32Array、 Int16Array

setTimeout 、setInterval、 clearTimeout

八、三元表达式

8.1 一般三元表达式

boolean_expression ? true_value : false_value;

boolean_expression: 布尔表达式,表达式在参与三元运算中必须求得一个布尔类型的值,要么是 true,要么是 false,结果作为判断依据,判断到底去:前面的值还是后面的值

true_value:布尔表达式的值为真时,三元表达式的结果

false_value:布尔表达式的值为假时,三元表达式的结果

作用:根据布尔表达式的结果,如果为真,三元表达式结果就是真值,如果为假,三元表达式结果就是假值

8.2 嵌套的三元表达式

二层嵌套 x = a > 10 ? 1 : a > 1 ? 2 : 3

三层嵌套 x = a > 10 ? 1 : a > 1 ? 2 : a > -5 ? 3:4

三层嵌套加赋值 a = a > 10 ? 1 : a > 1 ? 2 : a > -5 ? 3:4

三层嵌套加赋值加函数调用 错误情况1

function a(a){ a *= a};

a = a() > 10 ? 1 : a > 1 ? 2 : a > -5 ? 3:4

三层嵌套加赋值加函数正常调用 错误情况2

function a(a){ a *= a};

a = a(4) > 10 ? 1 : a > 1 ? 2 : a > -5 ? 3:4

三层嵌套加赋值加函数正常调用 正确情况

function a(a){ return a *= a};

a = a(4) > 10 ? 1 : a > 1 ? 2 : a > -5 ? 3:4

九、箭头函数

ES6标准新增了一种新的函数:Arrow Function(箭头函数)。

为什么叫Arrow Function?因为它的定义用的就是一个箭头

x => x * x

相当于

function (x) {

return x * x;

}

十、运算符

10.1 位运算符

位运算符有 7 个,分为两类:逻辑位运算符:位与(&)、位或(|)、位异或(^)、非位(~)

移位运算符:左移(>)、无符号右移(>>>)

10.2 逻辑运算符

下面我们来尝试读一下 代码:

  1. [!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]
  2. (![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[!+[]+!+[]+!+[]]]+[+!+[]]+([+[]]+![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[!+[]+!+[]+[+[]]]

十一、函数内arguments

简单来说:arguments 是一个对应于传递给函数的参数的类数组对象

arguments 对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments 对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。例如,如果一个函数传递了三个参数,你可以以如下方式引用他们:

arguments.callee:指向当前执行的函数(在 严格模式 下,第5版 ECMAScript (ES5) 禁止使用)

argunments.length:指向传递给当前函数的参数数量

在严格模式下,剩余参数、默认参数和解构赋值参数的存在不会改变 arguments对象的行为,但是在非严格模式下就有所不同了

十二、一些眼瞎的写法(伪代码)

  1. 自执行函数嵌套执行 function(a, b){}(fn1,fn2)
  2. _0x319289 _$SW Oo0o00o0 a b c
  3. 函数名与不一致原因(1.构造函数、2. 重新赋值)
  4. 三元表达式嵌套
  5. 控制流平坦化
  6. 打包
  7. 魔改加密包
  8. 重构解释器
  9. 剩下的想到了再说 =.=。肯定还有很多,只能以后再总结进去了

注:jsfuck 表情包 AAEncode 等属于骚操作不算在其列

十三、js反爬原理

13.1 在了解js反爬原理之前,要理解爬虫的工作原理

反爬虫的两大基本要求和问题:

  1. 让浏览器正常访问
  2. 让爬虫脚本无法访问

这就要求:

  1. 不影响用户体验
  2. 能严重阻止爬虫工程师的编程难度

13.2 确定JS反爬手段的特点

  1. cookie加密
  2. 参数加密
  3. headers加密
  4. 控制流平坦化

爬虫方法论

  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘飞凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值