머리말
Array.isArray가 오늘날 JavaScript에서 객체가 Array 유형에 속하는지 여부를 판단하는 첫 번째 선택이라는 것은 의심 할 여지가 없지만이 기사의 나머지 메서드와 그 뒤에있는 원칙과 제한 사항을 이해해야한다고 생각합니다. 대부분은 자바 스크립트에 있기 때문에 레퍼런스 타입은 Array 타입과 같은 isArray 판단 방법을 제공하지 않으며, 이때 나머지 방법을 사용하여 추론을 도출 할 필요가 있습니다.
오리 모델
동물이 오리처럼 걷고 오리처럼 부를 때 그것은 오리입니다.
객체가 Array 유형의 속성 (예 : 'splice', 'join'또는 'length')을 포함하는 경우 해당 객체는 Array 유형에 속합니다.
prototypejs의 1.6.0.3 버전 은이 로직을 사용하며 코드는 다음과 같습니다.
isArray: function(object) {
return object != null && typeof object == "object" && 'splice' in object && 'join' in object;
}
하지만 덕 모드에는 문제가 있는데, 동물이 오리처럼 걷다가 오리처럼 소리를 지르면 오리가 될뿐만 아니라 '도날드 덕'이 될 수도 있습니다.
이것은 Array 유형의 두 가지 속성 인 " splice" 및 " join" 을 포함하는 객체 와 같습니다 . Array 유형 외에도 Person 유형이 될 수도 있습니다.
function isArray(object) {
return object != null && typeof object == "object" && 'splice' in object && 'join' in object;
}
function Person(){
/**
code
*/
}
Person.prototype.splice = function(){
/**
code
*/
}
Person.prototype.join = function(){
/**
code
*/
}
let p = new Person();
let isArr = isArray(p);
console.log('isArray : ' + isArr);//isArray : true
duck 모드는 jquery 의 isArrayLike 메소드 와 같이 ' like Array ' 를 판단 하는 데 더 많이 사용 되며 코드는 다음과 같습니다.
function isArrayLike( obj ) {
var length = !!obj && obj.length,
type = toType( obj );
if ( typeof obj === "function" || isWindow( obj ) ) {
return false;
}
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}
obj 두 가지 판단 논리 의 길이 === 0 및 길이 유형 === "number"&& length> 0 && (length-1) 은 객체가 'length'속성을 통해 ' like Array '에 부합하는지 여부를 판단하는 것 입니다.
instanceof 키워드
instanceof 키워드의 내용은 " 사용 시나리오에 대한 심층 이해와 typeof 및 instanceof의 예방 조치에 대한 자세한 설명이므로 여기에서는 간단한 설명 만 제공합니다. instanceof 키워드는 Array 함수의 프로토 타입 속성 값이 객체의 프로토 타입 체인에 있는지 여부를 확인하는 데 사용됩니다. 존재하는 경우 객체가 Array 유형이고 그렇지 않은 경우 그렇지 않음을 의미합니다.
그러나 instanceof는 완전히 신뢰할 수 없습니다. 예를 들어 instanceof의 판단 결과는 Symbol.hasInstance 속성의 영향을받을 수 있습니다.
function Person(){
}
Object.defineProperty(Person,Symbol.hasInstance,{
value : function(){
return false;
}
})
let p = new Person();
p instanceof Person;//false
데이터 및 유형이 전역 변수에 속하지 않는 경우 instanceof의 판단 결과에도 영향을 미칠 수 있습니다. 예를 들어, 이제 두 개의 html 파일 인 main.html 및 iframe.html을 정의하면 코드는 다음과 같습니다.
main.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>main</title>
</head>
<body>
<iframe src="./iframe.html"></iframe>
<script type="text/javascript">
window.onload = function(){
console.log('document.domain : ' + document.domain);
let mainArr = [1,2,3,4,5];
console.log('mainArr instanceof Array : ' + (mainArr instanceof Array));//
let iframe = document.documentElement.getElementsByTagName('iframe')[0];
let iframeWin = iframe.contentWindow.window;
let iframeArr = iframeWin.arr;
console.log('iframeArr : ' + JSON.stringify(iframeArr));
console.log('iframeArr instanceof Array : ' + (iframeArr instanceof Array));//
console.log('iframeArr instanceof iframeWin.Array : ' + (iframeArr instanceof iframeWin.Array));//
}
</script>
</body>
</html>
iframe.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>iframe</title>
</head>
<body>
<p>iframe</p>
<script type="text/javascript">
window.onload = function(){
window.arr = [6,7,8,9,10];
}
</script>
</body>
</html>
npx http-server가 main.html을 연 후 결과를 얻습니다.
다른 전역 변수에서 동일한 이름을 가진 생성자는 동일한 함수가 아니라는 것을 알 수 있습니다. 데이터와 유형이 동일한 전역 변수 아래에 있지 않은지 판단하기 위해 instanceof를 사용하는 것은 불가능합니다.
Object.prototype.toString 메서드
Object.prototype.toString은 교차 전역 변수의 영향을받지 않습니다.
main.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>main</title>
</head>
<body>
<iframe src="./iframe.html"></iframe>
<script type="text/javascript">
window.onload = function(){
let toString = Object.prototype.toString;
console.log('document.domain : ' + document.domain);
let mainArr = [1,2,3,4,5];
console.log('toString.call(mainArr) : ' + (toString.call(mainArr)));//
let iframe = document.documentElement.getElementsByTagName('iframe')[0];
let iframeWin = iframe.contentWindow.window;
let iframeArr = iframeWin.arr;
console.log('toString.call(iframeArr) : ' + (toString.call(iframeArr)));//
}
</script>
</body>
</html>
iframe.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>iframe</title>
</head>
<body>
<p>iframe</p>
<script type="text/javascript">
window.onload = function(){
window.arr = [6,7,8,9,10];
}
</script>
</body>
</html>
npx http-server가 main.html을 연 후 결과를 얻습니다.
그러나 Symbol.toStringTag를 사용하면 Object.prototype.toString의 출력에 영향을줍니다.
let toString = Object.prototype.toString;
function Person(){
}
let p = new Person();
console.log('toString.call(p) : ' + toString.call(p));//toString.call(p) : [object Object]
Object.defineProperty(p,Symbol.toStringTag,{
get(){
return "Person";
}
})
console.log('toString.call(p) : ' + toString.call(p));//toString.call(p) : [object Person]
당신은 또한 수:
let toString = Object.prototype.toString;
function Person(){
}
let p = new Person();
console.log('toString.call(p) : ' + toString.call(p));//toString.call(p) : [object Object]
Object.defineProperty(Person.prototype,Symbol.toStringTag,{
get(){
return "Person";
}
})
console.log('toString.call(p) : ' + toString.call(p));//toString.call(p) : [object Person]
다음과 같이 작성할 수도 있습니다.
let toString = Object.prototype.toString;
class Person{
get [Symbol.toStringTag](){
return 'Person';
}
}
let p = new Person();
console.log('toString.call(p) : ' + toString.call(p));//toString.call(p) : [object Person]
Array.isArray 메서드
쓰기 가능한 속성 값이 true이므로 Array.isArray를 수정할 수 있습니다.
Object.getOwnPropertyDescriptor(Array,'isArray');
//{writable: true, enumerable: false, configurable: true, value: ƒ}
Array.isArray = function(data){
return null !== data && typeof data === 'object';
}
console.log(Array.isArray(window));//true
Array.isArray는 교차 전역 변수의 영향을받지 않으며 Symbol.toStringTag를 수정해도 Array.isArray의 판단에 영향을주지 않습니다.
let toString = Object.prototype.toString;
Object.defineProperty(Array.prototype,Symbol.toStringTag,{
get(){
return "Person";
}
})
let arr = new Array();
console.log(Array.isArray(arr));//true
console.log('toString.call(arr) : ' + toString.call(arr));//toString.call(arr) : [object Person]
특정 Array.isArray 판단 논리 는 array-isarray.tq 파일 에서 v8 을 찾았습니다 .
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
namespace runtime {
extern runtime ArrayIsArray(implicit context: Context)(JSAny): JSAny;
} // namespace runtime
namespace array {
// ES #sec-array.isarray
javascript builtin ArrayIsArray(js-implicit context:
NativeContext)(arg: JSAny): JSAny {
// 1. Return ? IsArray(arg).
typeswitch (arg) {
case (JSArray): {
return True;
}
case (JSProxy): {
// TODO(verwaest): Handle proxies in-place
return runtime::ArrayIsArray(arg);
}
case (JSAny): {
return False;
}
}
}
} // namespace array
종료
이 재능에 대한 지식이 부족하여 문제가 발견되면 저에게 지적하고 싶습니다. 감사합니다.