一. typeof
typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
1. 返回 "number"
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof(42) === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管它是 "Not-A-Number" (非数值) 的缩写
typeof Number(1) === 'number'; // Number 会尝试把参数解析成数值
2. 返回 "string"
typeof '' === 'string';
typeof 'bla' === 'string';
typeof `template literal` === 'string';
typeof '1' === 'string'; // 注意内容为数字的字符串仍是字符串
typeof (typeof 1) === 'string'; // typeof 总是返回一个字符串
typeof String(1) === 'string'; // String 将任意值转换为字符串,比 toString 更安全
3. 返回 "boolean"
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(1) === 'boolean'; // Boolean() 会基于参数是真值还是虚值进行转换
typeof !!(1) === 'boolean'; // 两次调用 ! (逻辑非) 操作符相当于 Boolean()
4. 返回 "undefined"
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined';
5. 返回 "object"
typeof {a: 1} === 'object';
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
typeof null === 'object'; // 记住
6. 返回 "function"
typeof function() {} === 'function';
typeof class C {} === 'function'
typeof Math.sin === 'function';
7. 对new 一个构造函数 的typeof
对于除了 Function 外的所有构造函数进行 new 创建一个实例,这个实例的类型都是 'object'
typeof new Number(100) === 'object';
typeof new String('String') === 'object';
new Function() 创建的实例的类型是'function'
typeof new Function() === 'function'
二.
在JS里,如果把字符串和数字相加,JS会先把数字变成字符串,进行字符串的相连
2+'4' ,返回'24'
typeof 2+3 返回的是 'number3' 。因为typeof的优先级高于+,所以先计算typeof 2 是'number',然后计算;'number'+3
三. NodeList
document.querySelectorAll会返回一个与指定的选择器组匹配的文档中的元素列表 (使用深度优先的先序遍历文档的节点)。返回的对象是 NodeList 。
返回值: 一个静态 NodeList,包含一个与至少一个指定选择器匹配的元素的Element对象,或者在没有匹配的情况下为空NodeList
NodeList 对象是节点的集合,通常是由属性,如Node.childNodes 和 方法,如document.querySelectorAll 返回的。
NodeList 不是一个数组,是一个类似数组的对象(Like Array Object)。虽然 NodeList 不是一个数组,但是可以使用 forEach() 来迭代。你还可以使用 Array.from() 将其转换为数组。
四. 关于变量的作用域
例1:
1 let a = 1
2 function fn1(){
3 function fn3(){
4 let a = 3
5 fn2()
6 }
7 let a = 2
8 return fn3
9 }
10 function fn2(){
11 console.log(a)
12 }
13 let fn = fn1()
14 fn()
a=1 的作用域:1-14行
13行执行了fn1,返回值是fn3,所以fn就是fn3。在执行fn1的时候,先定义了函数fn3,然后a=2,这个a=2的作用域就是2-9行。
14行执行fn3,跑到第三行,声明a=3,它的作用域是3-6行。
然后执行fn2,跑到第十行,打印a。可是fn2里没有a,他在a=1的作用域里,所以打印1
例2:
1 let a = 1
2 function fn1(){
3 function fn2(){
4 console.log(a)
5 }
6 function fn3(){
7 let a = 3
8 fn2()
9 }
10 let a = 2
11 return fn3
12 }
13 let fn = fn1()
14 fn()
第一行a=1的作用域:1-14行
13行执行fn1,返回fn3,所以fn就是fn3。在第二行执行fn1的时候,先定义了fn2和fn3两个函数,然后a=2的作用域:2-12行。
执行fn3,跑到第六行。a=3的作用域:6-9行。
然后执行fn2,跑到第三行,打印a。fn2里没有a。fn2在a=2的作用域里,所以打印2
五. 函数调用传参
传的参数分为基本数据类型和对象类型
function inc(n){
n++
}
let n = 10
inc(n)
console.log(n) //10
n=10,传进函数里,由于在内存图里基本数据类型存的是值,即n 里存的就是10.所以把n 里存的东西传进去,也就是把10这个值传进去了。在函数里把10+1.但是在外边调用完函数后打印n,n的值还是10。并不会改变n的值。
function inc(arr) {
arr.forEach((v, i) => arr[i]++)
}
let arr = [1, 2, 3]
inc(arr)
console.log(arr) // [2,3,4]
arr是一个数组,在内存图里arr这个名字里存的是一个地址,这个地址指向[1,2,3]。把arr当作实参传进一个函数里时,传的是地址,所以在函数里对arr里的每一项+1,会改变arr这个数组