JS 常见面试题 2
1.JS 如何实现类型判断
在 JavaScript 中,你可以使用不同的方式来进行类型判断或检查变量的类型。以下是一些常见的方法:
typeof 操作符: 使用
typeof
操作符可以检查一个变量的类型。它返回一个字符串,表示变量的数据类型。typeof 5; // "number" typeof "Hello"; // "string" typeof true; // "boolean" typeof undefined; // "undefined" typeof null; // "object"(特殊情况,实际上应为 "object") typeof {}; // "object" typeof []; // "object" typeof function () {}; // "function"
注意:
typeof null
返回"object"
是历史遗留问题,不是一个准确的类型检查方式。instanceof 操作符:
instanceof
操作符用于检查一个对象是否是指定构造函数的实例。它用于检查对象的原型链。const arr = []; arr instanceof Array; // true
注意:
instanceof
只能用于检查对象是否是某个构造函数的实例,不能用于原始数据类型的检查。Object.prototype.toString.call() 方法: 使用
Object.prototype.toString.call()
方法可以更准确地检查对象的类型。Object.prototype.toString.call(5); // "[object Number]" Object.prototype.toString.call("Hello"); // "[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([]); // "[object Array]" Object.prototype.toString.call(function () {}); // "[object Function]"
这种方法返回一个以
[object 类型]
形式表示的字符串,可以用来准确检查变量的类型。typeof 与 instanceof 的限制:
typeof
和instanceof
在某些情况下可能不够准确,尤其是对于复杂的数据类型(如数组和自定义对象)。因此,通常最好使用Object.prototype.toString.call()
来进行更精确的类型检查。
总的来说,根据具体的使用场景,你可以选择不同的方法来进行类型检查。通常,typeof
用于检查原始数据类型,instanceof
用于检查对象的构造函数,而 Object.prototype.toString.call()
用于更精确地检查对象的类型。
2. js 实现继承
在 JavaScript 中,可以使用不同的方式来实现继承。以下是一些常见的继承方式:
原型链继承: 这是 JavaScript 中最基本的继承方式。通过将子类的原型对象设置为父类的实例,子类可以继承父类的属性和方法。
function Parent() { this.name = "Parent"; } Parent.prototype.sayHello = function () { console.log("Hello from " + this.name); }; function Child() { this.name = "Child"; } Child.prototype = new Parent(); const childInstance = new Child(); childInstance.sayHello(); // "Hello from Child"
注意:原型链继承有一些缺点,例如共享父类的属性,不能传递参数给父类构造函数等。 这个是通过原型链继承的第一个问题:原型中存在引用类型的时候,原型中包含的引用值会在所有实例共享。第二个问题是创建子类实例对象的时候,无法向父类构造函数传参
构造函数继承(借用构造函数): 在子类构造函数内调用父类构造函数,从而继承父类的属性。
function Parent(name) { this.name = name; } function Child(name) { Parent.call(this, name); } const childInstance = new Child("Child"); console.log(childInstance.name); // "Child"
这种方式解决了原型链继承的一些问题,但父类的方法仍然无法被子类继承。
组合继承(原型链继承 + 构造函数继承): 这是一种常用的继承方式,结合了原型链继承和构造函数继承的优点。
function Parent(name) { this.name = name; } Parent.prototype.sayHello = function () { console.log("Hello from " + this.name); }; function Child(name) { Parent.call(this, name); } Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; const childInstance = new Child("Child"); childInstance.sayHello(); // "Hello from Child"
这种方式既可以继承父类的属性,也可以继承父类的方法。
ES6 类继承: ES6 引入了
class
和extends
关键字,更方便地实现继承。class Parent { constructor(name) { this.name = name; } sayHello() { console.log("Hello from " + this.name); } } class Child extends Parent { constructor(name) { super(name); } } const childInstance = new Child("Child"); childInstance.sayHello(); // "Hello from Child"
ES6 类继承更符合传统面向对象编程的思维方式。
选择合适的继承方式取决于你的需求和项目的架构。不同的继承方式适用于不同的情况,需要根据具体情况来决定使用哪种方式。