值得注意的的JS语法规则

本文介绍一些JS的特别的语法特性,大家面试前可以看看

  1. var定义的变量有变量提升,function定义的实名函数有变量提升
  2. ES5中只有全局作用域和函数作用域两个,没有局部作用域的说法,只有try…catch中的catch块算是个局部作用域
  3. typeof目前可以检测出八种值,返回值为字符串:数字(‘number’)、字符串(‘string’)、布尔值(‘boolean’)、undefined(‘undefined’)、函数对象(‘function’)、symbol值(‘symbol’)、bigInt值(‘bigint’)、狭义对象或Array或null(‘object’)
  4. instanceof用于检测左边的值是否是右边构造函数的实例(会在原型链上查找),返回值为boolean值,如果左侧的值不为对象,则返回false(不会使用包装对象)
  5. 对于转换成boolean值,只有以下六种值会当成false:undefined、null、false、0、NaN、空字符串
  6. JS中所有的数字都是以浮点数的形式存储的,所以:1 === 1.0
    小数的数字运算容易丢失精度,而整数的数字运算在结果区间(-253, 253)中是准确的。
  7. 小数点前的数字多于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
  1. NaN是唯一不等于自身的值:NaN === NaN // false, == 也一样
  2. 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
  1. JS中的单例模式:var obj = {}
  2. 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]'
  1. === 与 Object.is()的区别:
	+0 === -0 // true
	Object.is(+0, -0) // false
	NaN === NaN // false
	Object.is(NaN, NaN) // true
  1. 我们经常说的Object对象,其实是Object这个构造函数,这样理解的话,很多概念就比较好理解了。(理解了这条,之后的某些条目才能很好的理解,比如原型链相关知识)
  2. 构造函数,是函数也是对象。是对象就会有属性,其中最重要的属性就是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构造函数的实例
  1. new命令的作用原理:
	function A (arg) {} // 这里的A就是构造函数
	var obj = {} // 创建一个空对象,作为待返回的实例对象
	obj.__proto__ = A.prototype // 将实例对象的原型属性指向构造函数的原型对象
	/* this = obj // 将obj赋值给函数中的this,实际上这条语句无法也无需执行,只是为了便于理解 */
	A.call(obj[, arg]) // 执行构造函数中的代码
	// 以上三条语句的效果和 var obj = new A([, arg])是一样的
  1. 长文预警——JS中对象的继承
    算了,我还是再开一篇文章吧
  2. Object.create
    刚接触的时候感觉好强,但后来发现还是一个语法糖,正如前面的new操作符,也是语法糖一样
	// 接受两个参数,一个是返回对象的原型对象,一个是属性描述对象的集合对象
	Object.create(prototype[, propertyDescriptors])
	// 它是以下语句的语法糖
	var obj = {}
	Object.setPrototypeOf(obj, prototype)
	Object.defineProperties(obj, propertyDescriptors)
  1. 对于Array.some和Array.every,在不满足条件是会中断循环直接返回值的。
  2. String.prototype.replace(search, replacement),第二个参数可以接受一个函数,有时候能够很简单地解决某些问题。
  3. 使用RegExp构造函数,可以动态生成正则表达式,也有妙用。
  4. 正则表达式中的先行断言和后行断言,也是解决某些问题的神兵利器。
  5. JS的异步模型,也是一个重点。
    好文推荐:从浏览器多进程到 JS 单线程,JS 运行机制最全面的一次梳理
    文章中精华部分,一是浏览器进程与renderer进程、GPU进程的交互,以及renderer进程汇总各线程的关系,可以很好地回答“从浏览器输入网址到页面显示之间发生了什么?”,然后才发现这个问题真的是可浅可深;
    二是CSS能使用硬件加速以及其使用方法和注意事项,尤其是图层的概念。
    三是ES6的宏任务,微任务之别,以及各任务的优先级。这里补充一下:
      一个循环:宏任务(同步任务、异步任务)=》微任务(process.nextTick/promise/mutationObserver)=》渲染。
      其中,在循环中产生的宏任务会推入任务队列中,最早在下一个循环中执行;而在循环中产生的微任务,则直接添加到当前循环的微任务队列末尾。或者说,微任务只在当前循环产生。
  6. 初学者有时候会很头痛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
	})

参考文档

1、《JavaScript 教程》

你可能感兴趣的:(值得注意的的JS语法规则)