个人型网站开站费用,wordpress怎么加属性,青海西宁高端网站建设,东莞网站推广电话文章目录 JavaScript 类型及其判断使用 typeof 判断类型使用 instanceof 判断类型使用 constructor 和 Object.prototype.toString 判断类型JavaScript 类型及其转换JavaScript 函数参数传递cannot read property of undefined 问题解决方案分析一道网红题目JavaScript 类型判断… 文章目录 JavaScript 类型及其判断使用 typeof 判断类型使用 instanceof 判断类型使用 constructor 和 Object.prototype.toString 判断类型JavaScript 类型及其转换JavaScript 函数参数传递cannot read property of undefined 问题解决方案分析一道网红题目JavaScript 类型判断总结 ✍创作者全栈弄潮儿 个人主页 全栈弄潮儿的个人主页 ️ 个人社区欢迎你的加入全栈弄潮儿的个人社区 专栏地址欢迎订阅前端架构师之路 JavaScript 类型及其判断
JavaScript 具有七种内置数据类型它们分别是
nullundefinedbooleannumberstringobjectsymbol
其中前面五种为基本类型。第六种 object 类型又具体包含了 function、array、date 等。
对于这些类型的判断我们常用的方法有
typeofinstanceofObject.prototype.toStringconstructor
使用 typeof 判断类型
基本类型可以使用 typeof 来判断
typeof 5 // number
typeof lucas // string
typeof undefined // undefined
typeof true // boolean但是也存在着一些特例比如用 typeof 判断 null 时
typeof null // object我们再看使用 typeof 判断复杂类型时的表现
const foo () 1
typeof foo // functionconst foo {}
typeof foo // objectconst foo []
typeof foo // objectconst foo new Date()
typeof foo // objectconst foo Symbol(foo)
typeof foo // symbol因此我们可以总结出使用 typeof 可以准确判断出除 null 以外的基本类型以及 function 类型、symbol 类型null 会被 typeof 判断为 object。
使用 instanceof 判断类型
再来看看 instanceof
使用 a instanceof B 判断的是a 是否为 B 的实例即 a 的原型链上是否存在 B 构造函数 。因此如果我们使用
function Person(name) {this.name name
}
const p new Person(lucas)p instanceof Person
// true这里 p 是 Person 构造出来的实例。同时顺着 p 的原型链也能找到 Object 构造函数
p.__proto__.__proto__ Object.prototype因此
p instanceof Object// true原型原型链的知识我们会在后续章节中介绍这里只需要理解 instanceof 的判断原理即可。另外一个细节需要注意
5 instanceof Number // false返回 false是因为 5 是基本类型它并不是 Number 构造函数构造出来的实例对象如果
new Number(5) instanceof Number // true结果返回 true。 我们使用以下代码来模拟 instanceof 原理
// L 表示左表达式R 表示右表达式
const instanceofMock (L, R) {if (typeof L ! object) {return false}while (true) { if (L null) {// 已经遍历到了最顶端return false}if (R.prototype L.__proto__) {return true}L L.__proto__}
}L 表示左表达式R 表示右表达式我们可以如此使用
instanceofMock(, String)// falsefunction Person(name) {this.name name
}
const p new Person(lucas)instanceofMock(p, Person)// true使用 constructor 和 Object.prototype.toString 判断类型
使用 constructor 可以查看目标的构造函数这也可以进行类型判断但也存在着问题具体请看 var foo 5 foo.constructor // ƒ Number() { [native code] }
var foo ‘Lucas’ foo.constructor // ƒ String() { [native code] }
var foo true foo.constructor // ƒ Boolean() { [native code] }
var foo [] foo.constructor // ƒ Array() { [native code] }
var foo {} foo.constructor // ƒ Object() { [native code] }
var foo () 1 foo.constructor // ƒ Function() { [native code] }
var foo new Date() foo.constructor // ƒ Date() { [native code] }
var foo Symbol(“foo”) foo.constructor // ƒ Symbol() { [native code] }
var foo undefined foo.constructor // VM257:1 Uncaught TypeError: Cannot read property ‘constructor’ of undefined at :1:5
var foo null foo.constructor // VM334:1 Uncaught TypeError: Cannot read property ‘constructor’ of null at :1:5
我们发现对于 undefined 和 null如果尝试读取其 constructor 属性将会进行报错。并且 constructor 返回的是构造函数本身一般使用它来判断类型的情况并不多见。
使用 Object.prototype.toString 判断类型我们称之为“万能方法”“终极方法” console.log(Object.prototype.toString.call(1)) // [object Number]
console.log(Object.prototype.toString.call(‘lucas’)) // [object String]
console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
console.log(Object.prototype.toString.call(true)) // [object Boolean]
console.log(Object.prototype.toString.call({})) // [object Object]
console.log(Object.prototype.toString.call([])) // [object Array]
console.log(Object.prototype.toString.call(function(){})) // [object Function]
console.log(Object.prototype.toString.call(null)) // [object Null]
console.log(Object.prototype.toString.call(Symbol(‘lucas’))) // [object Symbol]
JavaScript 类型及其转换
JavaScript 的一个显著特点就是“灵活”。“灵活”的反面就是猝不及防的“坑”多其中一个典型的例子就是被诟病的类型“隐式转换”。
MDN 这样介绍过 JavaScript 的特点JavaScript 是一种弱类型或者说动态语言。这意味着你不用提前声明变量的类型在程序运行过程中类型会被自动确定。
我们再来看一些基本例子在使用加号进行运算时
console.log(1 1)
// 11console.log(1 true)
// 2console.log(1 false)
// 1console.log(1 undefined)
// NaNconsole.log(lucas true)
// lucastrue我们发现
当使用 运算符计算 string 和其他类型相加时都会转换为 string 类型其他情况都会转换为 number 类型但是 undefined 会转换为 NaN相加结果也是 NaN 比如布尔值转换为 number 类型true 为 1false 为 0因此
console.log(1 true)
// 2console.log(1 false)
// 1console.log(false false)
// 0console.log(true true)
// 2再看代码
console.log({} true)
// [object Object]true在 号两侧如果存在复杂类型比如对象那么这到底是怎样的一套转换规则呢
当使用 运算符计算时如果存在复杂类型那么复杂类型将会转换为基本类型再进行运算。
这就涉及到“对象类型转基本类型”这个过程。具体规则对象在转换基本类型时会调用该对象上 valueOf 或 toString 这两个方法该方法的返回值是转换为基本类型的结果。
那具体调用 valueOf 还是 toString 呢这是 ES 规范所决定的实际上这取决于内置的 toPrimitive 调用结果。主观上说这个对象倾向于转换成什么就会优先调用哪个方法。如果倾向于转换为 Number 类型就优先调用 valueOf如果倾向于转换为 String 类型就只调用 toString。
valueOf 以及 toString 是可以被开发者重写的。比如
const foo {toString () {return lucas},valueOf () {return 1}
}我们对 foo 对象的 valueOf 以及 toString 进行了重写这时候调用
alert(foo)输出lucas。这里就涉及到“隐式转换”在调用 alert 打印输出时“倾向于使用 foo 对象的 toString 方法将 foo 转为基本类型”得以打印出结果。 然而
console.log(1 foo)输出2这时候的隐式转换“倾向于使用 foo 对象的 valueOf 方法将 foo 转为基本类型”得以进行相加。
我们再全面总结一下对于加法操作如果加号两边都是 Number 类型其规则为
如果 号两边存在 NaN则结果为 NaNtypeof NaN 是 ‘number’如果是 Infinity Infinity结果是 Infinity如果是 -Infinity (-Infinity)结果是 -Infinity如果是 Infinity (-Infinity)结果是 NaN
如果加号两边有至少一个是字符串其规则为
如果 号两边都是字符串则执行字符串拼接如果 号两边只有一个值是字符串则将另外的值转换为字符串再执行字符串拼接如果 号两边有一个是对象则调用 valueof() 或者 toStrinig() 方法取得值转换为基本类型再进行字符串拼接。
当然也可以进行显式转换我们往往使用类似 Number、Boolean、String、parseInt 等方法进行显式类型转换。
JavaScript 函数参数传递
我们知道 JavaScript 当中有“引用赋值”和“基本类型赋值”以及相关概念“深拷贝”、“浅拷贝”区分。那么函数的参数传递有什么讲究呢请看例题
let foo 1
const bar value {value 2console.log(value)
}
bar(foo)
console.log(foo) 两处输出分别为 2、1也就是说在 bar 函数中参数为基本类型时函数体内复制了一份参数值而不会影响参数实际值。
let foo {bar: 1}
const func obj {obj.bar 2console.log(obj.bar)
}
func(foo)
console.log(foo)两处输出分别为 2、{bar: 2}也就是说如果函数参数是一个引用类型当在函数体内修改这个引用类型参数的某个属性值时将会对参数进行修改。因为这时候函数体内的引用地址指向了原来的参数。
但是如果在函数体内直接修改了对参数的引用则情况又不一样
let foo {bar: 1}
const func obj {obj 2console.log(obj)
}
func(foo)
console.log(foo)两处输出分别为 2、{bar: 1}这样的情况理解起来较为晦涩其实总结下来就是
参数为基本类型时函数体内复制了一份参数值对于任何操作不会影响参数实际值函数参数是一个引用类型时当在函数体内修改这个值的某个属性值时将会对参数进行修改函数参数是一个引用类型时如果我们直接修改了这个值的引用地址则相当于函数体内新创建了一份引用对于任何操作不会影响原参数实际值
cannot read property of undefined 问题解决方案
这里我们分析一个常见的 JavaScript 细节cannot read property of undefined 是一个常见的错误如果意外的得到了一个空对象或者空值这样恼人的问题在所难免。
考虑这样的一个数据结构
const obj {user: {posts: [{ title: Foo, comments: [ Good one!, Interesting... ] },{ title: Bar, comments: [ Ok ] },{ title: Baz, comments: []}],comments: []}
}为了在对象中相关取值的过程需要验证对象每一个 key 的存在性。常见的处理方案有 短路运算符进行可访问性嗅探
obj.user
obj.user.posts
obj.user.posts[0]
obj.user.posts[0].comments|| 单元设置默认保底值
(((obj.user || {}).posts||{})[0]||{}).comments try…catch
var result
try {result obj.user.posts[0].comments
}
catch {result null
}最后TC39 提案中有一个新的提案支持 console.log(obj?.user?.posts[0]?.comments)
由此可见JavaScript 语言也在不断演进。通过这个案例想告诉大家熟练掌握基础环节将对于进阶起到关键作用。
分析一道网红题目
综合以上知识点我们来看一道“网红”题目 Can (a 1 a 2 a 3) ever evaluate to true? 即 a 1 a 2 a 3 可能为 true 吗 直观上分析如果变量 a 是一个基本 Number 类型这是不可能为 true 的因此解题思路也需要从变量 a 的类型及对象转换基本类型上来考虑。
方案一
const a {value: 1,toString: function () {return a.value}
}
console.log(a 1 a 2 a 3) // true这个方案中我们将 a 定义为一个对象并重写了其 toString 方法。因此在每次进行判断时按照规则 号两边出现了对象类型另一边是 Number 类型需要调用 a 对象 toString 方法toString 方法的返回值会作为对象转为基本类型的值我们每次将 value 属性加 1。同样如果按照相同的方式重写 valueOf 方法也是可以达到同样目的的。
方案二
let value 0
Object.defineProperty(window, a, {get: function() {return value}
})console.log(a 1 a 2 a 3) // true这里我们将 a 作为属性挂载在 window 对象当中重写其 getter 方法。
JavaScript 类型判断总结
通过 x null 来判断 null 类型对于 typeof x 不为 object 的情况直接返回 typeof x 结果这时候可以判断出 numberstringbooleanundefinedsymbol 类型Object.prototype.toString 方法该方法确实可以称得上“终极方案”。对返回结果使用 .slice(8, -1)更加方便拿到结果
Object.prototype.toString.call(true).slice(8, -1)
// Boolean