1、undefined是未被申明的变量,或是已申明但未被赋值的变量,或并不存在的对象属性;null是无值,是一个空指针
undefined == null undefined !== null undefined类型是undefined null的类型是Object
JS中关于null、“”、undefined三者的具体区别?
2、this对象是运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。
a. 由new调用?绑定到新创建的空对象;
b. 由call、apply、bind调用?绑定到指定的参数对象;如foo.call(obj)为obj
c. 由上下文对象调用?绑定到这个上下文对象;如obj.foo()为obj。注意:如果obj.foo赋值给其它变量,则上下文环境就不再是obj了。
d. 默认情况下绑定到全局对象,foo();在严格模式下绑定到undefined;
匿名函数会创建属于自己的this,箭头函数的this是创建的时候的环境。
3、touch事件
3.1、clientX-触点相对于可见视区左边沿的的X坐标. 不包含页面滚动的偏移量.
clientY-触点相对于可见视区上边沿的的Y坐标. 不包含页面滚动的偏移量.
3.2、pageX-触点相对于整个HTML文档左边沿的的X坐标. 包含页面滚动的偏移量.
pageY-触点相对于整个HTML文档上边沿的的Y坐标. 包含页面滚动的偏移量.
3.3、screenX-触点相对于移动设备屏幕左边沿的的X坐标. 不包含页面滚动的偏移量.
screenY-触点相对于移动设备屏幕上边沿的Y坐标. 不包含页面滚动的偏移量.
4、mouse事件
4.1、clientX-鼠标相对于窗口左边沿的的X坐标. 不包含页面滚动的偏移量.
clientY-鼠标相对于窗口上边沿的的Y坐标. 不包含页面滚动的偏移量.
4.2、pageX-触点相对于整个HTML文档左边沿的的X坐标. 包含页面滚动的偏移量.
pageY-触点相对于整个HTML文档上边沿的的Y坐标. 包含页面滚动的偏移量.
4.3、screenX-触点相对于电脑屏幕左边沿的的X坐标. 不包含页面滚动的偏移量.
screenY-触点相对于电脑屏幕上边沿的Y坐标. 不包含页面滚动的偏移量.
4.4、offsetX 规定了事件对象与目标节点的内填充边在 X 轴方向上的偏移量(未进入标准,但大多浏览器支持)
offsetY规定了事件对象与目标节点的内填充边在 Y 轴方向上的偏移量(未进入标准,但大多浏览器支持)
5、在es6中,在类中直接定义的方法和使用存储器的属性会加到类的原型中,静态方法、静态属性、写在类顶层的属性和构造函数中的属性将不会添加到类的原型中(待完善)
6、window.requestAnimationFrame()
告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行,回调函数会收到一个时间戳参数,但是该时间戳不一定是实时。回调函数的执行频率通常与浏览器刷新频率相同。该方法会返回一个long型的id,将id传入 window.cancelAnimationFrame()
可以取消回调函数
var start = null;
var element = document.getElementById('SomeElementYouWantToAnimate');
element.style.position = 'absolute';
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
element.style.left = Math.min(progress / 10, 200) + 'px';
if (progress < 2000) {
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
7、Array对象的方法
a、不改变原数组,只返回新数组
1、concat() 连个两个或多个数组
2、entries() 返回数组的可迭代对象
3、every() 用于检测所有元素是否符合指定条件,有符合条件就结束遍历,可传入第二个参数作为传
入函数的this(需要传入函数)
4、filter() 将所有符合条件的元素返回,可传入第二个参数作为传入函数的this(需要传入函数)
5、find() 将第一个符合条件的元素返回,只要有符合条件的元素就结束遍历,可传入第二个参数作
为传入函数的this(需要传入函数)
6、findIndex() 将第一个符合条件的元素的索引返回,有符合条件的元素就结束遍历,可传入第二个参数
作为传入函数的this(需要传入函数)
7、forEach() 数组的每个元素都执行一次回调函数,可传入第二个参数作为传入函数的
this(需要传入函数)
8、from() 将传入的对象转为一个数组,如果没有length属性则返回空数组(Array.from())
9、includes() 判断数组中是否有指定的元素,可传入第二个参数指定起始位置
10、indexOf() 返回指定元素第一次出现的索引,没有就返回-1,可传入第二个参数指定起始位置
11、isArray() 判断传入的对象是否为数组
12、join() 将数组转为字符串,默认用','分隔
13、keys() 返回数组的可迭代对象数组
14、lastIndexOf() 返回指定元素最后一次出现的位置,可传入第二个参数指定起始位置(从后往前搜索)
15、map() 将数组中的元素按指定函数处理后返回新数组,可传入第二个参数作为传入函数的
this(需要传入函数)
16、reduce() 通过传入的函数将数组计算为一个值,可传入第二个参数作为起始值
17、reduceRight() 同reduce,但是从右往左计算
18、slice() 提取从指定位置到结束位置的元素
19、some() 判断是否有元素符合指定条件,有符合条件就结束遍历,可传入第二个参数作为传入函数
的this(需要传入函数)
21、toString() 将数组转为字符串,分隔符为','
22、valueOf() 返回数组对象原始值
b、改变原数组
1、copyWithin(target, start, end) 从数组指定位置拷贝元素到另一指定位置(target: 复制到的
目标索引,start:开始复制的索引,end:结束索引的位置、
可为负值)
2、fill() 将传入的值替换数组中所有的值
3、pop() 删除数组的最后一个元素
4、push() 往数组最后的位置插入指定元素
5、reverse() 将数组颠倒
6、shift() 删除数组的第一个元素
7、sort() 通过回调函数对数组排序,回调函数需要返回的是number型
8、splice(start, size, insertValues) 添加或删除数组
9、unshift() 往数组的头部插入一个或多个元素
8、String对象方法
9、每次for循环都会创建一个新的块级作用域
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
for循环中设置循环变量那部分是一个父级作用域,循环体的内部逻辑是子级作用域
10、属性遍历
for...in
循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。Object.keys
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。Object.getOwnPropertyNames
返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。Object.getOwnPropertySymbols
返回一个数组,包含对象自身的所有 Symbol 属性的键名。Reflect.ownKeys
返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
- 首先遍历所有数值键,按照数值升序排列。
- 其次遍历所有字符串键,按照加入时间升序排列。
- 最后遍历所有 Symbol 键,按照加入时间升序排列。
11、typeof
typeof Undefined === 'undefined'
typeof Null === 'object' // 由于历史原因造成的bug,很有可能不会变化
typeof true === 'boolean'
typeof 1 === 'number'
typeof 'b' === 'string'
typeof Symbol === 'symbol'
typeof 函数 === 'function'
typeof 其他对象 === 'object'
12、箭头函数在声明时this指向就已经确定,且无法更改。
13、Object的key都是String类型
14、Promise中调用reject不会立即结束抛出错误,会继续运行reject后面的代码
15.1、变量提升中,函数声明式定义的函数会提升到块中的最上边
a()
function a () {
console.log('a')
}
// a
15.2、在块级作用域中定义的函数的赋值原理
// 原函数
var a = 0;
if(true){
a = 1;
function a(){}
a = 21;
console.log("里面",a); // 21
}
console.log("外部",a); // 1
// 预编译后
var a; // 变量提升,块级作用域function a变量提升
var a = 0; // 实际上是直接赋值
if(true){
function a(){} // 函数提升
a = 1; // 块级作用域function a赋值为1
// function a(){}; // 原来函数定义的地方同步块级变量a到window.a
a = 21; // 块级作用域变量a重新赋值21
console.log("里面",a); // 21
}
console.log("外部",a); // 1
16、new创建实例的过程
- 创建一个空对象
- 将空对象的__proto__指向构造函数的prototype
- 调用apply,使构造函数的this指向空对象
- 如果构造函数有返回值且是对象则返回返回值,否则返回第一步创建的对象
17、部分正则理解记录
-
(?![0-9]+$)表示不匹配都是数字的
18、事件
- target指向触发的元素,currentTarget指向事件绑定的元素
19、函数名加模板字符串可以调用函数,且会根据模板字符串生成参数
let type = 'string'
function fn (...args) {
console.log(args)
}
fn`this is ${ type }.`
// [['this is ', '.'], 'string']
// args的第一个值是个不可更改的数组
20、宏任务和微任务
宏任务:指执行栈中待执行的任务,同步代码,计时器,事件回调,http回调
都是宏任务。
微任务:指执行栈清空后立即执行的任务,Promise 和 MutationObserver
都是微任务。
执行顺序:宏任务 -> 微任务 -> 微任务 -> 宏任务
- 执行栈取先进入宏任务队列的第一个宏任务,直至该宏任务的同步代码执行完后
- 检查微任务队列,有则取微任务队列的第一个执行,直至该微任务的同步代码执行完
- 继续检查微任务队列,有则继续取,没有则下一步
- 如果是浏览器,则可能渲染页面
- 开始下一轮tick(一轮event loop),检查宏任务队列
setTimeout(function () {
console.log('1')
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => {
console.log(5)
new Promise((resolve) => {
console.log(6)
resolve()
}).then(() => {
console.log(8)
})
})
new Promise((resolve) => {
console.log(3)
resolve()
}).then(() => {
console.log(7)
})
console.log(4)
}, 0)
setTimeout(function () {
console.log(9)
}, 0)
async function async1 () {
console.log(2);
await async2(); // await使后面的代码变为微任务
console.log(6)
}
async function async2 () {
console.log(3)
}
console.log(1);
setTimeout(function () {
console.log(8)
}, 0);
async1();
new Promise(function (resolve) {
console.log(4);
resolve()
}).then(function () {
console.log(7)
});
console.log(5)
21、Number类型存储原理 参考链接
js的存储标准是IEEE754,采用的双精度浮点数 。
双精度浮点数:双精度浮动共64位,第一位是符号位,用于表示正负;后面11位表示指数;后面52位是小数位;
双精度浮点数的存储方法是以科学计数法存储的。比如:
0.1的二进制是0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010(由于0.1转二进制无限循环,所以末尾会采用四舍五入,既1则进位0则反之),则存储格式为0 01111111011 1001100110011001100110011001100110011001100110011010。转换回来的的算式是:(-1) ** 0 * 2 ** -4 * (0b11001100110011001100110011001100110011001100110011010 * 2 ** -52)。
讲解:其中符号位为0表示是正数;指数由于简化负指数的计算,所以会有个指数偏移值(规定为2 ** (e - 1) - 1,其中e为存储指数的比特长度,双精度的e为11),然后0.1的二进制往左移动了4位(标准计数法(可科学计数法差不多意思)都要以1开头),所以指数位最终为指数偏移值 - 4;可以发现小数位的最左侧少了1,这是因为标准计数法都是以1开头,所以可以省去,计算的时候再加上。
22、for...in...
用于遍历对象除Symbol外可枚举属性,并且会遍历原型链上可枚举的属性
如果想只获取自身属性可用Object.getOwnPropertyNames
22、for...of...
语句在可迭代对象(包括 Array
,Map
,Set
,String
,TypedArray
,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句(MDN)
对于不同迭代对象,variable是不一样的,比如Array中,variable是数组的项,在Map中,variable是map的键名和值组成的数组([key, value])
23、set/get
如果给某一变量定义了set和get,且该变量返回的是引用值类型,则对引用值类型复制时是会触发get,但不会触发set;只有在对变量赋值时才会触发set,且不会触发get。