看完这篇文章,你将了解:
- 展开运算符在哪使用
- 解释型语言是什么
- 补充三种跨域 tricks
- 描述页面性能的时间点 (什么是 first paint, domready, onload)
- JS 的浮点数问题 (.2 + .4 !== .6 怎么办)
- 可迭代对象
- 用 Object.prototype.toString 检测对象类型
- instanceof 的用法与定义
展开运算符
根据 MDN ,在遇到以下情形时可以考虑展开运算符
- 函数传参
- 数组构造
- 数组或对象克隆
比如
// 函数传参
function myFunction(x, y, z) {}
var args = [0, 1, 2]
myFunction(...args) // 可用 apply 代替
var dataFields = [2000, 1, 1]
var d = new Date(...dateField) // 不可用 apply 代替
// 数组构造
var parts = ['a', 'b']
var lyrics = [...parts, 'c', 'd', 'e']
// 数组克隆
var arr = [1, 2, 3]
var arr2 = [...arr] // 可用 arr.slice() 代替
// 此时 arr2 与 arr 一样而 arr 不受影响(若 arr 不含引用类型成员)
// 对象克隆
var obj = {a: 1, b: 2}
var obj2 = {...obj} // 可用 JSON.parse(JSON.stringify()) 代替
// 此时 obj2 与 obj 一样而 obj 不受影响(若 obj 不含引用类型值)
此外,还可以通过以下方式赋值
let [head, ...tail] = [1, 2, 3, 4]
console.log(head) // 1
console.log(tail) // [2, 3, 4]
解释性语言
解释性语言是相对于编译型语言而言的。
先将程序编译成机器语言,然后再运行编译后的文件的就是编译型语言, 如 C++, 先生成 exe,再运行 exe 文件
边解释边运行程序的就是解释型语言,如 JavaScript,不借助中间文件
跨域补充
参考这篇文章, 除了 jsonp 外,还可以用以下方式跨域
衡量页面性能的四个时间点
- 白屏时间(first Paint Time)——用户从打开页面开始到页面开始有东西呈现为止
- 首屏时间——用户浏览器首屏内所有内容都呈现出来所花费的时间
- 用户可操作时间(dom Interactive)——用户可以进行正常的点击、输入等操作,默认可以统计 domready 时间,因为通常会在这时候绑定事件操作
- 总下载时间——页面所有资源都加载完成并呈现出来所花的时间,即页面 onload 的时间
时间顺序是:first paint → 首屏 → domready → onload
Javascript 的浮点数计算问题
.2 + .4 === .6 // false
.2 + .4 === .6000000000000001 // true
解决方法是
// 如果是判断式,用 Number.EPSILON
Math.abs(.2 + .4 - .6) < Number.EPSILON
// 如果是计算式,用 toFixed()
(.2 + .4).toFixed(1) // .6
注意:这里补充一下浮点数的 toFixed 方法与 toPrecision 方法的区别
- toFixed(n): 固定小数位数为 n,toPrecision(n): 固定有效位数为 n
- toFixed 返回小数,toPrecision 返回字符串
1.08.toFixed(1) // 1.1
1.08.toPrecision(1) // 1
可迭代对象
根据 MDN ,可迭代对象是指:
一个实现了 @@iterator
方法的对象,该对象可以在原型链上找到 Symbol.iterator
属性
比如数组:
可迭代对象的特点是可以通过 for a of obj
遍历,并且 for a of obj
遍历的时候会调用 @@iterator
方法。该方法返回一个迭代器
根据标准,JS 内置的可迭代对象有以下几种:
// 1)数组
for(let x of ['a','b'])
console.log(x)
// 2)字符串
for(let x of "abc")
console.log(x)
// 3)Map
let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
console.log(pair);
}
// 4)Set
let set = new Set().add('a').add('b');
for (let x of set) {
console.log(x);
}
// 5)arguments
function printArgs() {
for (let x of arguments) {
console.log(x);
}
}
printArgs('a', 'b');
// 6)Typed Arrays
// 7)Generators
可以通过以下方法判断一个对象是否为可迭代对象
var arr = [1, 2, 3, 4]
// 能否用 for of 遍历
for (a of arr) {console.log(a)}
// 是否有 Symbol.iterator 方法
typeof a[Symbol.iterator]
注意可迭代对象和迭代器是不同的,区别在于:
- 可迭代对象:实现了
@@iterator
方法 - 迭代器:实现了
next
方法
同时可迭代协议和迭代器协议也是不同的,区别在于:
- 可迭代协议:允许 JS 对象定制自己的迭代行为,比如定义在一个
for a of obj
中什么样的值可以被遍历 - 迭代器协议:定义一个标准的方式来产生有限或无限序列的值,所有值完成遍历后返回默认值
Object.prototype.toString.call(obj) 对象类型检测
有一个问题,如何判断一个 js 对象是数组类型
Array.isArray // 对
instanceof // 对
typeof // 错
Object.prototype.toString // 对
作为答案之一,今天知道了一个方法 Object.prototype.toString.call(obj)
根据 MDN
toString()
can be used with every object and allows you to get its class. To use theObject.prototype.toString()
with every object, you need to callFunction.prototype.call()
orFunction.prototype.apply()
on it, passing the object you want to inspect as the first parameter calledthisArg
.
instanceof 的用法与定义
之前疑惑的一点是:
var arr = new Array(1, 2, 3, 4)
arr instanceof Array // true
arr instanceof Object // true
为什么 instanceof 允许与两个不同的值运算为 true?
IBM Developer 上的一篇文章解决了我的困惑
通常来讲,使用 instanceof 就是判断一个实例是否属于某种类型。例如:
// 判断 foo 是否是 Foo 类的实例 function Foo(){} var foo = new Foo(); console.log(foo instanceof Foo) //true
另外,更重要的一点是 instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型。例如:
// 判断 foo 是否是 Foo 类的实例 , 并且是否是其父类型的实例 function Aoo(){} function Foo(){} Foo.prototype = new Aoo(); //JavaScript 原型继承 var foo = new Foo(); console.log(foo instanceof Foo) //true console.log(foo instanceof Aoo) //true
JavaScipt instanceof 运算符代码 (ps: 这不就是链表查找么)
function instance_of(L, R) { //L 表示左表达式,R 表示右表达式 var O = R.prototype; // 取 R 的显示原型 L = L.__proto__; // 取 L 的隐式原型 while (true) { if (L === null) return false; if (O === L) // 这里重点:当 O 严格等于 L 时,返回 true return true; L = L.__proto__; } }
金句
- 展开运算符可以用于函数传参,构造数组,克隆对象
- document.domain, window.name, postMessage 可以跨域
- 衡量页面性能的四个指标依次是 first paint, 首屏, domready, onload
- toFixed 是固定小数位数, toPrecision 是固定有效位数
- 可迭代对象是指一个实现了 @@iterator 方法的对象,可以用 for of 遍历
- 可以用 Object.prototype.toString.call 方法检测一个对象种类
- instanceof 本质是定义在原型链上的链表查找
暂无评论