一、JavaScript数据类型及其判断
1.使用typeof判断数据类型
规律:返回值为字符串,基本数据类型返回对应的基本数据类型,复杂数据类型只会返回object和function,null返回object,虽然typeof null为object,但这只是JavaScript 存在的一个悠久 Bug,不代表null就是引用数据类型,并且null本身也不是对象
2.使用instanceof判断数据类型
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
例:
function Fn(a){
this.a = a
}
f = new Fn('a')
console.log(f.__proto__ === Fn.prototype); //true
console.log(f.__proto__.__proto__ === Object.prototype); //true
console.log(f instanceof Fn); //true
console.log(f instanceof Object); //true
console.log(5 instanceof Number); //false
console.log(new Number(5) instanceof Number); //true
上述代码中,5是基本类型不是对象,所以返回false,new Number(5)是对象,所以返回true。
Object在f对象的原型链上,所以instanceof返回true
下面实现一下instanceof
function newInstance(obj,ctor){
if(typeof obj !== 'object'){
return false
}
while(1){
if(ctor === null){
return false
}
if(obj.__proto__ === ctor.prototype){
return true
}
obj = obj.__proto__
}
}
function Fn(a){
this.a = a
}
f = new Fn('a')
console.log(newInstance(f,Fn)); //true
console.log(newInstance(f,Object)); //true
3、使用constructor和Object.prototype.toString判断数据类型
console.log(Object.prototype.toString.call(1)); //[object Number]
console.log(Object.prototype.toString.call('1')); //[object String]
console.log(Object.prototype.toString.call(undefined));//[object Undefined]
console.log(Object.prototype.toString.call(null));//[object Null]
console.log(Object.prototype.toString.call(true));//[object Boolean]
console.log(Object.prototype.toString.call(Symbol('1')));//[object Symbol]
console.log(Object.prototype.toString.call(function(){}));//[object Function]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call({}));//[object Object]
Object.prototype.toString是万能方法,什么类型都能判断,通过slice(8,-1))就可以拿到大写开头的数据类型了
console.log(Object.prototype.toString.call(1).slice(8,-1)); //Number
constructor返回变量的构造函数,但是null和undefined类型会报错
var a = 5
console.log(a.constructor); //[Function: Number]
二、JavaScript数据类型及其转换
JavaScript是一种弱类型,或者说是一个动态语言,不用声明变量的数据类型,在程序运行中,变量的数据类型会被自动确定
例:
console.log(1 + '1'); //11
console.log('1' + true); //1true
console.log(1 + true); //2
console.log(1 + undefined); //NaN
console.log(1 + null); //1
console.log(1 + true); //2
console.log(1 + false); //1
console.log({} + true); //[object Object]true
由以上例子可得出规律:string类型和其他数据类型相加时,其他数据类型会转成string类型。其他情况都会转成number类型,undefined类型会转成NaN,相加结果为NaN,true转为1,false转为0.
如果相加俩侧存在复杂类型,复杂类型会转成基本类型,再进行计算。
在转换时会用对象的valueOf或toString方法,这俩方法的返回值为转换的结果。具体用哪个方法,从主观上说,这个对象倾向转成什么,就优先调用哪个方法,对象倾向转为string类型就用toString方法,倾向转为number类型就调用valueOf方法。
valueOf和toString是可以被开发者重写的
const obj = {
toString(){
return '1'
},
valueOf(){
return 1
}
}
console.log(2 + obj); //3
console.log('2' + obj); //21
可以看到与字符串相加时,调用了toString,与数字相加时调用了valueOf
三、JavaScript函数参数传递
先看个例子
var foo = {n:1};
var a = 1
function fan(foo,a){
console.log(foo.n); //1
foo.n = 2
a = 2
foo = {}
foo.n = 3
console.log(foo); //{ n: 3 }
}
fan(foo,a)
console.log(foo.n,a); //2 1
如果参数是基本类型,会在函数体内复制一份参数值,不会影响原参数,按我理解就是在声明个变量接收了这个基本类型的值。如果参数是引用类型,则声明的变量指向了这个参数的引用地址,所以修改某个属性,原参数也会跟着变,当把指向改变了,任何操作就对原参数没有影响了。
四、cannot read property of undefined问题解决方案
cannot read property of undefined是很常见的错误,当不知道对象某属性是否存在时,要如何避免报错呢
例
var user = {
a: { b: { c: { msg: 'good' } } }
}
1.通过短路运算符进行可访问性嗅探
var user = {
a: { b: { c: { msg: 'good' } } }
}
console.log( user.a && user.a.b && user.a.b.c && user.a.b.c.msg); //good
console.log( user.a && user.a.b && user.a.b.c && user.a.b.c.mmm); //undefined
2. 通过||单元设置默认值保底值
var user = {
a: { b: { c: { msg: 'good' } } }
}
console.log( ( ( (user.a || {}).b || {} ).c || {} ).msg ); //good
console.log( ( ( (user.a || {}).b || {} ).c || {} ).mmm ); //undefined
3.使用try…catch
var result
try {
result = user.a.b.c.mmm.a
} catch (error) {
result = null
}
console.log(result); // null
4.简易的get方法
const get = (p, o) => p.reduce( (xs,x)=>(xs&&xs[x]) ? xs[x] : null, o)
console.log(get(['a','b','c','msg'],user)); //good
console.log(get(['a','b','c','mmm'],user)); //null
进行柯里化
const newGet = p => o => p.reduce((xs,x) => (xs&&xs[x]) ? xs[x] : null, o)
const fbn = newGet(['a','b','c','msg'])
console.log(fbn(user)); //good
console.log(fbn( {a:{b:{}}} )); //null