~~只记录重点和作者认为的难点 电子版:链接: https://pan.baidu.com/s/1D9UMFxxN1330hLBhqmiPhA 提取码: az1t ~~
前言:JavaScript是一种非常松散的面向对象语言,一种全新的动态语言,致力于增强网站和web应用程序的交互性。
1.什么是JavaScript
JavaScript历史回顾:
最早用来处理以前由服务器端语言负责的一些输入验证操作;
JavaScript是一种专为与网页交互而设计的脚本语言;
一个完整的JavaScript组成:核心(ECMAScript,提供核心语言功能)、文档对象模型(DOM提供访问和操作网页内容的方法和接口)、浏览器对象模型(BOM提供与浏览器交互的方法和接口)
2.HTML中的JavaScript
属性:
- async :立即加载脚本文件,异步执行,不能阻止其他页面动作,比如下载资源或等待其 他脚本加载。两个标记为async的脚本不一定谁先执行。
- defer:立即加载脚本文件,延迟执行,脚本可以延迟到文档完全被解析和显示之后再执行。
- type:代码块中脚本语言的内容类型(也称 MIME 类型)。
- src:外部文件地址。文件可以跟网页在同 一台服务器上,也可以位于完全不同的域。
- charset:字符集类型。
- crossorigin:配置相关请求的 CORS(跨源资源共享)设置。
- integrity:允许比对接收到的资源和指定的加密签名以验证子资源完整性(SRI, 12 Subresource Integrity)。如果接收到的资源的签名与这个属性指定的签名不匹配,则页面会报错,脚本不会执行。这个属性可以用于确保内容分发网络(CDN,Content Delivery Network)不会提供恶意内容。
3.语言基础
语法
- ECMAScript中的一切(变量、函数名、操作符)都区分大小写。函数名不能用typeof ,因为是关键字,但是typeOf可以作为函数名;
- 标识符:第一个字符必须是一个字母、下划线或者$;其他字符可以是字母、下划线、$、数字;
- 关键字:break do in typeof
case else instanceof var
catch export new void
class extends return while
const finally super with
continue for switch yield
debugger function this
default if throw
delete import try
保留字:enum
implements package public
interface protected static
let private
await
变量
var、let、const区别:
var :函数作用域,声明提升,可以重复声明
let:块作用域,没有声明提升,暂时性死区,不可以重复声明
const:基本与let 相同,但声明时必须初始化变量且以后不能修改
数据类型
typeof操作符:
typeof 123;//“number”
typeof message;//“string”
typeof “hi”;//“string”
typeof true;//“boolean”
typeof undefined;//“undefined”
typeof Boolean/String/Number/Object;// "function"
typeof Undefined/Null;//"undefined"
typeof null;//"object"
typeof((a,b)=>a-b) ;//“function”
Undefined类型:
只有一个值:undefined
var message;
alert(message);//undefined
alert(age);//报错 未声明
alert(typeof messgage);//"undefined
alert(typeof age);//"undefined
Null类型
只有一个值:null 表示一个空对象指针 所以
typeof null;//“object”
如果定义的变量准备在将来用于保存对象,那么最好将变量初始化为null
alert(null==undefined);//true!!!
Boolean类型
两个字面值:true 、false
可以对任何数据类型的值调用Boolean()函数,而且总会返回一个Boolean值
能转换为true的值:true、任何非空字符串、任何非零数字值、任何对象
能转换为false的值:false、""(空字符串)、0、NaN、null、undefined
Number类型
Number类型使用IEEE754格式表示整数和浮点数
八进制:第一位必须是0,然后是八进制数字序列(0~7),如果字面值中的数值超出了范围,那么前导0将被忽略,后面的数值将被当作十进制数值解析
例:
var octalNum1 = 070; // 八进制的 56
var octalNum2 = 079; // 无效的八进制数值——解析为 79
var octalNum3 = 08; // 无效的八进制数值——解析为 8
八进制字面量在严格模式下是无效的;
十六进制:前两位必须是0x,后跟任何十六进制数字(09及AF 可小写)
var hexNum1 = 0xA; // 十六进制的 10
var hexNum2 = 0x1f; // 十六进制的 31
在进行算术计算时,所有八进制和十六进制表示的数值最终都将被转换成十进制数值
浮点数值
该数值中必须包含一个小数点,并且小数点后面必须至少有一位数字。可以写 .1 有效但不推荐
由于保存浮点数值需要的内存空间是保存整数值的两倍,因此ECMAScript会不失时机地将浮点数值转换为整数值:
例:
var floatNum1=1. ;//小数点后面没有数字—解析为1
var floatNum2=10.0 ;//整数 -----解析为10
科学计数法:
var floatNum=3.125e7;//等于31250000
浮点数值的最高精度是17位小数,但在进行算术计算时其精度远远不如整数。浮点数值计算会产生舍入误差的问题;
例:0.1+0.2= 0.30000000000000004 不是0.3
数值范围
ECMAScript能够表示的最小数值保存在Number.MIN_VALUE中=5e-324;
最大数值保存在Number.MAX_VALUE中=1.7976931348623157e+308;
如果超过这个范围则该值被转换为-Infinity (负无穷)或Infinity(正无穷),并且不会参与下一次的计算;
判断一个数值是不是有穷的:isFinite()函数,
NaN:
即非数值(Not a Number)是一个特殊的数值,用于表示一个本来要返回数值的操作数未返回数值的情况,ECMAScript中任何0除以0返回NaN;
正数/0返回Infinity;
负数/0返回-Infinity;
任何涉及NaN的操作都会返回NaN;
NaN与任何值都不相等,包括NaN; alert(NaN==NaN);//false
isNaN()函数判断一个值是否“不是数值”,先将参数转换为数值
alert(isNaN(NaN)); //true
alert(isNaN(10)); //false(10是一个数值)
alert(isNaN(“10”)); //false(可以被转换成数值10)
alert(isNaN(“blue”)); //true(不能转换成数值)
alert(isNaN(true)); //false(可以被转换成数值 1)
数值转换
有三个函数可以把非数值转换为数值:
Number():可以用于任何数据类型
规则:
- Boolean转数值:true:1;false:0
- Number:直接转
- null:0
- undefined:NaN
- 字符串:
a.只包含数字或有效的浮点格式---->十进制数值 例:
Number(“123”)—>123;Number(“001”)—>1
Number(“01.1”)---->1.1
b.字符串中包含有效的十六进制格式,例如“0xf“,则转换为十进制整数数值;
c.空字符串---->0;
d.除上述格式之外的字符---->NaN - 对象:先调用valueOf函数如果返回原始类型,则按照上述规则转换成数值;如果返回不是原始类型,调用toString方法,将返回的字符串转为数值。
parseInt()、parseFloat():专门用于把字符串转换成数值
parseInt()更常用,忽略字符串前面的空格,如果第一个字符不是数字字符或者符号,就会返回NaN;空字符串返回NaN;
var num1 = parseInt(“1234blue”); // 1234
var num2 = parseInt(""); // NaN
var num3 = parseInt(“0xA”); // 10(十六进制数)
var num4 = parseInt(22.5); // 22
var num5 = parseInt(“070”,8); // 56(八进制数)
var num6 = parseInt(“70”); // 70(十进制数)
var num7 = parseInt(“0xf”); // 15(十六进制数)
parseFloat()也是从第一个字符开始解析,解析到遇见一个无效的浮点数字字符为止,也就是说字符串的第一个小数点是有效的,而第二个小数点就是无效的了;parseFloat()只解析十进制;
var num1 = parseFloat(“1234blue”); //1234 (整数)
var num2 = parseFloat(“0xA”); //0
var num3 = parseFloat(“22.5”); //22.5
var num4 = parseFloat(“22.34.5”); //22.34
var num5 = parseFloat(“0908.5”); //908.5
var num6 = parseFloat(“3.125e7”); //31250000
var num7 = parseFloat(".123.45"); //0.123
String类型
转换String类型
toString()不接收任何参数。不过,在对数值调用这个方法时,toString()可以接收一个底数参数,即以什么底数来输出数值的字符串表示。默认情况下,toString()返回数值的十
进制字符串表示。而通过传入参数,可以得到数值的二进制、八进制、十六进制,或者其他任何有效基
数的字符串表示,比如:
let num = 10;
console.log(num.toString()); // “10”
console.log(num.toString(2)); // “1010”
console.log(num.toString(8)); // “12”
console.log(num.toString(10)); // “10”
console.log(num.toString(16)); // "a
Symbol 类型
唯一的不可变的,用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
基本用法
let sym = Symbol();
console.log(typeof sym); // symbol
调用 Symbol()函数时,也可以传入一个字符串参数作为对符号的描述(description),将来可以通
过这个字符串来调试代码。但是,这个字符串参数与符号定义或标识完全无关:
let genericSymbol = Symbol();
let otherGenericSymbol = Symbol();
let fooSymbol = Symbol(‘foo’);
let otherFooSymbol = Symbol(‘foo’);
console.log(genericSymbol == otherGenericSymbol)//false
console.log(fooSymbol == otherFooSymbol)//false
不能使用new 创建
2. 使用全局符号注册表
如果运行时的不同部分需要共享和重用符号实例,那么可以用一个字符串作为键,在全局符号注册
表中创建并重用符号。
为此,需要使用 Symbol.for()方法:
let fooGlobalSymbol = Symbol.for(‘foo’);
console.log(typeof fooGlobalSymbol); // symbol
Symbol.for()对每个字符串键都执行幂等操作。第一次使用某个字符串调用时,它会检查全局运
行时注册表,发现不存在对应的符号,于是就会生成一个新符号实例并添加到注册表中。后续使用相同
字符串的调用同样会检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。
let fooGlobalSymbol = Symbol.for(‘foo’); // 创建新符号
let otherFooGlobalSymbol = Symbol.for(‘foo’); // 重用已有符号
console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
即使采用相同的符号描述,在全局注册表中定义的符号跟使用 Symbol()定义的符号也并不等同:
let localSymbol = Symbol(‘foo’);
let globalSymbol = Symbol.for(‘foo’);
console.log(localSymbol === globalSymbol); // false
全局注册表中的符号必须使用字符串键来创建,因此作为参数传给 Symbol.for()的任何值都会被转换为字符串。此外,注册表中使用的键同时也会被用作符号描述。
let emptyGlobalSymbol = Symbol.for();
console.log(emptyGlobalSymbol); // Symbol(undefined)
还可以使用 Symbol.keyFor()来查询全局注册表,这个方法接收符号,返回该全局符号对应的字
符串键。如果查询的不是全局符号,则返回 undefined。
// 创建全局符号
let s = Symbol.for(‘foo’);
console.log(Symbol.keyFor(s)); // foo
// 创建普通符号
let s2 = Symbol(‘bar’);
console.log(Symbol.keyFor(s2)); // undefined
如果传给 Symbol.keyFor()的不是符号,则该方法抛出 TypeError:
Symbol.keyFor(123); // TypeError: 123 is not a symbol
Object类型
每个 Object 实例都有如下属性和方法。
constructor:用于创建当前对象的函数。
hasOwnProperty(propertyName):用于判断当前对象实例(不是原型)上是否存在给定的属
性。要检查的属性名必须是字符串(如 o.hasOwnProperty(“name”))或符号。
isPrototypeOf(object):用于判断当前对象是否为另一个对象的原型。
propertyIsEnumerable(propertyName):用于判断给定的属性是否可以使用for-in 语句枚举。与 hasOwnProperty()一样,属性名必须是字符串。
toLocaleString():返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
toString():返回对象的字符串表示。
valueOf():返回对象对应的字符串、数值或布尔值表示。通常与 toString()的返回值相同。
因为在 ECMAScript 中 Object 是所有对象的基类,所以任何对象都有这些属性和方法。
操作符
一元操作符
一元加和减
如果将一元加应用到非数值,则会执行与使用 Number()转型函数一样的类型转换;
对数值使用一元减会将其变成相应的负值(如上面的例子所示)。在应用到非数值时,一元减会遵
循与一元加同样的规则,先对它们进行转换,然后再取负值。
位操作符
有符号整数使用 32 位的前 31 位表示整数值。第 32 位表示数值的符号,如 0 表示正,1 表示负。这
一位称为符号位(sign bit),它的值决定了数值其余部分的格式。正值以真正的二进制格式存储,即 31
位中的每一位都代表 2 的幂。第一位(称为第 0 位)表示 20
,第二位表示 21,依此类推。如果一个位是空的,则以0填充,相当于忽略不计。比如,数值18的二进制格式为00000000000000000000000000010010,
或更精简的 10010。
负值以一种称为二补数(或补码)的二进制编码存储。一个数值的二补数通过如下 3 个步骤计算
得到:
(1) 确定绝对值的二进制表示(如,对于18,先确定 18 的二进制表示);
(2) 找到数值的一补数(或反码),换句话说,就是每个 0 都变成 1,每个 1 都变成 0;
(3) 给结果加 1。
按位非 ~
let num1 = 25; // 二进制 00000000000000000000000000011001
let num2 = ~num1; // 二进制 11111111111111111111111111100110
console.log(num2); // -26 负二进制转为十进制:减1取反
相当于数值取反-1
按位与 &
按位与操作在两个位都是 1 时返回 1,在任何一位是 0 时返回 0。
按位或 |
按位或操作在至少一位是 1 时返回 1,两位都是 0 时返回 0。
按位异或 ^
按位异或与按位或的区别是,它只在一位上是 1 的时候返回 1(两位都是 1 或 0,则返回 0
左移 <<
let oldValue = 2; // 等于二进制 10
let newValue = oldValue << 5; // 等于二进制 1000000,即十进制 64
注意在移位后,数值右端会空出 5 位。左移会以 0 填充这些空位,让结果是完整的 32 位数值
注意,**左移会保留它所操作数值的符号。**比如,如果2 左移 5 位,将得到64,而不是正 64。
有符号右移 >>
会将数值的所有 32 位都向右移,同时保留符号(正或负)。
let oldValue = 64; // 等于二进制 1000000
let newValue = oldValue >> 5; // 等于二进制 10,即十进制 2
同样,移位后就会出现空位。不过,右移后空位会出现在左侧,且在符号位之后。ECMAScript 会用符号位的值来填充这些空位,以得到完整的数值。
无符号右移 >>>
无符号右移会给空位补 0,而不管符号位是什么。
布尔操作符
逻辑非 !
首先将操作数转换为布尔值,然后再对其取反。无论应用到的是什么数据类型,始终返回布尔值。
逻辑非操作符也可以用于把任意值转换为布尔值。同时使用两个叹号(!!),相当于调用了转型函
数 Boolean()。
逻辑与 &&
逻辑与操作符是一种短路操作符,意思就是如果第一个操作数决定了结果,那么永远不会对第二个
操作数求值。
逻辑或 ||
逻辑或操作符也具有短路的特性。只不过对逻辑或而言,第一个操作数求值为
true,第二个操作数就不会再被求值了。
乘性操作符
如果乘性操作符有不是数值的操作数,则该操作数会在后台被使用 Number()转型函数转换为数值。这意味着空字符串会
被当成 0,而布尔值 true 会被当成 1。
乘法操作符 *
除法操作符 /
取模操作符 %
指数操作符
Math.pow(3, 2)== 3 ** 2
let squared = 3;
squared **= 2;
console.log(squared); // 9
加性操作符
加法操作符
如果两个操作数都是字符串,则将第二个字符串拼接到第一个字符串后面;
如果只有一个操作数是字符串,则将另一个操作数转换为字符串,再将两个字符串拼接在一起。
如果有任一操作数是对象、数值或布尔值,则调用它们的 toString()方法以获取字符串,然后再
应用前面的关于字符串的规则。
减法操作符
如果有任一操作数是字符串、布尔值、null 或 undefined,则先在后台使用 Number()将其转
换为数值,然后再根据前面的规则执行数学运算。如果转换结果是 NaN,则减法计算的结果是
NaN。
如果有任一操作数是对象,则调用其 valueOf()方法取得表示它的数值。如果该值是 NaN,则
减法计算的结果是 NaN。如果对象没有 valueOf()方法,则调用其 toString()方法,然后再
将得到的字符串转换为数值。
关系操作符
小于(<)、大于(>)、小于等于(<=)和大于等于(>=)
对字符串而言,关系操作符会比较字符串中对应字符的编码,而这些编码是数值。比较完之后,会返回布尔值。问题的关键在于,大写字母的编码都小于小写字母的编码。
只要是数值和字符串比较,字符串就会先被转换为数值,然后进行数值比较。
任何关系操作符在涉及比较 NaN 时都返回 false。
let result1 = NaN < 3; // false
let result2 = NaN >= 3; // false
相等操作符
== !=
先进行类型转换(通常称为强制类型转换)再确定操作数是否相等。
在转换操作数的类型时,相等和不相等操作符遵循如下规则。
如果任一操作数是布尔值,则将其转换为数值再比较是否相等。false 转换为 0,true 转换为 1。
如果一个操作数是字符串,另一个操作数是数值,则尝试将字符串转换为数值,再比较是否相等。
如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法取得其原始值,再根据前面的规则进行比较。
在进行比较时,这两个操作符会遵循如下规则。
null 和 undefined 相等。
null 和 undefined 不能转换为其他类型的值再进行比较。
如果有任一操作数是 NaN,则相等操作符返回 false,不相等操作符返回 true。记住:即使两个操作数都是 NaN,相等操作符也返回 false,因为按照规则,NaN 不等于 NaN。
如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回 true。否则,两者不相等。
=== !==
全等和不全等操作符与相等和不相等操作符类似,只不过它们在比较相等时不转换操作数。
语句
for in
for-in 语句是一种严格的迭代语句,用于枚举对象中的非符号键属性.ECMAScript 中对象的属性是无序的,因此 for-in 语句不能保证返回对象属性的顺序。换句话说,所有可枚举的属性都会返回一次,但返回的顺序可能会因浏览器而异。如果 for-in 循环要迭代的变量是 null 或 undefined,则不执行循环体。
标签语句
label: statement
下面是一个例子:
start: for (let i = 0; i < count; i++) {
console.log(i);
}
在这个例子中,start 是一个标签,可以在后面通过 break 或 continue 语句引用。标签语句的
典型应用场景是嵌套循环。
break continue
break 语句用于立即退出循环,强制执行循环后的下一条语句。
而 continue 语句也用于立即退出循环,但会再次从循环顶部开始执行。
with语句
with 语句的用途是将代码作用域设置为特定的对象。
let qs = location.search.substring(1);
let hostName = location.hostname;
let url = location.href;
上面代码中的每一行都用到了 location 对象。如果使用 with 语句,就可以少写一些代码:
with(location) {
let qs = search.substring(1);
let hostName = hostname;
let url = href;
}
Switch语句
全等判断
能够在条件判断中使用表达式,就可以在判断中加入更多逻辑:
let num = 25;
switch (true) {
case num < 0:
console.log("Less than 0.");
break;
case num >= 0 && num <= 10:
console.log("Between 0 and 10.");
break;
case num > 10 && num <= 20:
console.log("Between 10 and 20.");
break;
default:
console.log("More than 20.");
}
函数
严格模式对函数也有一些限制:
函数不能以 eval 或 arguments 作为名称;
函数的参数不能叫 eval 或 arguments;
两个命名参数不能拥有同一个名称。
4、变量、作用域、内存
原始值与引用值
保存原始值的变量是按值访问的,因为我们操作的就是存储在变量中的实际值。
保存引用值的变量是按引用访问的,因为引用值是保存在内存里的对象,JavaScript不允许直接访问内存位置,也就不能直接操作对象所在的内存空间。在操作对象时实际上操作的是该对象的引用而非实际的对象本身。
所有函数的参数都是按值传递的!!!
原始值传参就不用多说了,看引用值传参
function setName(obj) {
obj.name = "Nicholas";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"
function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"
这个例子前后唯一的变化就是 setName()中多了两行代码,将 obj 重新定义为一个有着不同 name 的新对象。当 person 传入 setName()时,其 name 属性被设置为"Nicholas"。然后变量 obj 被设置 为一个新对象且 name 属性被设置为"Greg"。如果 person 是按引用传递的,那么 person 应该自动将 指针改为指向 name 为"Greg"的对象。可是,当我们再次访问 person.name 时,它的值是"Nicholas", 这表明函数中参数的值改变之后,原始的引用仍然没变。当 obj 在函数内部被重写时,它变成了一个指 向本地对象的指针。而那个本地对象在函数执行结束时就被销毁了。
访问基本类型和引用类型时,访问基本类型是按值访问的,访问引用类型是按引用访问的,
**复制时基本类型和引用类型时都是按值复制的,只是引用类型的复制是复制的地址(即指针,也是值)。**传递参数时,都是按值传递的,类似与基本类型和引用类型的复制,假设参数是按照引用传递的,从引用的本义来讲,应该是参数复制变量的地址(实际是变量的值,此处变量的值只是一个地址值而已,和变量本身所在的地址不是一个值),而实际是复制的变量的值不是变量的地址,显示假设不成立。由此得出,参数传递都是按照值传递的。
执行上下文与作用域
每个上下文都关联一个变量对象,这个上下文中定义的所有变量和函数都存在于这个变量上。上下文在其所有代码都执行完毕后会被销毁,包括定义在它上面的所有变量和函数(全局上下文在应用程序退出前才会被销毁,比如关闭网页或退出浏览器)
上下文中的代码在执行的时候,会创建变量对象的一个作用域链,这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。代码正在执行的上下文的变量对象始终位于作用域链的最前端。
作用域链增强
虽然执行上下文主要有全局上下文和函数上下文两种(eval()调用内部存在第三种上下文),但有其他方式来增强作用域链。某些语句会导致在作用域链前端临时添加一个上下文,这个上下文在代码执行后会被删除。以下情况会在作用域链前端增加一个变量对象:
1.try/catch语句中的catch块:
会创建一个新的变量对象,这个变量对象会包含要跑出的错误对象的声明。
2.with语句:
向作用域前端添加指定的对象
变量声明
var 声明会被拿到函数或者全局作用域的顶部,位于作用域中所有代码之前。这个现象叫作’提升‘。
垃圾回收
垃圾回收策略:标记清理、引用计数
内存泄漏:
1.意外声明全局变量是最常见但也最容易修复的内存泄漏问题。
2.定时器也可能会悄悄地导致内存泄漏。
定时器的回调通过闭包引用了外部变量:只要定时器一直运行,回调函数中引用的 name 就会一直占用内存。
let name = 'Jake';
setInterval(() => {
console.log(name);
}, 100);
3.使用 JavaScript 闭包很容易在不知不觉间造成内存泄漏。
let outer = function() { 10 let name = 'Jake';
return function() {
return name;
};
};
只要返回 的函数存在就不能清理 name,因为闭包一直在引用着它。假如 name 的内容很大(不止是一个小字符 串),那可能就是个大问题了。
基本引用类型
Date
new Date();//传入毫秒数;返回date对象
Date.parse(‘2021/1/1’);//返回毫秒数
Date.now();//返回毫秒数
继承的方法
toLocaleString 返回与浏览器运行的本地环境一致的日期和时间。包含针对事件的AM、PM(上午、下午)不包含时区 // ‘2021/12/13 下午5:17:02’
toString 返回带时区信息的日期和时间,24小时制。//‘Mon Dec 13 2021 17:17:11 GMT+0800 (中国标准时间)’
valueOf 返回毫秒数 //1639387044458
RegExp
flags:
- g:全局模式
- i:不区分大小写
- m:多行模式
- u:使用Unicode模式匹配
- y:粘附模式,只查找从lastIndex开始及之后的字符串
- s:dotAll模式,表示元字符.匹配任何字符串(包括\n \r)
元字符:( [ { \ ^ $ | ) ] } ? * + .
匹配元字符需要转义
let reg = /.a/gi 匹配所有.a
使用构造函数定义时需要二次转义
let reg = new RegExp(’\.a’,‘gi’)
RegExp实例属性
global:布尔值,表示是否设置了 g 标记。
ignoreCase:布尔值,表示是否设置了 i 标记。
unicode:布尔值,表示是否设置了 u 标记。
sticky:布尔值,表示是否设置了 y 标记。
lastIndex:整数,表示在源字符串中下一次搜索的开始位置,始终从 0 开始。
multiline:布尔值,表示是否设置了 m 标记。
dotAll:布尔值,表示是否设置了 s 标记。
source:正则表达式的字面量字符串(不是传给构造函数的模式字符串),没有开头和结尾的
斜杠。
flags:正则表达式的标记字符串。始终以字面量而非传入构造函数的字符串模式形式返回(没
有前后斜杠)。
RegExp实例方法
exec():接收一个参数,即要应 用模式的字符串。
如果找到了匹配项,则返回包含第一个匹配信息的数组;如果没找到匹配项,则返回 null。
返回的数组虽然是 Array 的实例,但包含两个额外的属性:index 和 input。index 是字符串中匹配模式的起始位置,input 是要查找的字符串。
这个数组的第一个元素是匹配整个模式的字符串, 其他元素是与表达式中的捕获组匹配的字符串。
rest():接收一个字符串参数。如果输入的文本与模式匹配,则参数 返回 true,否则返回 false。
toString():返回正则表达式的字面量表示。
toLocaleString():返回正则表达式的字面量表示。
valueOf():返回正则表达式本身
原始值包装类型
每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型的对象,从而暴露出操作原始值的各种方法。
let s1 = “some text”;
let s2 = s1.substring(2);
s1是个原始类型不是对象,逻辑上不应该有方法,但是代码却能够正常执行。
这是因为访问s1时是以读模式访问的,也就是要从内存中读取变量保存的值。在以读模式访问字符串值的任何时候,后台都会执行以下3步:
- 创建一个 String 类型的实例;
- 调用实例上的特定方法;
- 销毁实例。
可以把这 3 步想象成执行了如下 3 行 ECMAScript 代码:
let s1 = new String(“some text”);
let s2 = s1.substring(2);
s1 = null;
这种行为可以让原始值拥有对象的行为。对布尔值和数值而言,以上 3 步也会在后台发生,只不过 使用的是 Boolean 和 Number 包装类型而已。
引用类型与原始值包装类型的主要区别:
在于对象的生命周期。在通过 new 实例化引用类型后,得到 的实例会在离开作用域时被销毁,而自动创建的原始值包装对象则只存在于访问它的那行代码执行期 间。这意味着不能在运行时给原始值添加属性和方法。比如下面的例子:
let s1 = “some text”;
s1.color = “red”;
console.log(s1.color); // undefined
这里的第二行代码尝试给字符串 s1 添加了一个 color 属性。可是,第三行代码访问 color 属性时, 它却不见了。原因就是第二行代码运行时会临时创建一个 String 对象,而当第三行代码执行时,这个对 象已经被销毁了。实际上,第三行代码在这里创建了自己的 String 对象,但这个对象没有 color 属性。
Boolean
var a = false;
var b = new Boolean(false);
console.log(typeof a);// boolean
console.log(typeof b);//object
console.log(b instanceof Boolean); //true
b.valueOf();//false
b.toString();//"false"
Number
Number.isInteger()方法,用于辨别一个数值是否保存为整数。
console.log(Number.isInteger(1)); // true
console.log(Number.isInteger(1.00)); // true
console.log(Number.isInteger(1.01)); // false
IEEE 754 数值格式有一个特殊的数值范围,在这个范围内二进制值可以表示一个整数值。这个数值 范围从 Number.MIN_SAFE_INTEGER(-253 + 1)到 Number.MAX_SAFE_INTEGER(253 - 1)。对超出这个范围的数值,即使尝试保存为整数,IEEE 754 编码格式也意味着二进制值可能会表示一个完全不同的 数值。为了鉴别整数是否在这个范围内,可以使用 Number.isSafeInteger()方法
String
方法
- concat 拼接 不改变原值
- slice 截取 不改变原值(起始位置,结束位置+1)
- substring 截取 不改变原值 (起始位置,结束位置+1)
- substr 截取 不改变原值 (起始位置,截取长度)
如果都为一个参数则都是截取到字符串最后
let stringValue = "hello world";
console.log(stringValue.slice(3));//lo world
console.log(stringValue.substring(3));//lo world
console.log(stringValue.substr(3));//lo world
console.log(stringValue.slice(3, 7));// "lo w"
console.log(stringValue.substring(3,7)); // "lo w"
console.log(stringValue.substr(3, 7));// "lo world"
当参数有负数时:
- slice 所有负值参数都当成字符串长度加上负值
- substring 会将所有负值参数都转换为0
- substr 第一个负值参数当成字符串长度加上负值,第二个负值参数转换为0
let stringValue = "hello world";
console.log(stringValue.slice(-3));//rld
console.log(stringValue.substring(-3));//hello word
console.log(stringValue.substr(-3));//rld
console.log(stringValue.slice(3, -4));//lo w
console.log(stringValue.substring(3, -4)); // "hel"
console.log(stringValue.substr(3, -4)); // ""
-
repeat
这个方法接收一个整数参数,表示要将字 13 符串复制多少次,然后返回拼接所有副本后的结果。
let stringValue = "na ";
console.log(stringValue.repeat(16) + “batman”);// na na na na na na na na na na na na na na na na batman -
padStart和 padEnd
会复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件。这两个方法的第一个参数是长度,第二个参数是可选的填充字符串,默认为空格 。
let stringValue = "foo";
console.log(stringValue.padStart(6)); // " foo"
console.log(stringValue.padStart(9, ".")); // "......foo"
console.log(stringValue.padEnd(6)); // "foo "
console.log(stringValue.padEnd(9, ".")); // "foo......"
迭代与解构
字符串的原型上暴露了一个@@iterator 方法,表示可以迭代字符串的每个字符。
有了这个迭代器之后,字符串就可以通过解构操作符来解构了。比如,可以更方便地把字符串分割 为字符数组:
let message = “abcde”;
console.log([…message]); // [“a”, “b”, “c”, “d”, “e”]
单例内置对象
global
URL编码
encodeURI()和 encodeURIComponent()方法用于编码统一资源标识符(URI),以便传给浏览器。
这两个方法的主要区别是,encodeURI()不会编码属于 URL 组件的特殊字符,比如冒号、斜杠、问号、 1 井号,而 encodeURIComponent()会编码它发现的所有非标准字符。来看下面的例子:
let uri = "http://www.wrox.com/illegal value.js#start";
// "http://www.wrox.com/illegal%20value.js#start"
console.log(encodeURI(uri));
// "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.js%23start" console.log(encodeURIComponent(uri));
对应 decodeURI 、decodeURIComponent
eval
当解释器发现 eval()调用时,会将参数解释为实际的 ECMAScript 语句,然后将其插入到该位置。 通过 eval()执行的代码属于该调用所在上下文,被执行的代码与该上下文拥有相同的作用域链。这意 味着定义在包含上下文中的变量可以在 eval()调用内部被引用;可以在 eval()内部定义 一个函数或变量,然后在外部代码中引用.
通过 eval()定义的任何变量和函数都不会被提升,这是因为在解析代码的时候,它们是被包含在 一个字符串中的。它们只是在 eval()执行的时候才会被创建。
在严格模式下,在 eval()内部创建的变量和函数无法被外部访问。
global 对象属性
window对象
虽然 ECMA-262 没有规定直接访问 Global 对象的方式**,但浏览器将 window 对象实现为 Global 对象的代理。**