本文介绍一些JS的特别的语法特性,大家面试前可以看看
- var定义的变量有变量提升,function定义的实名函数有变量提升
- ES5中只有全局作用域和函数作用域两个,没有局部作用域的说法,只有try…catch中的catch块算是个局部作用域
- typeof目前可以检测出八种值,返回值为字符串:数字(‘number’)、字符串(‘string’)、布尔值(‘boolean’)、undefined(‘undefined’)、函数对象(‘function’)、symbol值(‘symbol’)、bigInt值(‘bigint’)、狭义对象或Array或null(‘object’)
- instanceof用于检测左边的值是否是右边构造函数的实例(会在原型链上查找),返回值为boolean值,如果左侧的值不为对象,则返回false(不会使用包装对象)
- 对于转换成boolean值,只有以下六种值会当成false:undefined、null、false、0、NaN、空字符串
- JS中所有的数字都是以浮点数的形式存储的,所以:1 === 1.0
小数的数字运算容易丢失精度,而整数的数字运算在结果区间(-253, 253)中是准确的。 - 小数点前的数字多于21位,小数点后的零多于5个时,会使用科学计数法表示:
// 注意,此时使用String()转换成字符串会是科学记数法的字符串
1000000000000000000000 // 1e+21,超出2^53,已经不准确了
1000000000000000001000.111111111 // 1e+21
0.0000001 // 1e-7
1.0000001 // 1.0000001,如果小数点前不为零,则不会用小数的科学记数法
0 / 0 // NaN
1 / 0 // Infinity
1 / -0 // -Infinity
- NaN是唯一不等于自身的值:
NaN === NaN // false, == 也一样
- parseInt、parseFloat、Number:
// 第一个参数必为string类型,会进行数值转换(请牢记全部转成字符串)
// 第二个参数默认值10,可以接受[2,36]中的整数,如果是0、undefined、null则仍当做10
// 返回值只可能是十进制整数或NaN
// 不能识别科学记数法
parseInt(str, number)
parseInt(0.0000001) // 1,1e-7 => '1e-7' => 1
parseInt('') // NaN
[1,10,100,1000].map(parseInt) // [1, NaN, 4, 27]
// 和parseInt类似,只接受第一个字符串参数
// 能够识别科学记数法的表示
parseFloat(str)
parseFloat('1e-2float') // 0.01
parseFloat('') // NaN
Number('') // 0
Number(null) // 0
Number(undefined) // NaN
Number(true) // 1
Number(false) // 0
Nmuber({}) // NaN
Nmuber([]) // 0
Number([23]) // 23
Nmuber([2, 3]) // NaN
- JS中的单例模式:
var obj = {}
- a + b:若a,b有一个为字符串,则两边都转成字符串(‘+’作为连接符),否则都转成数值。
a > b: 若a, b都为字符串,则按照Unicode码一一比较;若a, b都为原始类型的值,则转成数值比较;若a, b为对象等合成类型,为了转换成一个原始类型的值,会先调用valueOf方法,再调用toString方法,一般结果会是’[object Object]'类似的字符串,然后再看是否需要转数值。(PS: NaN和任何数比较都返回false)
//值得注意的是
{} == {} // false,这里比较的是两个对象的地址
{} >= {} // true, 相当于比较:'[object Object]' >= '[object Object]'
- === 与 Object.is()的区别:
+0 === -0 // true
Object.is(+0, -0) // false
NaN === NaN // false
Object.is(NaN, NaN) // true
- 我们经常说的Object对象,其实是Object这个构造函数,这样理解的话,很多概念就比较好理解了。(理解了这条,之后的某些条目才能很好的理解,比如原型链相关知识)
- 构造函数,是函数也是对象。是对象就会有属性,其中最重要的属性就是prototype属性,指向构造函数的原型对象。
这里我们要明白五个概念:
function A () {} // 这里的A就可以作为构造函数对象
A.prototype // 构造函数的原型对象
A.prototype.constructor // 原型对象上的重要属性,指向构造函数本身
var exp = new A() // exp是A的一个实例
exp.__proto__ // 浏览器环境下存在,指向它的构造函数的原型对象
// 所以可以得出以下等式
A === A.prototype.constructor
A.prototype === exp.__proto__
A === exp.__prooto__.constructor
A.__proto__ // 这里是什么?A是Function构造函数的实例
- new命令的作用原理:
function A (arg) {} // 这里的A就是构造函数
var obj = {} // 创建一个空对象,作为待返回的实例对象
obj.__proto__ = A.prototype // 将实例对象的原型属性指向构造函数的原型对象
/* this = obj // 将obj赋值给函数中的this,实际上这条语句无法也无需执行,只是为了便于理解 */
A.call(obj[, arg]) // 执行构造函数中的代码
// 以上三条语句的效果和 var obj = new A([, arg])是一样的
- 长文预警——JS中对象的继承
算了,我还是再开一篇文章吧 - Object.create
刚接触的时候感觉好强,但后来发现还是一个语法糖,正如前面的new操作符,也是语法糖一样
// 接受两个参数,一个是返回对象的原型对象,一个是属性描述对象的集合对象
Object.create(prototype[, propertyDescriptors])
// 它是以下语句的语法糖
var obj = {}
Object.setPrototypeOf(obj, prototype)
Object.defineProperties(obj, propertyDescriptors)
- 对于Array.some和Array.every,在不满足条件是会中断循环直接返回值的。
- String.prototype.replace(search, replacement),第二个参数可以接受一个函数,有时候能够很简单地解决某些问题。
- 使用RegExp构造函数,可以动态生成正则表达式,也有妙用。
- 正则表达式中的先行断言和后行断言,也是解决某些问题的神兵利器。
- JS的异步模型,也是一个重点。
好文推荐:从浏览器多进程到 JS 单线程,JS 运行机制最全面的一次梳理
文章中精华部分,一是浏览器进程与renderer进程、GPU进程的交互,以及renderer进程汇总各线程的关系,可以很好地回答“从浏览器输入网址到页面显示之间发生了什么?”,然后才发现这个问题真的是可浅可深;
二是CSS能使用硬件加速以及其使用方法和注意事项,尤其是图层的概念。
三是ES6的宏任务,微任务之别,以及各任务的优先级。这里补充一下:
一个循环:宏任务(同步任务、异步任务)=》微任务(process.nextTick/promise/mutationObserver)=》渲染。
其中,在循环中产生的宏任务会推入任务队列中,最早在下一个循环中执行;而在循环中产生的微任务,则直接添加到当前循环的微任务队列末尾。或者说,微任务只在当前循环产生。 - 初学者有时候会很头痛this指向问题。这里总结一类this指向问题:回调函数(高阶函数)中的this指向。
我们首先想清楚,我们的回调函数本质上是什么?本质上是给一个函数传递了另一个函数,而普通函数(非箭头函数,bind之后的bound函数)的传递就是传址,没有任何上下文环境。
// 我们传递的只是callback函数在内存中的地址,而内存中的callback并没有绑定this
var a = function (callback) {
callback() // 没有绑定this
}
var b = function (callback) {
this.callback() // 绑定this
}
window.value = 2
a(function () {
console.log(this.value) // 2
})
b(function () {
console.log(this.value) // 2
})
a.call({value: 1}, function () {
console.log(this.value) // 2,因为callback没有在this上调用,那指向的就是window对象
})
b.call({value: 1}, function () {
console.log(this.value) // 1
})