安全初级—正则表达式、This关键字、闭包

news/2024/11/23 2:58:12/

文章目录

  • 正则表达式
      • 字面量字符
      • 元字符
      • 转义符
      • 特殊字符
      • 字符类
      • 预定义模式
      • 重复类
      • 量词符
      • 贪婪模式
      • 修饰符
  • This关键字
    • 使用场合
    • 使用注意点
      • 避免多层 this
      • 避免数组处理方法中的 this
      • 避免回调函数中的 this
    • 绑定 this 的方法
      • Function.prototype.call()
      • Function.prototype.apply()
      • Function.prototype.bind()
  • 闭包
      • 变量作用域
      • 读取函数内部的局部变量
      • 闭包概念

正则表达式

字面量字符

某个字符只表示它字面的含义,例如/a/匹配a/b/匹配b

元字符

(1)点字符(.)

点字符可以匹配除回车(\r)、换行(\n)、行分隔符(u2028)和段分隔符(\u2029)以外的所有字符。

同时,点字符对于码点大于0xFFFF字符也不能正确的匹配,会认为这是两个字符

c.t会匹配ct之间包含任意一个字符的情况,只要字符在同一行。

(2)位置字符

位置字符用来提示字符所处的位置,主要有两个字符。

  • ^ 表示字符串的开始位置
  • $ 表示字符串的结束位置
// test必须出现在开始位置
/^test/.test('test123') // true// test必须出现在结束位置
/test$/.test('new test') // true// 从开始位置到结束位置只有test
/^test$/.test('test') // true
/^test$/.test('test test') // false

(3)选择符(|

(|)表示“或关系”(or),即a|b匹配ab

多个选择符可以联合使用。

// 匹配fred、barney、betty之中的一个
/fred|barney|betty/

其他的元字符还包括\*+?()[]{}

转义符

正则表达式中,需要反斜杠转义的,一共有12个字符:^.[$()|*+?{\

这些有特殊含义的元字符,如果要匹配它们本身,就需要在它们前面要加上反斜杠。

特殊字符

对于不能打印的特殊字符,正则表达式提供了表达方法

  • \cX 表示Ctrl-[X],其中的X是A-Z之中任一个英文字母,用来匹配控制字符。
  • [\b] 匹配退格键(U+0008),不要与\b混淆。
  • \n 匹配换行键。
  • \r 匹配回车键。
  • \t 匹配制表符 tab(U+0009)。
  • \v 匹配垂直制表符(U+000B)。
  • \f 匹配换页符(U+000C)。
  • \0 匹配null字符(U+0000)。
  • \xhh 匹配一个以两位十六进制数(\x00-\xFF)表示的字符。
  • \uhhhh 匹配一个以四位十六进制数(\u0000-\uFFFF)表示的 Unicode 字符。

字符类

字符类(class)表示有一系列字符可供选择,只要匹配其中一个就可以了

例如[abc] 表示abc之中任选一个匹配。

(1)脱字符(^)

如果方括号内的第一个字符是[^],则表示除了字符类之中的字符,其他字符都可以匹配。

例如[^abc] 表示abc之外都可以匹配。

如果方括号内没有其他字符,即只有[^],就表示匹配一切字符,其中包括换行符。

点号作为元字符(.)是不包括换行符的

(2)连字符(-)

某些情况下,对于连续序列的字符,连字符(-)用来提供简写形式,表示字符的连续范围。

例如[123456789]可以写成[1-9],同理[A-Z]表示26个大写字母。

/a-z/.test('b') // false
/[a-z]/.test('b') // true

如果(-)中没有出现在[]中,就只是匹配字面的含义,不具备简写的作用。

只有当(-)用在[]之中,才表示连续的字符序列。

合法的字符类简写形式:

[0-9.,]
[0-9a-fA-F]
[a-zA-Z0-9-]
[1-31]  //不代表`1`到`31`,只代表`1`到`3`

连字符还可以用来指定 Unicode 字符的范围。

var str = "\u0130\u0131\u0132";
/[\u0128-\uFFFF]/.test(str)
// true

预定义模式

预定义模式指的是某些常见模式的简写方式

  • \d 匹配0-9之间的任一数字,相当于[0-9]
  • \D 匹配所有0-9以外的字符,相当于[^0-9]
  • \w 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]
  • \W 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]
  • \s 匹配空格(包括换行符、制表符、空格符等),相等于[ \t\r\n\v\f]
  • \S 匹配非空格的字符,相当于[^ \t\r\n\v\f]
  • \b 匹配词的边界。
  • \B 匹配非词边界,即在词的内部。

通常,正则表达式遇到换行符(\n)就会停止匹配。

重复类

模式的精确匹配次数,使用大括号({})表示。{n}表示恰好重复n次,{n,}表示至少重复n次,{n,m}表示重复不少于n次,不多于m次。

量词符

量词符用来设定某个模式出现的次数。

  • ? 问号表示某个模式出现0次或1次,等同于{0, 1}
  • * 星号表示某个模式出现0次或多次,等同于{0,}
  • + 加号表示某个模式出现1次或多次,等同于{1,}

贪婪模式

量词符默认情况下都是最大可能匹配,即匹配到下一个字符不满足匹配规则为止。这被称为贪婪模式。

var s = 'aaa';
s.match(/a+/) // ["aaa"]

非贪婪模式,即最小可能匹配。只要一发现匹配,就返回结果,不往下检查。

将贪婪模式改为非贪婪模式,可以在量词符后面加一个问号。

var s = 'aaa';
s.match(/a+?/) // ["a"]

除了非贪婪模式的加号(+?),还有非贪婪模式的星号(*?)和非贪婪模式的问号(??)。

  • +?:表示某个模式出现1次或多次,匹配时采用非贪婪模式。
  • *?:表示某个模式出现0次或多次,匹配时采用非贪婪模式。
  • ??:表格某个模式出现0次或1次,匹配时采用非贪婪模式。

修饰符

修饰符(modifier)表示模式的附加规则,放在正则模式的最尾部。

修饰符可以单个使用,也可以多个一起使用。

// 单个修饰符
var regex = /test/i;// 多个修饰符
var regex = /test/ig;

(1)g修饰符

正则模式含有g修饰符,每次都是从上一次匹配成功处,开始向后匹配。

var regex = /b/g;
var str = 'abba';regex.test(str); // true
regex.test(str); // true
regex.test(str); // false

因为字符串abba只有两个b,所以前两次匹配结果为true,第三次匹配结果为false

(2)i 修饰符

正则对象区分字母的大小写,加上i修饰符以后表示忽略大小写。

/abc/.test('ABC') // false
/abc/i.test('ABC') // true

(3)m 修饰符

m修饰符表示多行模式(multiline),会修改^$的行为。默认情况下(即不加m修饰符时),^$匹配字符串的开始处和结尾处,加上m修饰符以后,^$还会匹配行首和行尾,即^$会识别换行符(\n)。

/world$/.test('hello world\n') // false
/world$/m.test('hello world\n') // true

This关键字

this就是属性或方法“当前”所在的对象。

下面是一个实际的例子。

var person = {name: '张三',describe: function () {return '姓名:'+ this.name;}
};person.describe()
// "姓名:张三"

由于对象的属性可以赋给另一个对象,所以属性所在的当前对象是可变的,即this的指向是可变的。

function f() {return '姓名:'+ this.name;
}var A = {name: '张三',describe: f
};var B = {name: '李四',describe: f
};A.describe() // "姓名:张三"
B.describe() // "姓名:李四"

函数f内部使用了this关键字,随着f所在的对象不同,this的指向也不同。

只要函数被赋给另一个变量,this的指向就会变。

使用场合

(1)全局环境

全局环境使用this,它指的就是顶层对象window

this === window // truefunction f() {console.log(this === window);
}
f() // true

(2)构造函数

构造函数中的this,指的是实例对象。

var Obj = function (p) {this.p = p;
};
//在构造函数obj,this指向p属性
var o = new Obj('Hello World!');
o.p // "Hello World!"

(3)对象的方法

如果对象的方法里面包含thisthis的指向就是方法运行时所在的对象。该方法赋值给另一个对象,就会改变this的指向。

var obj ={foo: function () {console.log(this);}
};obj.foo() // obj
//此时this指向obj
//以下的用法会改变this的指向
// 情况一
(obj.foo = obj.foo)() // window
// 等同于
(obj.foo = function () {console.log(this);
})()
// 等同于
(function () {console.log(this);
})()// 情况二
(false || obj.foo)() // window
//等同于
(false || function () {console.log(this);
})()// 情况三
(1, obj.foo)() // window
//等同于
(1, function () {console.log(this);
})()

使用注意点

避免多层 this

由于this的指向是不确定的,所以切勿在函数中包含多层的this

var o = {f1: function () {console.log(this);var f2 = function () {console.log(this);}();}
}o.f1()
// Object
// Window

这种情况,f1第一次指向对象o,然后代码运行到f2时,this的指向又变成了全局对象。

避免数组处理方法中的 this

数组的mapforeach方法,允许提供一个函数作为参数。这个函数内部不应该使用this

var o = {v: 'hello',p: [ 'a1', 'a2' ],f: function f() {this.p.forEach(function (item) {console.log(this.v + ' ' + item);});}
}o.f()
// undefined a1
// undefined a2

上面的this其实也是类似于多层this,函数f的调用也是相当于在全局环境下调用,所以这里的this指向也是指向window对象。

避免回调函数中的 this

回调函数中的this往往会改变指向,最好避免使用。

var o = new Object();
o.f = function () {console.log(this === o);
}// jQuery 的写法
$('#button').on('click', o.f);

以上的代码,在调用函数f时,是在按钮对象的环境下调用的,所以this的指向也不是o,而是指向按钮的DOM对象。

绑定 this 的方法

JavaScript 提供了callapplybind这三个方法,来切换/固定this的指向。

Function.prototype.call()

函数实例的call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。

call方法的参数,应该是一个对象。如果参数为空、nullundefined,则默认传入全局对象。

var n = 123;
var obj = { n: 456 };function a() {console.log(this.n);
}//如果`call`方法没有参数,或者参数为`null`或`undefined`,则等同于指向全局对象。
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
//如果指向全局对象,返回结果为`123`
a.call(window) // 123
//如果使用`call`方法将`this`关键字指向`obj`对象,返回结果为`456`
a.call(obj) // 456

如果call方法的参数是一个原始值,那么这个原始值会自动转成对应的包装对象,然后传入call方法。

var f = function () {return this;
};f.call(5)  //5为参数,不是对象
// Number {[[PrimitiveValue]]: 5}

call方法还可以接受多个参数。

func.call(thisValue, arg1, arg2, ...)

Function.prototype.apply()

apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数,使用格式如下。

func.apply(thisValue, [arg1, arg2, ...])

(1)找出数组最大元素

JavaScript 不提供找出数组最大元素的函数。结合使用apply方法和Math.max方法,就可以返回数组的最大元素。

var a = [10, 2, 4, 15, 9];
Math.max.apply(null, a) // 15

(2)将数组的空元素变为undefined

通过apply方法,利用Array构造函数将数组的空元素变成undefined

Array.apply(null, ['a', ,'b'])
// [ 'a', undefined, 'b' ]

(3)转换类似数组的对象

另外,利用数组对象的slice方法,可以将一个类似数组的对象(比如arguments对象)转为真正的数组。

Array.prototype.slice.apply({0: 1, length: 1}) // [1]
Array.prototype.slice.apply({0: 1}) // []
Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
Array.prototype.slice.apply({length: 1}) // [undefined]
//前提:被处理的对象必须有`length`属性,以及相对应的数字键。

Function.prototype.bind()

bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。

var counter = {count: 0,inc: function () {this.count++;}
};var func = counter.inc.bind(counter);
func();
counter.count // 1//`counter.inc()`方法被赋值给变量`func`。这时必须用`bind()`方法将`inc()`内部的`this`,绑定到`counter`,否则就会出错。

bind()方法有一些使用注意点。

(1)每一次返回一个新函数

bind()方法每运行一次,就返回一个新函数,这会产生一些问题。

(2)结合回调函数使用

回调函数是 JavaScript 最常用的模式之一,但是一个常见的错误是,将包含this的方法直接当作回调函数。

(3)结合call()方法使用

利用bind()方法,可以改写一些 JavaScript 原生方法的使用形式。

闭包

闭包就是能够读取外层函数内部变量的函数

变量作用域

变量的作用域为两种:全局作用域和局部作用域

1)函数内部可以读取全局变量

2)函数外部无法读取函数内部的局部变量

读取函数内部的局部变量

1)在函数内部再定义一个函数

function f1() {let code = 200;function f2() {console.log(code);}
}

函数f1内部的函数f2可以读取f1中所有的局部变量。因此,若想在外部访问函数f1中的局部变量code,可通过函数f2间接访问。

2)为外部程序提供访问函数局部变量的入口

function f1() {let code = 200;function f2() {console.log(code);}return f2;
}f1()();  // 200

闭包概念

  • 闭包访问的变量,是每次运行上层函数时重新创建的,是相互独立的。

  • 不同的闭包,可以共享上层函数中的局部变量

使用闭包的注意点:

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。


http://www.ppmy.cn/news/986014.html

相关文章

解决Spring循环依赖

当我们使用Spring框架构建应用程序时,循环依赖是一个常见的问题。循环依赖指的是两个或多个Bean之间相互依赖,形成了一个循环的依赖关系。在这篇博客中,我们将深入探讨Spring循环依赖的原理,包括原因、解决方案和示例代码。 什么…

内存函数讲解

&#x1f495;"痛苦难以避免&#xff0c;而磨难可以选择。"-->村上春树&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;数据在内存中的存储 内存函数就是管理内存数据的函数&#xff0c;包含于头文件<string.h>中 1.memcpy函数-->内存…

[check-update] get changed dataId error, code_ 403

这个异常主要是nacos开启了密码认证,然后项目缺少一些相应的配置。 解决方案&#xff1a; bootstrap.properties文件加上如下配置&#xff1a; spring.cloud.nacos.usernamenacos spring.cloud.nacos.passwordnacosyml配置文件也加上对应的账号和密码。

VUE中使用ElementUI组件的单选按钮el-radio-button实现第二点击时取消选择的功能

页面样式为&#xff1a; html 代码为&#xff1a; 日志等级&#xff1a; <el-radio-group v-model"logLevel"><el-radio-button label"DEBUG" click.native.prevent"changeLogLevel(DEBUG)">DEBUG</el-radio-button><el-r…

【计算机网络】简易TCP网络小程序

文章目录 1. 简易TCP网络程序1.1 服务端1.1.1 服务端创建套接字1.1.2 服务端绑定1.1.3 服务端监听1.1.4 服务端获取连接1.1.5 服务端处理请求 1.2 客户端1.2.1 客户端创建套接字1.2.2 客户端连接服务器1.2.3 客户端发起请求 1.3 服务器测试1.4 单执行流服务器的弊端 2. 多进程版…

uniapp使用HQChart的k线,用webSocket更新数据

项目&#xff1a;不借用HQChart的各种接口数据&#xff0c;即数据后端返回&#xff0c;但是数据格式要和原数据格式一样。 //k线图 CreateHQChartKLine(){var chartHeightuni.upx2px(this.ChartHeight);let hqchartCtrlthis.$refs.HQChartCtrl;hqchartCtrl.KLine.Option.Type&…

ZQC的游戏 题解

前言 这题题意描述不是很清楚啊&#xff0c;所以我找了个有权限的人把题面改了改&#xff0c;应该还是比较清楚了。 感觉这道题挺妙的&#xff0c;就来写一篇题解。 思路 首先&#xff0c;根据贪心思想&#xff0c;我们会将 1 1 1 号点半径以内能吃的都吃了&#xff0c;假…

v2ex站点base64编码解码

最近在刷v站&#xff0c;我毕竟也是入坑不久的小白&#xff0c;发现各位兄弟的联系方式都是乱码&#xff0c;我以为是经过md5处理之类的&#xff0c;最后搜了下发现是对信息进行了base64编解码处理&#xff0c;目的是为了防止社工对个人信息的爬取处理。 下面是通过python对个人…