- Hello,这里是mouche,当然你也可以叫我某车,反正大家都爱这么叫😁
- 最近看到一些判断就想记下来,这一篇算附带自己的思考和整理的整理型的博客吧,接下去如果有想到新的也会在这一篇进行整理
- 如果有错误的可以在评论区提醒我,互相学习😊
前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
一、判断属性来源于对象本身还是原型链
思路:先判断属性是否在对象上,然后再判断是否在其本身上
👉使用in
操作符 + obj.hasOwnProperty
in操作符
: 会在通过对象能够访问给定属性时返回true
,无论该属性存在于对象本身还是其原型链上hasOwnProperty
: 会返回一个布尔值,指示对象自身属性中是否具有指定的属性- 使用:返回
true
则说明在原型链上
function isPropertyFromPrototype(obj, prop) { //属性在对象本身或原型链上,但是不在对象本身-----属性在原型链上 return (prop in obj) && ! obj.hasOwnProperty(prop) }
- 测试:
function test() { this.name = '某车'; this.said = '想工作'; } test.prototype.expect = '前端'; const obj = new test() console.log(isPropertyFromPrototype(obj, 'name')); //对象本身 console.log(isPropertyFromPrototype(obj, 'expect')); //原型链上
👉使用for..in
+ obj.hasOwnProperty
- 这里涉及遍历对象属性的五大方法,来自阮一峰老师的ES6入门
for...in
:循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。Object.keys
:返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名Object.getOwnPropertyNames
:返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名Object.getOwnPropertySymbols
:返回一个数组,包含对象自身的所有 Symbol 属性的键名Reflect.ownKeys
:返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
for...in
会遍历自身和原型链上的,辣么也是一样的道理,就遍历对象的属性,然后依次判断是否在对象本身上- 使用: 遍历对象,如果有该属性即判断是否来源其本身,来源其本身则返回
false
function isPropertyFromPrototype(obj, prop) { for(let i in obj) { if(i === prop) return !obj.hasOwnProperty(prop) } }
- 测试: 测试代码如上,打印输出如下
二、对象判空方法
- 这个要结合上面的五大方法,同时你也会发现
Symbol
在这个过程中是个怪烦人的存在(Bushi
🤜for..in
- 上面已经说过它可以循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
- 如果能够进入
for..in
循环则说明对象不为空(不考虑symbol属性)
- 初步使用
const isEmpty = function(obj){ for(let i in obj){ return false } return true }
- 测试
const objEmpty = {} //空对象 function test() {} test.prototype.except = '前端'; const obj = new test(); //有原型属性的对象 const objSym = {}; const sym = Symbol.for('symbol属性') objSym[sym] = 'symbol属性' //有symbol属性的对象 console.log(isEmpty(objEmpty)) //空对象---true console.log(isEmpty(obj)) //有原型属性的对象 -- false console.log(isEmpty(objSym)) //有symbol属性的对象 -- true --- 显然不怎么合我们意
- 那么如果考虑symbol属性的话--上面
Object.getOwnPropertySymbols
说了可以返回一个数组,包含对象自身的所有 Symbol 属性的键名,那么结合一下即可、
- 使用:
const isEmpty = function(obj){ //长度不为0则说明含有Symbol属性,直接返回false if(Object.getOwnPropertySymbols(obj).length != 0) return false for(let i in obj){ return false } return true }
- 测试(和上面一样的代码)
🤜JSON.stringify
- 使用:
const isEmpty = function(obj) { return JSON.stringify(obj) === '{}' }
- 测试(和上面一样代码)
- 你看着true,true,true,就知道问题大啦😬
JSON.stringify
算是这一系列缺陷最大的吧,本来人家也只是一个序列化的方法。不愿再爱(开发中因为不够了解然后踩坑的我😵💫)undefined
,函数
,Symbol
作为属性值,以symbol
为属性键 的时候经过JSON.stringify()
转换后会丢失, 也就是说他们会被忽略,虽然它也不仅这点问题。。。🤯
const symKey = Symbol.for('symbol属性') const test = { objMethod: function(){ console.log('属性值为方法') }, objUndefined: undefined, objSym: Symbol.for('属性值为symbol') } test[symKey] = '键为symbol' console.log(JSON.stringify(test))
🤜Object.keys()
- 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名
- so,和for...in...一样不含Symbol属性
const isEmpty = function(obj) { return Object.keys(obj).length === 0 && Object.getOwnPropertySymbols(obj).length === 0 }
还有Object.getOwnPropertyNames()
和Object.prototype.hasOwnProperty.call(obj, prop)
我觉得都差不多,就不多列举了
说是这样说,但是具体还是得看你所需要的到底是需要怎么个“空”法再对症下药🥸
三、判断数组成员
🙌indexof
indexOf()
: 返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回 -1- 语法:
indexOf(searchElement, fromIndex)
- searchElement: 寻找的元素
- fromIndex:开始寻找的下标
indexOf
使用全等运算(===)
最近我遇到它的场所应该是在数组去重
🙌includes
includes()
: 用来判断一个数组(也可以是类数组)是否包含一个指定的值,根据情况,如果包含则返回true
,否则返回false
- 语法和
indexof
一样 includes()
使用零值相等
- 拓展:Map里面判断键是否相等也是用的零值相等
- 零值相等: 跟
===
的区别为对于===
而言NaN !== NaN
, 而对于零值运算而言两者是相等
🙌find
find()
:返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined
- 语法:
find(function(element, index, array) { /* … */ }, thisArg)
element
: 当前遍历到的元素index
: 当前遍历到的索引array
:数组本身thisArg
: 执行回调时用作this的对象- 回调函数必须返回一个真值
🙌findIndex
findIndex()
: 返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1- 其他跟find差不多
🙌some
some()
: 测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个Boolean
类型的值
🙌every
every()
: 测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值
这些根据需求然后选择就好了,用法都差不多长一个样,忘了咋用的可以查查MDN
四、类型判断
这个已经算是最经典的问题了吧,
🤝typeof
- 能够判断基本类型(除了
null
),引用类型除了function
返回function
类型之外其他都返回object
NaN
的数据类型为number
null
的数据类型为Object
(转换为二进制后前三位都是000)
注意都是小写开头
🤝instancof
- instanceof 是用于检测构造函数的
prototype
属性是否出现在某个实例对象的原型链上 - 只能判断引用类型
- 具体实现可以看:instanceof的实现
🤝construtor
constructor
属性返回Object的构造函数的引用- 不能判断
undefined
和null
,并且使用它是不安全的,因为contructor
的指向是可以改变的
🤝Array.prototype.toString.call()
- 咧个嘞就是最好的方案了,啥都能咔咔咔一顿判断
toString()
返回 "[object type]",其中type
是对象的类型- 可以使用
Array.prototype.toString.call().slice(8,-1)
五、判断是否为数组
除了上面的instanceof,construtor,Array.prototype.toString.call()之外
🙏 Array.isArray
Array.isArray()
用于确定传递的值是否是一个Array
- 图源MDN(我不会说是我懒得写了)
- 最好用的方法是
Array.isArray
,只是不支持 IE8 及以下。- 如果要考虑兼容性,则可以使用
Object.prototype.toString
- so,看到的比较好的一种写法(
underscore.js
)
(obj) => return Array.isArray ? Array.isArray(obj) : Object.prototype.toString.call(obj) === '[object Array]';
六、判断是否为数字
除了上述的方法之外
✍Number.isFinite()
Number.isFinite()
: 用来检测传入的参数是否是一个有穷数, 只有数值类型的值,且是有穷的,才返回true
- 对于
NaN
,Infinity
或-Infinity
的数字,它返回false
个人感觉是比较符合平时业务的需求的
✍正则表达式
- 正则表达式则更加灵活了,可以判断整数呀,正数呀,反正就是能咔咔咔一顿改满足需求
var reg=/^[-\\+]?([0-9]+\\.?)?[0-9]+$/;
七、判断是否是通过new运算符
你可以使用寻找原型链的方法去判断(像instanceof呀,constructor呀),但是不够准确,new.target是目前最适合的方法了吧
//例如这种场景 var p = new Person('mouche','某车'); // 先new一个对象 p.fn = Person; // 把函数/类 Person 赋值给自身对象p的fn属性 p.fn(); // 这句调用时会把它判断为new调用
💪new.target
new.target
返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target
的值是undefined
这个最近的运用场景是在手写bind函数里面,需要判断是否使用了new: bind的实现
前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库