# JS 的高频题库
# 数据类型判断
综述
js 中有 7 种内置数据类型,分别的 null、undefined、boolean、number、string、object 和 symbol(ES6)。前五种是基本数据类型。object 类型又具有 function、array、date 等。(后续会新增一种 BigInt 类型)
判断类型的常见方法有四种 typeo、instance、Object.prototype.toString、constructor
# typeof 判断
typeof 5; // number
typeof "string"; // string
typeof undefined; // "undefined"
typeof true; // boolean
基本类型的也有特例,就是 null
typeof null; // "object"
复杂数据类型判断
const foo = () => 1;
typeof foo; // "function"
const foo = {};
typeof foo; // "object"
const foo = [];
typeof foo; // "object"
const foo = new Date();
typeof foo; // "object"
const foo = Symbol("foo");
typeof foo; // "symbol"
综上所述:typeof 能准确的判断除了 null 之外的基本数据类型,能准确判断 function 类型、symbol 类型。null 以及其他的复杂数据类型得到的结果都是 object。
# instanceof 判断
所谓 a instanceof B
的意思就是判断 a 是否为 B 的实例,即 a 的原型链上是否存在 B 的构造函数。
function Person(name) {
this.name = name;
}
const p = new Person("lucy");
p instanceof Persion; // true
p 是 Persion 构造出来的实例对象。顺着 p 的原型链也能找到 Object 的构造函数。即:
p.__proto__.__proto__ = Object.prototype;
看另一个:由于 5 是基本类型,不是 Number 构造函数构造出来的实例对象所以报错。换一种方式就可以了
5 instanceof Number; // false
new Number(5) instanceof Number; // true
来实现一个简单的 instanceof
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__;
}
};
# constructor
- 下述得到的类型的类型都是函数,也就是
typeof foo.constructor
是 function。后续无法使用 - 该方法无法判断 null 与 undefined
ar foo = 5
console.log(foo.constructor) // ƒ Number() { [native code] }
var foo = 'string'
console.log(foo.constructor) // ƒ String() { [native code] }
var foo = true
console.log(foo.constructor) // ƒ Boolean() { [native code] }
var foo = []
console.log(foo.constructor) // ƒ Array() { [native code] }
var foo = {}
console.log(foo.constructor) // ƒ Object() { [native code] }
var foo = () => 1
console.log(foo.constructor) // ƒ Function() { [native code] }
var foo = new Date
console.log(foo.constructor) // ƒ Date() { [native code] }
console.log(Object.prototype.toString.call(foo))
var foo = Symbol("foo")
console.log(foo.constructor) // ƒ Symbol() { [native code] }
var foo = undefined
console.log(foo.constructor) // 报错:Uncaught TypeError: Cannot read properties of undefined (reading 'constructor')
var foo = null
console.log(foo.constructor) // Uncaught TypeError: Cannot read properties of null (reading 'constructor')
# 终极方法 Object.prototype.toString
Object.prototype.toString.call(1); // '[object Number]'
Object.prototype.toString.call("string"); // '[object String]'
Object.prototype.toString.call(true); // '[object Boolean]'
Object.prototype.toString.call(undefined); // '[object Undefined]'
Object.prototype.toString.call(null); // '[object Null]'
Object.prototype.toString.call({}); // '[object Object]'
Object.prototype.toString.call(function () {}); // '[object Function]'
Object.prototype.toString.call([]); // '[object Array]'
Object.prototype.toString.call(Symbol("lucy")); // '[object Symbol]'
Object.prototype.toString.call(new Date()); // '[object Date]'
# 数据类型转换
console.log(1 + "1"); // 11
console.log(1 + true); // 2
console.log(1 + false); // 1
console.log(1 + undefined); // NaN
console.log("string" + true); // stringtrue
运算符 + 计算 string 类型和其他数据类型时,其他数据类型会转换成 string 类型。其他情况,都会转成 number 类型,但是 undefined 类型会转换为 NaN,相加之后也是 NaN。
console.log({} + true); // [object Object]true
如果运算符 + 有复杂数据类型,比如对象。复杂数据类型会先转变成基本数据类型。
其中“对象类型转基本类型” 这个过程的规则是在转换时,会调用该对象上的 valueOf 或 toString 方法,这两个方法的返回值是转换后的结果。一般情况下会先调用 valueof 再调用 toString。
总结
- 如果 + 操作两侧都是 number 类型
- 如果 + 运算符两边存在 NaN,则结果为 NaN
- 如果是 Infinity + Infinity,结果是 Infinity
- 如果是 -Infinity + (-Infinity),结果是 -Infinity
- 如果是 Infinity + (-Infinity),结果是 NaN
- 如果 + 运算符两边有一个是字符串
- 如果两边都是字符串,则执行字符串拼接操作
- 如果两边只有一个字符串,则另一个会转成字符串,再执行字符串拼接操作
- 如果两边有一个是对象,则调用对象的 valueOf 或 toString 方法取值,转成基本数据类型再进行字符串拼接。
# 函数参数传递
综述
- 函数参数为基本类型时,函数体内复制了一份参数值,任何操作都不会影响原参数的实际值
- 函数参数时引用类型时,当在函数体内修改这个值的某个属性值时,将会对原来的参数进行修改
- 函数参数是引用类型时,如果直接修改这个值的引用地址,则相当于创建了一个新的引用,任何操作都不会影响原参数的实际值
// 情况1
let foo = 1;
const bar = (value) => {
value = 2;
console.log(value);
};
bar(foo); // 2
console.log(bar); // 1
// 情况2
let foo = { bar: 1 };
const fun = (obj) => {
obj.bar = 3;
console.log(obj.bar);
};
fun(foo); // 3
console.log(foo); // 3
// 情况3
let foo = { bar: 1 };
const fun = (obj) => {
obj = 3;
console.log(obj);
};
fun(foo); // 3
console.log(foo); // { bar: 1}