整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

深入解析JavaScript中的数据类型检测方法及其

深入解析JavaScript中的数据类型检测方法及其适用场景

avaScript中的数据类型检测是一个重要的概念,它涉及到如何确定一个变量或者值的类型。在JavaScript中,有多种方法可以用来检测数据类型,包括typeof、instanceof、Object.prototype.toString、Array.isArray和NaN判断等。下面将详细介绍这些数据类型检测方案:


typeof

  • 基本用法:typeof是一个内置的操作符,用于检测给定变量的数据类型。它可以返回如"number"、"string"、"boolean"、"object"、"function"和"undefined"等字符串。
  • 用途与限制:typeof对于基本数据类型(如number、string、boolean、undefined、function)的检测非常可靠。然而,对于null和所有对象(包括数组和对象),typeof都会返回"object",这可能导致一些误判。

instanceof

  • 基本用法:instanceof用于检测构造器函数的prototype属性是否出现在某个对象的原型链上。如果是,则返回true;否则返回false。
  • 用途与限制:instanceof适合用于自定义的对象类型检测,因为它可以检查一个对象是否是一个特定构造器的实例。但对于原生对象类型(如Number、String、Boolean),在大多数情况下,使用instanceof并不是一个好主意,因为这些类型的构造器函数并不保证能够准确识别出相应类型的值。

Object.prototype.toString

  • 基本用法:通过调用一个对象的Object.prototype.toString方法,可以得到一个格式化的字符串,这个字符串包含了对象的具体类型信息。
  • 用途与限制:Object.prototype.toString.call(value)可以说是JavaScript中最准确的类型检测方法之一,能够区分数组、null以及其他各种内置对象。但是,这种方法需要记住的代码比较多,语法也相对冗长。

Array.isArray

  • 基本用法:Array.isArray(value)用于检测给定的值是否是一个数组。
  • 用途与限制:该方法专门用于数组的检测,简单且直接。但它只能用于检测数组,对于其他类型的检测无能为力。

NaN判断

  • 基本用法:在JavaScript中,NaN是一个特殊的值,表示“非数字”。由于NaN是唯一与自身不相等的值,因此可以使用value !==value来判断一个值是否是NaN。此外,还可以使用Number.isNaN(value)来进行更准确的判断。
  • 用途与限制:这种方法专用于检测NaN,对于其他类型的检测不适用。

综上所述,JavaScript提供了多种数据类型检测方案,每种方案都有其用途和限制。在实际开发中,应根据具体需求选择合适的方法来确保数据类型的正确判断。


JavaScript中,有多种方法可以判断一个变量的数据类型。以下是一些常见的方法:

  1. typeof 操作符

typeof 是JavaScript中的一元操作符,返回一个表示未计算变量类型或已计算对象类型的字符串。但是,需要注意的是 typeof 对于 null 和 array 的处理可能不是你所期望的:


console.log(typeof undefined);    // "undefined"  
console.log(typeof 123);          // "number"  
console.log(typeof 'hello');      // "string"  
console.log(typeof true);         // "boolean"  
console.log(typeof {});           // "object"  
console.log(typeof []);           // "object" 而不是 "array"  
console.log(typeof null);         // "object" 而不是 "null"  
console.log(typeof function(){}); // "function"
  1. instanceof 操作符

instanceof 操作符用于检测构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。这主要用于检测对象是否属于某个类。

console.log([] instanceof Array);  // true  
console.log(null instanceof Object); // false,因为 null 不是一个对象
  1. Array.isArray() 方法

这是检测一个值是否为数组的最佳方法。

console.log(Array.isArray([]));  // true  
console.log(Array.isArray({}));  // false
  1. Object.prototype.toString.call() 方法

这个方法返回表示该对象的字符串。对于检测原始值类型,特别是当 typeof 给出不直观的结果时(如 null 和 array),这是一个很有用的方法。

function getType(obj) {  
    return Object.prototype.toString.call(obj).slice(8, -1);  
}  
  
console.log(getType(null));       // "Null"  
console.log(getType([]));         // "Array"  
console.log(getType({}));         // "Object"  
console.log(getType(123));        // "Number"  
console.log(getType('hello'));    // "String"  
console.log(getType(true));       // "Boolean"  
console.log(getType(undefined));  // "Undefined"
  1. constructor 属性

每个JavaScript对象都有一个 constructor 属性,它指向创建该对象的构造函数。但请注意,如果 constructor 被手动修改,则可能不准确。

console.log(([]).constructor===Array);  // true  
console.log(({}).constructor===Object); // true
  1. ES6 中的 Symbol.toStringTag

某些内置对象(如 Array、Date、RegExp 等)的 @@toStringTag 属性值是一个字符串,该字符串用于定制 Object.prototype.toString.call(obj) 的默认行为。但通常你不需要直接使用这个属性,除非你在实现自定义对象并希望改变 Object.prototype.toString.call(obj) 的默认行为。

、typeof和 instanceof区别(必会)

javascript 中,判断一个变量的类型可以用 typeof

  • 1、数字类型、typeof 返回的值是 number。比如说:typeof(1),返回值是 number
  • 2、字符串类型,typeof 返回的值是 string。比如 typeof(“123”返回值是 string
  • 3、布尔类型,typeof 返回的值是 boolean。比如 typeof(true)返回值是 boolean
  • 4、对象、数组、null 返回的值是 object。比如 typeof(window)typeof(document)typeof(null)返回的值都是 object
  • 5、函数类型,返回的值是 function。比如:typeof(eval)typeof(Date)返回的值都是 function
  • 6、不存在的变量、函数或者 undefined,将返回 undefined。比如:typeof(abc)typeof(undefined)都返回 undefined

javascript 中,instanceof 用于判断某个对象是否被另一个函数构造使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回”object”。ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题。

Instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型

2、js使用 typeof能得到的哪些类型?(必会)

typeof 只能区分值类型

typeof undefined // undefined
typeof null // object
typeof console.log // function
typeof NaN // number

3、解释一下什么是回调函数,并提供一个简单的例子?(必会)

软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用回调异步调用

同步调用 是一种阻塞式调用,调用方要等待对方执行完毕才 返回,它是一种单向调用;

回调 是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;

异步调用 是一种类似消息或事件的机制,不过它的 调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回 调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础,因此,下面我们着重讨论回调机制在不同软件架构中的实现

回调函数 就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应

案例:

#include<stdio.h>

//callbackTest.c
//1.定义函数 onHeight(回调函数)
//@onHeight 函数名
//@height 参数
//@contex 上下文
void onHeight(double height, void *contex)
{
    printf("current height is %lf", height);
}

//2.定义 onHeight 函数的原型
//@CallbackFun 指向函数的指针类型
//@height 回调参数,当有多个参数时,可以定义一个结构体
//@contex 回调上下文,在 C 中一般传入 nullptr,在 C++中可传入对象指针
typedef void (*CallbackFun)(double height, void *contex);

//定义全局指针变量
CallbackFun m_pCallback;

//定义注册回调函数
void registHeightCallback(CallbackFun callback, void *contex)
{
    m_pCallback=callback;
}

//定义调用函数
void printHeightFun(double height)
{
    m_pCallback(height, NULL);
}

//main 函数
int main()
{
    //注册回调函数 onHeight
    registHeightCallback(onHeight, NULL);

    //打印 height
    double h=99;
    printHeightFun(99);
}

4、什么是闭包?(必会)

“闭包就是能够读取其他函数内部变量的函数。例如在 javascript 中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。”

举例:创建闭包最常见方式,就是在一个函数内部创建另一个函数。下面例子中的 closure 就是一个闭包


function func(){ 
    var a=1 ,b=2;

    funciton closure(){ 
        return a + b; 
    } 
    return closure;
}

5、什么是内存泄漏(必会)

内存泄漏指任何对象在您不再拥有或需要它之后仍然存在

6、哪些操作会造成内存泄漏?(必会)

  • 1、垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收
  • 2、setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏
  • 3、闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

7、JS内存泄漏的解决方式(必会)

7.1 global variables:对未声明的变量的引用在全局对象内创建一个新变量。在浏览器中,全局对象就是 window。

function foo(arg) {
    bar='some text'; // 等同于 window.bar='some text';
}
  • 解决
  • 创建意外的全局变量
function foo() {
    this.var1='potential accident'
}
  • 可以在 JavaScript 文件开头添加 “use strict”,使用严格模式。这样在严格模式下解析 JavaScript 可以防止意外的全局变量
  • 在使用完之后,对其赋值为 null 或者重新分配

7.2 被忘记的 Timers或者 callbacks

JavaScript 中使用 setInterval 非常常见

大多数库都会提供观察者或者其它工具来处理回调函数,在他们自己的实例变为不可达时,会让回调函数也变为不可达的。对于 setInterval,下面这样的代码是非常常见的:

var serverData=loadData();

setInterval(function() {
    var renderer=document.getElementById('renderer');
    if(renderer) {
        renderer.innerHTML=JSON.stringify(serverData);
    }
}, 5000); //This will be executed every ~5 seconds.

这个例子阐述着timers 可能发生的情况:计时器会引用不再需要的节点或数据

7.3 闭包:一个可以访问外部(封闭)函数变量的内部函数

JavaScript 开发的一个关键方面就是闭包:一个可以访问外部(封闭)函数变量的内部函数。由于 JavaScript 运行时的实现细节,可以通过以下方式泄漏内存:

var theThing=null;

var replaceThing=function () {

    var originalThing=theThing;

    var unused=function () {
        if (originalThing) // a reference to 'originalThing'
        console.log("hi");
    };

    theThing={
        longStr: new Array(1000000).join('*'),
        someMethod: function () {
            console.log("message");
        }
    };
};

setInterval(replaceThing, 1000);

7.4 DOM引用

有时候,在数据结构中存储 DOM 结构是有用的。假设要快速更新表中的几行内容。将每行DOM 的引用存储在字典或数组中可能是有意义的。当这种情况发生时,就会保留同一 DOM 元素的两份引用:一个在 DOM 树种,另一个在字典中。如果将来某个时候你决定要删除这些行,则需要让两个引用都不可达。

var elements={
    button: document.getElementById('button'),
    image: document.getElementById('image')
};

function doStuff() {
    elements.image.src='http://example.com/image_name.png';
}

function removeImage() {
    // The image is a direct child of the body element.
    document.body.removeChild(document.getElementById('image'));
    // At this point, we still have a reference to #button in the
    //global elements object. In other words, the button element is
    //still in memory and cannot be collected by the GC.
}

8、说说你对原型(prototype)理解(必会)

JavaScript 是一种通过原型实现继承的语言与别的高级语言是有区别的,像 javaC#是通过类型决定继承关系的,JavaScript 是的动态的弱类型语言,总之可以认为 JavaScript 中所有都是对象,在 JavaScript 中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript 的对象中都包含了一个” prototype”内部属性,这个属性所对应的就是该对象的原型

prototype”作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,FirefoxChrome 内核的 JavaScript 引擎中提供了”proto“这个非标准的访问器(ECMA 新标准中引入了标准对象原型访问器”Object.getPrototype(object)”)

原型的主要作用就是为了实现继承与扩展对象

9、介绍下原型链(解决的是继承问题吗)(必会)

JavaScript 原型: 每个对象都会在其内部初始化一个属性,就是 prototype(原型)

原型链:当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去 prototype 里找这个属性,这个 prototype 又会有自己的 prototype,于是就这样一直找 下去,也就是我们平时所说的原型链的概念

特点JavaScript 对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变

10、简单说说 js中的继承(必会)

继承有以下六种方法:

  • 1、原型链继承 JavaScript 实现继承的基本思想:通过原型将一个引用类型继承另一个引用 类型的属性和方法
  • 2、借用构造函数继承(伪造对象或经典继承) JavaScript 实现继承的基本思想:在子类构造函数内部调用超类型构造函数。 通过使用 apply()call() 方法可以在新创建的子类对- 象上执行构造函数
  • 3、组合继承(原型+借用构造)(伪经典继承) JavaScript 实现继承的基本思想:将原型链和借用构造函数的技术组合在一块,从而发挥两者之长的一种继承模式将原型链和借用构造函- 数的技术组合到一起,从而取长补短发挥两者长处的一种继承模式
  • 4、型式继承 JavaScript 实现继承的基本思想:借助原型可以基于已有的对象创建新对象,同时还不必须因此创建自定义的类型
  • 5、寄生式继承 JavaScript 实现继承的基本思想:创建一个仅用于封装继承过程的函数,该 函数在内部以某种方式来增强对象,最后再像真正是它做了所有工作一样返回对象。寄生- 式继承是原型式继承的加强版
  • 6、寄生组合式继承 JavaScript 实现继承的基本思想:通过借用函数来继承属性,通过原型 链的混成形式来继承方法