이 글에서는 주로 js 데이터 유형에 대한 심층적인 이해를 공유합니다.
ECMAScript 사양에는 총 7개의 데이터 유형이 정의되어 있으며 아래와 같이 기본 유형과 참조 유형의 두 가지 범주로 나뉩니다.
기본 유형: 문자열, 숫자, 불리언, 기호, 정의되지 않음, Null
참조 유형: Object
기본 유형은 고정된 공간을 차지하므로 단순 유형이라고도 합니다. 이는 간단한 데이터 세그먼트입니다. 가변 쿼리 속도를 촉진하기 위해 스택에 저장합니다. 즉, 값으로 액세스합니다.
참조 유형은 값의 크기가 변경되므로 스택에 저장할 수 없습니다. 그렇지 않으면 변수 쿼리 속도가 느려집니다. 힙, 그리고 변수에 저장된 값은 객체가 저장된 메모리, 즉 주소로 접근하는 메모리를 가리키는 포인터입니다. 참조 유형에는 객체 외에도 Function, Array, RegExp, Date 등이 포함됩니다.
ECMAScript의 형식이 느슨하다는 점을 고려하면 특정 변수의 데이터 형식을 감지할 수 있는 방법이 필요합니다. JavaScript도 이 문제에 대해 다양한 방법을 제공하지만, 불행하게도 다양한 방법으로 얻은 결과는 고르지 않습니다.
다음은 일반적으로 사용되는 4가지 방법을 소개하고 각 방법의 문제점을 간략하게 분석합니다.
typeof는 오른쪽 뒤에 단항 표현식이 오고 이 표현식의 데이터 유형을 반환하는 연산자입니다. 반환된 결과는 숫자, 부울, 기호, 문자열, 개체, 정의되지 않음, 함수 등 7가지 유형을 포함하여 이 유형의 문자열(모두 소문자) 형식으로 표현됩니다.
typeof '';// string 有效 typeof 1;// number 有效 typeof Symbol();// symbol 有效 typeof true;//boolean 有效 typeof undefined;//undefined 有效 typeof null;//object 无效 typeof [] ;//object 无效 typeof new Function();// function 有效 typeof new Date();//object 无效 typeof new RegExp();//object 无效
때때로 typeof 연산자는 혼란스럽기는 하지만 기술적으로는 올바른 값을 반환합니다.
기본 유형의 경우 null을 제외하고 올바른 결과를 반환할 수 있습니다.
참조 유형의 경우 함수를 제외하고 항상 객체 유형을 반환합니다.
null의 경우 객체 유형을 반환합니다.
함수는 함수 유형을 반환합니다.
그 중 null에는 고유한 데이터 유형인 Null이 있으며 참조 유형의 배열, 날짜 및 정규식에도 고유한 특정 유형이 있으며 typeof는 이러한 유형을 처리할 때 프로토타입 체인의 최상위만 반환합니다. , 잘못된 것은 없지만 우리가 원하는 결과는 아닙니다.
instanceof는 A가 B의 인스턴스인지 확인하는 데 사용됩니다. 표현식은 B의 인스턴스입니다. A가 B의 인스턴스이면 true를 반환하고, 그렇지 않으면 false를 반환합니다. 여기서 특별히 주의해야 할 점은 다음과 같습니다. instanceof가 프로토타입을 감지합니다. , 내부 실행 프로세스를 시뮬레이션하기 위해 의사 코드 조각을 사용합니다.
instanceof (A,B) = { var L = A.__proto__; var R = B.prototype; if(L === R) { //A的内部属性__proto__指向B的原型对象 return true; } return false; }
위 프로세스에서 볼 수 있듯이 A의 __proto__가 다음을 가리킬 때 B 프로토타입이 사용되면 A는 B의 인스턴스로 간주됩니다. 몇 가지 예를 더 살펴보겠습니다.
[] instanceof Array;//true {} instanceof Object;//true new Date() instanceof Date;//true function Person(){}; new Person() instanceof Person; [] instanceof Object;//true new Date() instanceof Object;//true new Person instanceof Object;//true
instanceof는 [ ]가 Array의 인스턴스라고 판단할 수 있지만 다음과 같이 생각한다는 것을 발견했습니다. [ ]도 Object의 인스턴스입니다. 이유는 무엇입니까?
[ ], 배열, 객체 간의 관계를 분석해 보겠습니다.
从 instanceof 能够判断出 [ ].__proto__ 指向 Array.prototype,而 Array.prototype.__proto__ 又指向了Object.prototype,最终 Object.prototype.__proto__ 指向了null,标志着原型链的结束。因此,[]、Array、Object 就在内部形成了一条原型链:
从原型链可以看出,[] 的 __proto__ 直接指向Array.prototype,间接指向 Object.prototype,所以按照 instanceof 的判断规则,[] 就是Object的实例。依次类推,类似的 new Date()、new Person() 也会形成一条对应的原型链 。因此,instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。
instanceof 操作符的问题在于,它假定只有一个全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。
var iframe = document.createElement('iframe'); document.body.appendChild(iframe); xArray = window.frames[0].Array; var arr =new xArray(1,2,3);// [1,2,3] arr instanceof Array;// false
针对数组的这个问题,ES5 提供了 Array.isArray() 方法 。该方法用以确认某个对象本身是否为 Array 类型,而不区分该对象在哪个环境中创建。
if (Array.isArray(value)){ //对数组执行某些操作 }
Array.isArray() 本质上检测的是对象的 [[Class]] 值,[[Class]] 是对象的一个内部属性,里面包含了对象的类型信息,其格式为 [object Xxx] ,Xxx 就是对应的具体类型 。对于数组而言,[[Class]] 的值就是 [object Array] 。
当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。如下所示:
当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F
可以看出,F 利用原型对象上的 constructor 引用了自身,当 F 作为构造函数来创建对象时,原型上的 constructor 就被遗传到了新创建的对象上, 从原型链角度讲,构造函数 F 就是新对象的类型。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型。
同样,JavaScript 中的内置对象在内部构建时也是这样做的:
细节问题:
null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object
为什么变成了 Object?
因为 prototype 被重新赋值的是一个 { }, { } 是 new Object() 的字面量,因此 new Object() 会将 Object 原型上的 constructor 传递给 { },也就是 Object 本身。
因此,为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。
toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。
对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
Object.prototype.toString.call('') ; // [object String] Object.prototype.toString.call(1) ; // [object Number] Object.prototype.toString.call(true) ;// [object Boolean] Object.prototype.toString.call(Symbol());//[object Symbol] Object.prototype.toString.call(undefined) ;// [object Undefined] Object.prototype.toString.call(null) ;// [object Null] Object.prototype.toString.call(new Function()) ;// [object Function] Object.prototype.toString.call(new Date()) ;// [object Date] Object.prototype.toString.call([]) ;// [object Array] Object.prototype.toString.call(new RegExp()) ;// [object RegExp] Object.prototype.toString.call(new Error()) ;// [object Error] Object.prototype.toString.call(document) ;// [object HTMLDocument] Object.prototype.toString.call(window) ;//[object global] window是全局对象 global 的引用
相关推荐:
위 내용은 js 데이터 유형에 대한 깊은 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!