JavaScript基础知识(三)
JavaScript基础知识(三)
<script>元素
<script>元素属性
async:可选,异步执行脚本,表示应该立即开始下载脚本,但是不能阻止其他页面动作,比如下载资源或者等待其他脚本加载,不保证按照页面中放置的顺序执行,只对外部脚本文件有效。
charset:可选,使用src属性指定的代码字符集。
crossorigin:配置相关请求的CORS(跨源资源共享)设置,默认不使用CORS。
- crossorigin=anonymous,配置文件请求不必设置凭据标志。
- crossorigin=use-credentials,配置凭据标志,出站请求会包含凭据。
defer:可选,延迟执行脚本,表示脚本可以延迟到文档完全被解析和显示后再执行,对外部脚本文件有效。
integrity:可选,允许比对接收到的资源和指定的加密签名,以验证子资源完整性,签名不匹配则报错,脚本不会执行,确保CDN(内容分发网络)不会提供恶意内容。
language:废弃,指定脚本语言,例如JavaScript、VBScript
src:可选,包含外部文件。
type:可选,代替language,表示脚本语言的内容类型(MIME类型),默认都是text/javascript(已废弃)
- application/x-javascript,可能导致脚本被忽略
- application/javascript,application/ecmascript
- module,ES6模块,可使用import和export关键字。
<script>元素位置
- 浏览器按照出现的先后顺序依次解释,前提是没有使用async、defer
- <script>元素放到页面的
内,集中管理,意味着必须把所有脚本语言下载、解释、执行完毕才能渲染页面(浏览器解析到
的起始标签时才开始渲染),影响体验。
- <script>放到
的页面内容后面。
动态加载脚本
动态加载脚本,通过创建scipt标签,指定src,添加到页面中去。
1
2
3
4
5
6<script>
let script = document.creatElement('script');
script.src = 'somejs.js';
script.async = false; //设置同步加载
document.head.appendChild(script);
</script>动态加载脚本是异步执行的,相当于async,默认执行到动态加载前不会执行脚本。
动态加载脚本,可指定脚本async=false改成同步执行,但是会严重影响性能,因为浏览器预加载器不可见,可以设置预加载器知道这些动态请求文件的存在,在文档头部设置
1
2
3<head>
<link rel="preload" href="somejs.js">
</head>
缓存脚本
- 两个页面用到用一个js脚本,只下载一次。浏览器使用SPDY/HTTP2放入缓存。
<noscript>元素
- 提示不支持脚本和禁用脚本的浏览器
- 本身是一个Html元素
基础语法
标识符
- 变量、函数、属性、函数参数的名称,首字符必须字母、下划线、$,剩下的可以是字母、下划线、$、数字,一般采用驼峰法。关键字、保留字、true、false、null不能用作标识符。
严格模式
- strict mode ,
"use strict";
,参考es3的语法。
语句
关键字
- 特殊用途,表示控制语句的开始、结束、执行特定操作等
- break、do、in、typeof、case、else、var … 33+个
保留字
- 保留给未来用作关键字
- enum:始终保留
- implements、package、public、interface、protected、static、let、private:严格模式保留
- await:模块代码保留
变量
松散型,保存任意值的命名占位符。
var
定义变量,可改数据类型
在函数内部声明作用域,局部变量,全局变量
声明提升(hoist)
1
2
3
4
5
6
7
8
9
10
11
12
13
14function foo() {
console.log(age);
var age = 26;
}
foo(); // undefined,不会报错
////相当于
function foo() {
var age;
console.log(age);
age = 26;
}
foo(); // undefined多次、重复声明
1
2
3
4
5
6
7function foo() {
var age = 16;
var age = 26;
var age = 36;
console.log(age);
}
foo(); // 36
let
跟var最明显的区别,let声明的范围是块作用域。
1
2
3
4
5
6if (true) {
let age = 26;
console.log(age); // 26
}
console.log(age); // ReferenceError: age 没有定义
//说明:age变量的作用域仅限于if内部,块作用域是函数作用域的子集不允许重复声明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21var name;
var name;
let name; //SyntaxError;标识符 name 已经声明过了
let age;
let age; // SyntaxError;标识符 age 已经声明过了
//块作用域
var name = 'Nicholas';
console.log(name); // 'Nicholas'
if (true) {
var name = 'Matt';
console.log(name); // 'Matt'
}
let age = 30;
console.log(age); // 30
if (true) {
console.log(age); // 30
let age = 26;
console.log(age); // 26,不报错
}let 声明之前的执行瞬间导致暂时性死区,不会在作用域中提升, 不能以任何方式来引用未声明的变量
1
2
3
4
5
6// name 会被提升
console.log(name); // undefined
var name = 'Matt';
// age 不会被提升
console.log(age); // ReferenceError:age 没有定义
let age = 26;全局声明,let不会成为window对象的属性
for循环中的let声明
可修改数量类型
const
不同于let的是声明时必须初始化值
不可修改数据类型,但对于引用类型的除外
可用于特定循环
1
2
3
4
5
6
7
8
9
10
11
12
13let i = 0;
for (const j = 7; i < 5; ++i) {
console.log(j);
}
// 7, 7, 7, 7, 7
for (const key in {a: 1, b: 2}) {
console.log(key);
}
// a, b
for (const value of [1,2,3,4,5]) {
console.log(value);
}
// 1, 2, 3, 4, 5
变量使用规则:const > let
数据类型
简单数据类型(原始类型)
Undefined:为了明确未初始化变量和null的区别,由null派生出来的
Null:空对象指针
Boolean
Number
最大值:Number.MAX_VALUE,1.7976931348623157e+308
最小值:Number.MIN_VALUE,5e-324
Infinity
-Infinity
NaN
计算
1
2
3
4
5
6
7console.log(0/0); // NaN
console.log(-0/+0); // NaN
console.log(NaN/10); // NaN
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity判断
- isNaN,首先会调用对象的 valueOf() 方法,然后再确定返回的值是否可以转换为数值。如果不能,再调用 toString()方法, 并测试其返回值。这通常是 ECMAScript 内置函数和操作符的工作方式。
1
2
3
4
5
6console.log(NaN == NaN); // false
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10 是数值
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值 1- Number.isNaN
1
2
3
4
5console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN(10)); // false
console.log(Number.isNaN("10")); // false
console.log(Number.isNaN("blue")); // false
console.log(Number.isNaN(true)); // false- Object.is
1
2console.log(NaN == NaN); // false
console.log(Object.is(NaN,NaN)); // true数值转换
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
37let num1 = Number("Hello world!"); // NaN
let num2 = Number(""); // 0
let num3 = Number("000011"); // 11
let num4 = Number("123"); // 123
let num5 = Number("123a"); // NaN
let num6 = Number(true); // 1
let num7 = Number(false); // 0
let num8 = Number(null); // 0
let num9 = Number(undefined); // NaN
let num10 = Number(NaN); // NaN
let num11 = Number({}); // NaN
let num12 = Number([]); //0
let num1 = parseInt("1234blue"); // 1234
let num2 = parseInt(""); // NaN
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
//parseInt()也接收第二个参数,用于指定底数(进制数)
let num = parseInt("0xAF", 16); // 175
let num1 = parseInt("AF", 16); // 175
let num2 = parseInt("AF"); // NaN
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num4 = parseInt("10", 16); // 16,按十六进制解析
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0,parseFloat()只解析十进制值
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
let num6 = parseFloat("3.125e7"); // 31250000
//Number.isInteger()方法,用于辨别一个数值是否保存为整数
console.log(Number.isInteger(1)); // true
console.log(Number.isInteger(1.00)); // true
console.log(Number.isInteger(1.01)); // false//Number.isSafeInteger()鉴别整数是否在Number.MIN_SAFE_INTEGER(-2^53 + 1)到 Number.MAX_SAFE_INTEGER(2^53-1)这个范围 console.log(Number.isSafeInteger(-1 * (2 ** 53))); // false console.log(Number.isSafeInteger(-1 * (2 ** 53) + 1)); // true console.log(Number.isSafeInteger(2 ** 53)); // false console.log(Number.isSafeInteger((2 ** 53) - 1)); // true
1
2
3
4
5
6
7
8
9
10
11
12
+ String
+ 表示零或多个 16 位 Unicode 字符序列,双引号(")、 单引号(')或反引号(`)标示
```javascript
let firstName = "John";
let lastName = 'Jacob';
let lastName = `Jingleheimerschmidt`常用方法
length
1
2let message = "abcde";
console.log(message.length); // 5charCodeAt(arg?:number)
1
2
3
4
5
6
7let message = "abcde";
console.log(message.charAt(2)); // "c"
let message = "abcde";
// Unicode "Latin small letter C"的编码是 U+0063
console.log(message.charCodeAt(2)); // 99codePointAt(arg)
1
2let message = "abde";
console.log(message.codePointAt(1)); // 98fromCharCode(…arg)
1
console.log(String.fromCharCode(0x61, 0x62, 0x63, 0x64, 0x65)); // "abcde"
concat、slice、substr、substring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//concat()、slice()、substr()、substring()不会修改调用它们的字符串
let stringValue = "hello ";
let result = stringValue.concat("world");
console.log(result); // "hello world"
console.log(stringValue); // "hello"
let stringValue = "hello ";
let result = stringValue.concat("world", "!");
console.log(result); // "hello world!"
console.log(stringValue); // "hello"
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 worl"indexOf、lastIndexOf
1
2
3
4
5
6
7
8let stringValue = "hello world";
console.log(stringValue.indexOf("o")); // 4
console.log(stringValue.lastIndexOf("o")); // 7
//可选的第二个参数,表示开始搜索的位置,指定的位置开始向字符串末尾搜索,忽略该位置之前的字符
let stringValue = "hello world";
console.log(stringValue.indexOf("o", 6)); // 7
console.log(stringValue.lastIndexOf("o", 6)); // 4startsWith、endsWith、includes
1
2
3
4
5
6
7
8
9
10
11
12
13
14let message = "foobarbaz";
console.log(message.startsWith("foo")); // true
console.log(message.startsWith("bar")); // false
console.log(message.endsWith("baz")); // true
console.log(message.endsWith("bar")); // false
console.log(message.includes("bar")); // true
console.log(message.includes("qux")); // false
//可选的第二个参数,表示开始搜索的位置。如果传入第二个参数,则意味着这两个方法会从指定位置向着字符串末尾搜索,忽略该位置之前的所有字符。
let message = "foobarbaz";
console.log(message.startsWith("foo")); // true
console.log(message.startsWith("foo", 1)); // false
console.log(message.includes("bar")); // true
console.log(message.includes("bar", 4)); // falsetrim
1
2
3
4let stringValue = " hello world ";
let trimmedStringValue = stringValue.trim();
console.log(stringValue); // " hello world "
console.log(trimmedStringValue); // "hello world"repeat
1
2
3//接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果
let stringValue = "na ";
console.log(stringValue.repeat(2) + "batman"); //na na batmanpadStart、 padEnd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件
//第一个参数是长度,第二个参数是可选的填充字符串,默认为空格
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......"
//如果提供了多个字符的字符串,则会将其拼接并截断以匹配指定长度
//如果长度小于或等于字符串长度,则会返回原始字符串
let stringValue = "foo";
console.log(stringValue.padStart(8, "bar")); // "barbafoo"
console.log(stringValue.padStart(2)); // "foo"
console.log(stringValue.padEnd(8, "bar")); // "foobarba"
console.log(stringValue.padEnd(2)); // "foo"@@iterator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//可以迭代字符串的每个字符
let message = "abc";
let stringIterator = message[Symbol.iterator]();
console.log(stringIterator.next()); // {value: "a", done: false}
console.log(stringIterator.next()); // {value: "b", done: false}
console.log(stringIterator.next()); // {value: "c", done: false}
console.log(stringIterator.next()); // {value: undefined, done: true}
for (const c of "abcde") {
console.log(c);
}
// a
// b
// c
// d
// e
//字符串使用迭代器可以通过解构操作符来解构
let message = "abcde";
console.log([...message]); // ["a", "b", "c", "d", "e"]toUpperCase、toLowerCase
1
2
3
4
5let stringValue = "hello world";
console.log(stringValue.toLocaleUpperCase()); // "HELLO WORLD"
console.log(stringValue.toUpperCase()); // "HELLO WORLD"
console.log(stringValue.toLocaleLowerCase()); // "hello world"
console.log(stringValue.toLowerCase()); // "hello world"match
1
2
3
4
5
6
7
8
9
10
11
12let text = "cat, bat, sat, fat";
let pattern = /.at/;
// 等价于 pattern.exec(text)
let matches = text.match(pattern);
console.log(matches.index); // 0
console.log(matches[0]); // "cat"
console.log(pattern.lastIndex); // 0
let text = "cat, bat, sat, fat";
let pos = text.search(/at/);
console.log(pos); // 1 ,即"at"的第一个字符在字符串中的位置replace
1
2
3
4
5
6
7
8
9let text = "cat, bat, sat, fat";
let result = text.replace("at", "ond");
console.log(result); // "cond, bat, sat, fat"
result = text.replace(/at/g, "ond");
console.log(result); // "cond, bond, sond, fond"
let text = "cat, bat, sat, fat";
result = text.replace(/(.at)/g, "word ($1)");
console.log(result); // word (cat), word (bat), word (sat), word (fat)split
1
2
3
4let colorText = "red,blue,green,yellow";
let colors1 = colorText.split(","); // ["red", "blue", "green", "yellow"]
let colors2 = colorText.split(",", 2); // ["red", "blue"]
let colors3 = colorText.split(/[^,]+/); // ["", ",", ",", ",", ""]localeCompare
1
2
3
4
5
6
7
8
9
10//比较两个字符串
//如果按照字母表顺序,字符串应该排在字符串参数前头,则返回负值。(通常是-1,具体还要看与实际值相关的实现。)
//如果字符串与字符串参数相等,则返回 0。
//如果按照字母表顺序,字符串应该排在字符串参数后头,则返回正值。(通常是 1,具体还要看与实际值相关的实现。)
let stringValue = "yellow";
console.log(stringValue.localeCompare("brick")); // 1
console.log(stringValue.localeCompare("yellow")); // 0
console.log(stringValue.localeCompare("zoo")); // -1
Array
创建数组
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
38
39let colors = new Array();
let colors = new Array(20); // length 为 20
let colors = new Array("red", "blue", "green");
let colors = new Array(3); // 创建一个包含 3 个元素的数组
let names = new Array("Greg"); // 创建一个只包含一个元素,即字符串"Greg"的数组
//省略 new 操作符
let colors = Array(3); // 创建一个包含 3 个元素的数组
let names = Array("Greg"); // 创建一个只包含一个元素,即字符串"Greg"的数组
let colors = ["red", "blue", "green"]; // 创建一个包含 3 个元素的数组
let names = []; // 创建一个空数组
let values = [1,2,]; // 创建一个包含 2 个元素的数组
const options = [,,,,,]; // 创建包含 5 个元素的数组
console.log(options.length); // 5
console.log(options); // [,,,,,]
const options = [1,,,,5];
for (const option of options) {
console.log(option === undefined);
}
// false
// true
// true
// true
// false
const options = [1,,,,5];
// map()会跳过空位置
console.log(options.map(() => 6)); // [6, undefined, undefined, undefined, 6]
// join()视空位置为空字符串
console.log(options.join('-')); // "1----5"
//数组转字符串
let colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
console.log(colors.toString()); // red,blue,green数组检测
1
2
3
4
5
6let arr = [1,2,3]
console.log(arr instanceof Array)
console.log(Array.isArray(arr))
Object.prototype.toString.call(arr) === '[object Array]'数组方法
转换
Array.from(arg1,arg2?,arg3?)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24//参数1:想要转换成数组的伪数组对象或可迭代对象
//参数2:可选,如果指定了该参数,新数组中的每个元素会执行该回调函数
//参数3:可选参数,执行回调函数(第二个参数)时 this 对象
//类数组结构转换为数组实例
console.log(Array.from("Matt")); // ["M", "a", "t", "t"]
const m = new Map().set(1, 2)
.set(3, 4);
const s = new Set().add(1)
.add(2)
.add(3)
.add(4);
console.log(Array.from(m)); // [[1, 2], [3, 4]]
console.log(Array.from(s)); // [1, 2, 3, 4]
// Array.from()对现有数组执行浅复制
const a1 = [1, 2, 3, 4];
const a2 = Array.from(a1);
console.log(a1); // [1, 2, 3, 4]
alert(a1 === a2); // false
//扩展
console.log(Array.from([1, 2, 3], x => x + x)); //[2, 4, 6]Array.of
1
2
3
4//可变数量的参数创建一个新的 Array 实例,而不考虑参数的数量或类型
//于替代在 ES6之前常用的 Array.prototype.slice.call(arguments),一种异常笨拙的将 arguments 对象转换为数组的写法
console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4]
console.log(Array.of(undefined)); // [undefined]
迭代
Array.keys()、Array.values()、Array.entries()
复制、填充
Array.copyWithin()
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//浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度
[1, 2, 3, 4, 5].copyWithin(-2)
// [1, 2, 3, 1, 2]
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(-2, -3, -1)
// [1, 2, 3, 3, 4]
[].copyWithin.call({length: 5, 3: 1}, 0, 3);
// {0: 1, 3: 1, length: 5}
// ES2015 Typed Arrays are subclasses of Array
var i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]
// On platforms that are not yet ES2015 compliant:
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]Array.fill()
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//用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引
const array1 = [1, 2, 3, 4];
// Fill with 0 from position 2 until position 4
console.log(array1.fill(0, 2, 4));
// Expected output: Array [1, 2, 0, 0]
// Fill with 5 from position 1
console.log(array1.fill(5, 1));
// Expected output: Array [1, 5, 5, 5]
console.log(array1.fill(6));
// Expected output: Array [6, 6, 6, 6]
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3); // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2); // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5); // [1, 2, 3]
Array(3).fill(4); // [4, 4, 4]
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}
// Objects by reference.
const arr = Array(3).fill({}) // [{}, {}, {}];
// 需要注意如果 fill 的参数为引用类型,会导致都执行同一个引用类型
// 如 arr[0] === arr[1] 为 true
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]常用方法
- pop
- push
- shift
- unshift
- reduce
- reduceRight
- splice
- reverse
- sort
- slice
- at
- concat
- find
- findIndex
- findlast
- findLastIndex
- flat
- flatMap
- forEach
- includes
- indexOf
- lastIndexOf
- join
- some
- every
- filter
- map
Symbol
- 确保对象属性使用唯一标识符,不会发生属性冲突的危险。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18let sym = Symbol();
console.log(typeof sym); // symbol
let fooSymbol = Symbol('foo');
let otherFooSymbol = Symbol('foo');
console.log(fooSymbol == otherFooSymbol); // false
console.log(fooSymbol); // Symbol(foo);
let fooGlobalSymbol = Symbol.for('foo');
console.log(typeof fooGlobalSymbol); // symbol
console.log(fooGlobalSymbol); // Symbol(foo)
let fooGlobalSymbol = Symbol.for('foo'); // 创建新符号
let otherFooGlobalSymbol = Symbol.for('foo'); // 重用已有符号
console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
let localSymbol = Symbol('foo');
let globalSymbol = Symbol.for('foo');
console.log(localSymbol === globalSymbol); // falseMap、WeakMap
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81const m = new Map();
const m1 = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
alert(m1.size); // 3
const m = new Map();
alert(m.has("firstName")); // false
alert(m.get("firstName")); // undefined
alert(m.size); // 0
m.set("firstName", "Matt")
.set("lastName", "Frisbie");
alert(m.has("firstName")); // true
alert(m.get("firstName")); // Matt
alert(m.size); // 2
m.delete("firstName"); // 只删除这一个键/值对
alert(m.has("firstName")); // false
alert(m.has("lastName")); // true
alert(m.size); // 1
m.clear(); // 清除这个映射实例中的所有键/值对
alert(m.has("firstName")); // false
alert(m.has("lastName")); // false
alert(m.size); // 0
const m = new Map().set("key1", "val1");
m.set("key2", "val2")
.set("key3", "val3");
alert(m.size); // 3
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
alert(m.entries === m[Symbol.iterator]); // true
for (let pair of m.entries()) {
alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
for (let key of m.keys()) {
alert(key);
}
// key1
// key2
// key3
for (let key of m.values()) {
alert(key);
}
// value1
// value2
// value3
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
/*
因为 WeakMap 中的键/值对任何时候都可能被销毁,所以没必要提供迭代其键/值对的能力。当然,
也用不着像 clear()这样一次性销毁所有键/值的方法。WeakMap 确实没有这个方法。因为不可能迭代,
所以也不可能在不知道对象引用的情况下从弱映射中取得值。即便代码可以访问 WeakMap 实例,也没
办法看到其中的内容
*/
const key1 = {id: 1}, key2 = {id: 2},key3 = {id: 3};
const wm1 = new WeakMap([
[key1, "val1"],
[key2, "val2"],
[key3, "val3"]
]);
alert(wm1.get(key1)); // val1
alert(wm1.get(key2)); // val2
alert(wm1.get(key3)); // val3Set、WeakSet
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57const m = new Set();
const s1 = new Set(["val1", "val2", "val3"]);
alert(s1.size); // 3
const s = new Set();
alert(s.has("Matt")); // false
alert(s.size); // 0
s.add("Matt")
.add("Frisbie");
alert(s.has("Matt")); // true
alert(s.size); // 2
s.delete("Matt");
alert(s.has("Matt")); // false
alert(s.has("Frisbie")); // true
alert(s.size); // 1
s.clear(); // 销毁集合实例中的所有值
alert(s.has("Matt")); // false
alert(s.has("Frisbie")); // false
alert(s.size); // 0
const s = new Set().add("val1");
s.add("val2")
.add("val3");
alert(s.size); // 3
const s = new Set();
const functionVal = function() {};
const symbolVal = Symbol();
const objectVal = new Object();
s.add(functionVal);
s.add(symbolVal);
s.add(objectVal);
alert(s.has(functionVal)); // true
alert(s.has(symbolVal)); // true
alert(s.has(objectVal)); // true
// SameValueZero 检查意味着独立的实例不会冲突
alert(s.has(function() {})); // false
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
/*
因为 WeakSet 中的值任何时候都可能被销毁,所以没必要提供迭代其值的能力。当然,也用不着
像 clear()这样一次性销毁所有值的方法。WeakSet 确实没有这个方法。因为不可能迭代,所以也不
可能在不知道对象引用的情况下从弱集合中取得值。即便代码可以访问 WeakSet 实例,也没办法看到
其中的内容。
WeakSet 之所以限制只能用对象作为值,是为了保证只有通过值对象的引用才能取得值。如果允许
原始值,那就没办法区分初始化时使用的字符串字面量和初始化之后使用的一个相等的字符串了。
*/
const ws = new WeakSet();
const val1 = {id: 1},
val2 = {id: 2},
val3 = {id: 3};
// 使用数组初始化弱集合
const ws1 = new WeakSet([val1, val2, val3]);
alert(ws1.has(val1)); // true
alert(ws1.has(val2)); // true
alert(ws1.has(val3)); // true
引用类型
数据类型检测
typeof :是一个操作数,可以使用参数,括号里面放入被检测的数据,但不是函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19let s = "Nicholas";
let b = true;
let i = 22;
let u;
let n = null;
let o = new Object();
let arr = new Array();
let f = function(){}
console.log(typeof s); // string
console.log(typeof i); // number
console.log(typeof b); // boolean
console.log(typeof u); // undefined
console.log(typeof n); // object
console.log(typeof o); // object
console.log(typeof arr); // object
console.log(typeof f); // function,任何实现内部[[Call]]方法的对象都应该在typeof检测时返回"function"
console.log(typeof Array); // function
console.log(typeof Object); // function
console.log(typeof Date); // functioninstanceof :判断是什么类型的对象,判断变量是给定引用类型的实例
所有引用值都是 Object 的实例
用 instanceof 检测原始值,则始终会返回 false, 因为原始值不是对象。
1
2
3
4
5
6
7
8
9console.log(Array instanceof Object); //true
let arr = new Array();
console.log(arr instanceof Object); //true
let f = function(){}
console.log(f instanceof Object); //true
console.log(Object instanceof Object);//true
数据转换
==
- 如果任一操作数是布尔值,则将其转换为数值再比较是否相等。false 转换为 0,true 转换为1。
- 如果一个操作数是字符串,另一个操作数是数值,则尝试将字符串转换为数值,再比较是否相等。
- 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法取得其原始值,再根据前面的规则进行比较。
- null 和 undefined 相等。
- null 和 undefined 不能转换为其他类型的值再进行比较。
- 如果有任一操作数是 NaN,则相等操作符返回 false,不相等操作符返回 true。NaN不等于NaN。
- 如果两个操作数都是对象,则比较它们是不是同一个对象。
===
- 只有两个操作数在不转换的前提下相等才返回 true。
执行上下文(作用域)
针对变量、函数,上下文决定它们可以访问哪些数据以及它们的行为。
每个上下文都有关联一个变量对象,这个上下文中定义的所有变量和函数都在这个对象中。
全局上下文
- 浏览器中是windows对象。
上下文在所有代码都执行完毕后会被销毁,包括变量和函数,全局上下文会在应用退出销毁,如关闭网页或者退出浏览器。
每个函数都有自己的上下文,当代码执行流进入函数时,函数的上下文会被推到一个上下文栈上,函数执行完毕,上下文会弹出该函数的上下文,把控制权返还给之前的上下文。JS执行流是通过上下文栈进行控制的。
作用域链
- 上下文中的代码执行时,每进入一个新的上下文,都会创建变量对象的一个作用域链(scope chain),作用域链决定了各级上下文中的代码在访问变量和函数的顺序。
垃圾回收
- 标记清理
- 引用计数
全局对象
Global
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19undefined 特殊值 undefined
NaN 特殊值 NaN
Infinity 特殊值 Infinity
Object Object 的构造函数
Array Array 的构造函数
Function Function 的构造函数
Boolean Boolean 的构造函数
String String 的构造函数
Number Number 的构造函数
Date Date 的构造函数
RegExp RegExp 的构造函数
Symbol Symbol 的伪构造函数
Error Error 的构造函数
EvalError EvalError 的构造函数
RangeError RangeError 的构造函数
ReferenceError ReferenceError 的构造函数
SyntaxError SyntaxError 的构造函数
TypeError TypeError 的构造函数
URIError URIError 的构造函数window
1
//浏览器将 window 对象实现为 Global对象的代理
Math
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Math.ceil()方法始终向上舍入为最接近的整数。
// Math.floor()方法始终向下舍入为最接近的整数。
// Math.round()方法执行四舍五入。
// Math.fround()方法返回数值最接近的单精度(32 位)浮点值表示。
console.log(Math.ceil(25.9)); // 26
console.log(Math.ceil(25.5)); // 26
console.log(Math.ceil(25.1)); // 26
console.log(Math.round(25.9)); // 26
console.log(Math.round(25.5)); // 26
console.log(Math.round(25.1)); // 25
console.log(Math.fround(0.4)); // 0.4000000059604645
console.log(Math.fround(0.5)); // 0.5
console.log(Math.fround(25.9)); // 25.899999618530273
console.log(Math.floor(25.9)); // 25
console.log(Math.floor(25.5)); // 25
console.log(Math.floor(25.1)); // 25
//Math.random()方法返回一个 0~1 范围内的随机数,其中包含 0 但不包含 1