序言
本系列是学习前端一段时间后的整理,文中非原创内容大部分会注明出处。
基本概念
7 种数据类型: Null、Undefined、Number、Boolean、String、Object、Symbol
排除 Symbol 的话,《JavaScript 高级程序设计》中将 Undefined、Null、Number、Boolean、String 定义为基本数据类型,因为其是按值访问的,可以操作保存在变量中的实际的值。引用类型值是保存在内存中的对象,操作对象时,实际上操作的是对象的引用。
链接:js 中的值类型和引用类型的区别
如何判断变量的数据类型?
使用typeof
运算符:
- typeof 对于基本类型,除了 null 都可以显示正确的类型
- typeof 对于对象,除了函数都会显示 object
- 对于 null 来说,虽然它是基本类型,但是会显示 object,这是一个存在很久了的 Bug
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof b // b没有声明,但是还会显示undefined
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
typeof null // 'object'
使用Object.prototype.toString.call()
,该方法返回类似[object Type]
形式的字符串
let a = []
let b = {}
let c = true
let d = 'string'
let e = null
let f = undefined
let g = 1
let h = function () {}
let i = Symbol('symbol')
console.log(Object.prototype.toString.call(a)) // [object Array]
console.log(Object.prototype.toString.call(b)) // [object Object]
console.log(Object.prototype.toString.call(c)) // [object Boolean]
console.log(Object.prototype.toString.call(d)) // [object String]
console.log(Object.prototype.toString.call(e)) // [object Null]
console.log(Object.prototype.toString.call(f)) // [object Undefined]
console.log(Object.prototype.toString.call(g)) // [object Number]
console.log(Object.prototype.toString.call(h)) // [object Function]
console.log(Object.prototype.toString.call(i)) // [object Symbol]
console.log('[object Array]' === Object.prototype.toString.call(a)) // true
if 条件判断时的注意事项
数据类型 | 转换为 true 的值 | 转换为 false 的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | “” (空字符串) |
Number | 任何非零数字值(包括无穷大) | 0 和 NaN |
Object | 任何对象 | null |
Undefined | N/A(不适用) | undefined |
逻辑非
- 如果操作数是一个对象,返回 false
- 如果操作数是一个空字符串,返回 true
- 如果操作数是一个非空字符串,返回 false
- 如果操作数是数值 0,返回 true
- 如果操作数是任意非 0 的值(包括 Infinity),返回 false
- 如果操作数是 null,返回 true
- 如果操作数是 NaN,返回 true
- 如果操作数是 undefined,返回 true
四则运算注意事项
只有当加法运算时,其中一方是字符串类型,就会把另一个也转为字符串类型。其他运算只要其中一方是数字,那么另一方就转为数字。并且加法运算会触发三种类型转换:将值转换为原始值,转换为数字,转换为字符串。
1 + '1' // '11'
2 * '2' // 4
[1, 2] + [2, 1] // '1,22,1'
// [1, 2].toString() -> '1,2'
// [2, 1].toString() -> '2,1'
// '1,2' + '2,1' = '1,22,1'
对于加号需要注意这个表达式'a' + + 'b'
'a' + + 'b' // -> "aNaN"
// 因为 + 'b' -> NaN
// 你也许在一些代码中看到过 + '1' -> 1
toString() 方法的使用
数值、布尔值、对象和字符串值(没错,每个字符串也都有一个 toString() 方法,该方法返回字符串的一个副本)都有 toString() 方法。但 null 和 undefined 值没有这个方法。
多数情况下,调用 toString() 方法不必传递参数。但是,在调用数值的 toString() 方法时,可以传递一个参数:输出数值的基数。默认情况下,toString() 方法以十进制格式返回数值的字符串表示。而通过传递基数,toString() 可以输出以二进制、八进制、十六进制,乃至其他任意有效进制格式表示的字符串值。下面给出几个例子:
var num = 10
alert(num.toString()) // "10"
alert(num.toString(2)) // "1010"
alert(num.toString(8)) // "12"
alert(num.toString(10)) // "10"
alert(num.toString(16)) // "a"
变量、函数提升
在生成执行上下文时,会有两个阶段。第一个阶段是创建的阶段,JS 解释器会找出需要提升的变量和函数,并且给他们提前在内存中开辟好空间,函数的话会将整个函数存入内存中,变量只声明并且赋值为 undefined。在第二个阶段,也就是代码执行阶段,我们可以直接提前使用。在提升的过程中,相同的函数会覆盖上一个函数,并且函数优先于变量提升
简而言之:由于变量提升,使用 var 声明的变量声明前使用则值为 undefined(本作用域下),函数可以在声明之前就使用。
b() // call b
console.log(a) // undefined
var a = 'Hello world'
function b() {
console.log('call b')
}
var b = 'I am a var'
如果你想深入了解这一过程,可以 点击这里
instanceof
instanceof 运算符用于测试构造函数的 prototype 属性是否出现在对象的原型链中的任何位置
用法:对象 instanceof 构造函数
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
var auto = new Car('Honda', 'Accord', 1998);
console.log(auto instanceof Car);
// expected output: true
console.log(auto instanceof Object);
// expected output: true
Object 对象
参考:https://www.jb51.net/article/80177.htm
对象实例的一些方法
- hasOwnProperty(propertyName):接收一个字符串参数,该参数表示属性名称,用来判断该属性是否在当前对象实例中,而不是在对象的原型链中。
var arr = []
console.log(arr.hasOwnProperty("length")) // true
console.log(arr.hasOwnProperty("hasOwnProperty")) // false
// length 是 arr 自己的属性,而 hasOwnProperty 是原型链上的属性(方法)
- isPrototypeOf(Object):isPrototype 方法接收一个对象,用来判断当前对象是否在传入的参数对象的原型链上。关于原型链可参考原型与继承章节。
function MyObject() {}
var obj = new MyObject()
console.log(Object.prototype.isPrototypeOf(obj)) // true
- toString():返对象的字符串表示
- valueOf():返回对象的原始值,可能是字符串、数值、bool 值等,看具体的对象
特性操作的相关方法:
- Object.defineProperty(obj, propName, descriptor):接收三个参数,obj 是需要定义属性的对象,propName 是需要被定义 / 修改的属性名,descriptor 是属性描述符,包含一些属性的特性定义
var obj = {}
Object.defineProperty(obj, "name", {
value: "name", // 该属性的数据值,默认为 undefined
configurable: true, // 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认为 true
writable: true, // 表示能否修改属性的值,默认为 true
enumerable: true, // 表示能否通过 for-in 循环返回属性,默认为 true
get: function () {}, // 访问器属性,在读取属性时调用的函数,默认为 undefined
set: function () {} // 访问器属性,在写入属性时调用的函数,默认为 undefined
})
- Object.defineProperties():与 defineProperty 不同之处在于可以同时定义多个属性
var obj = {};
Object.defineProperty(obj, {
"name": {
value: "name",
configurable: true,
writable: true,
enumerable: true
},
"age": {
value: 20
}
})
- Object.getOwnPropertyDescriptor(obj, propName):用于读取特性值,接收对象及其属性名两个参数,返回一个对象
var person = {
_age: 10,
type: "小孩"
}
Object.defineProperty(person, "age", {
get: function () {
return this._age
},
set: function (newValue) {
this._age = newValue
this.type = newValue > 17 ? "成人" : "小孩"
}
})
console.log(Object.getOwnPropertyDescriptor(person, "type"))
// Object {value: "成人", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(person, "age"))
// Object {enumerable: false, configurable: false, get: function(),set: function ()}
其他:
- Object.getOwnPropertyNames():用于获取对象自身的所有属性,包括可枚举和不可枚举的所有属性,返回一个数组
function Parent() {
this.lastName = "Black"
}
function Child(firstName) {
this.firstName = firstName
}
Child.prototype = new Parent()
var son = new Child("Jack");
Object.defineProperty(son, "age", {
enumerable: false
})
console.log(Object.keys(son)) // ["firstName"]
console.log(Object.getOwnPropertyNames(son)) // ["firstName", "age"]
- Object.keys():用于获取给定对象的所有可枚举的自身属性的属性名,它返回一个数组,例子如上