ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript のデータ型と変数の分析 (例付き)

JavaScript のデータ型と変数の分析 (例付き)

不言
不言転載
2018-11-15 17:07:012067ブラウズ

この記事の内容は JavaScript のデータ型と変数の分析に関するものです (例付き)。必要な方は参考にしていただければ幸いです。

この記事では、JS の データ型と変数について説明します。これは JS を学習する際の最も基本的な質問ですが、重要な質問です。私の共有があなたのお役に立てば幸いです。

記事の冒頭で、最初にインタビューで遭遇したいくつかの質問について触れます:

例:

値によるパラメーターの受け渡しを理解するにはどうすればよいですか?

一時的なデッドゾーンとは何ですか?

変数プロモーションとは何ですか?

グローバル変数とウィンドウ プロパティの違いは何ですか?なぜ?

... ...

この記事は、私が経験した面接での質問を挟みながら、ナレッジポイントを分析するスタイルです。

基本データ型

JS には、数値、文字列、ブール値、null、未定義、シンボルの 6 つの基本データ型があります。

基本的なデータ型について理解する必要があるのは、メモリ内の基本型の格納方法はスタックであるということです。各値は個別に保存され、相互に影響を与えません。

基本型には値によってアクセスします。比較する場合は、値で比較します。

1 === 1 // true

参照データ型

参照型の値はヒープに格納され、参照はスタックに格納されます。

参照型には参照によってアクセスします。比較する場合、参照も比較されます。

{} === {} // => false

パラメータの受け渡し方法

JS では、パラメータは関数を含め、任意のタイプの値にすることができます。

ここで分析する必要があるのは、どのタイプのパラメータが渡されるのかということです。参照型かプリミティブ型か?

最初に基本的な例を見てみましょう:

var out_num = 1;

function addOne(in_num) {
    in_num += 1;
    return in_num;
}

addOne(out_num); // => 2
out_num // => 1

この例では、実際のパラメータ out_num を addOne() 関数に渡します。このとき、out_num は in_num に渡されます。つまり、内部 in_num = out_num プロセスが存在します。最終的な結果は、out_num が関数によって変更されていないことです。これは、in_num と out_num が独立してメモリに格納されている 2 つの値、つまり値渡しであることを示しています。

別の変換を見てみましょう:

var out_obj = { value: 1 };

function addOne(in_obj) {
    in_obj.value += 1;
    return in_obj;
}

addOne(out_obj); // => { value: 2 }
out_obj // => { value: 2 }

質問が来ていますか?関数のパラメータは値渡しではないのでしょうか?なぜ関数内の処理が外部に反映されるのでしょうか? これは超超超誤解です。

まず第一に、関数パラメーターは値によって渡されるという観点を修正する必要があります。 これをどう理解しますか?参照型については、参照型が参照と実際のメモリ空間に分割されると前述しました。ここでも、out_obj は in_obj に渡されます。つまり、in_obj = out_objout_obj と in_obj は 2 つの参照であり、それぞれ独立してメモリに格納されますが、同じメモリを指します。

そして in_obj.value = 1 が直接操作の実際のオブジェクトです。実際のオブジェクトに対する変更は、実際のオブジェクトを参照するすべての参照に同期されます。

JavaScript のデータ型と変数の分析 (例付き)

JavaScript のデータ型と変数の分析 (例付き)

#この例をもう一度見ると、より明確になるかもしれません。

var out_obj = { value: 1 };

function addOne(in_obj) {
    in_obj = { value: 2 };
    return in_obj;
}

addOne(out_obj); // => { value: 2 }
out_obj // => { value: 1 }
理解する必要があるのは 1 点だけです。オブジェクトを割り当てると、参照が指す実際のオブジェクトが変更されます。

データ型を決定する方法

データ型を決定するには、通常、次の 3 つの具体的な方法があります。

1. 演算子の型

typeof 演算子は、データ型を表す文字列を返します。これには次の明らかな欠陥があります:

typeof null // => 'object'

typeof [] // => 'object'
これは、JS 言語設計の開始時に残されたバグが原因です。 typeof による null の処理の詳細については、この記事 http://2ality.com/2013/10/typ... を参照してください。

したがって、typeof は、数値、文字列、ブール値、未定義、シンボルなどの基本的な型を決定するために使用するのが最適です。

2.instanceof 演算子

typeof は

type タグ を判断することでデータ型を判断し、instanceof はコンストラクターを判断します。プロトタイプは、オブジェクトのプロトタイプ チェーン上の任意の場所に表示されます。

例:

{} instanceof Object // => true

[] instanceof Array // => true
[] instanceof Object // => true
カスタム タイプも決定します:

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
var auto = new Car('Honda', 'Accord', 1998);

console.log(auto instanceof Car);
// => true

console.log(auto instanceof Object);
// => true
したがって、リテラル形式の基本データ型の場合、instanceof では決定できません:

1 instanceof Number // => false

Number(1) instanceof Number // => false

new Number(1) instanceof Number // => true

3. Object.prototype.toString()

これは、JSON を含むあらゆるデータ型をより正確かつ正確に判断できる、現在最も推奨されるメソッドです。 、日付、エラーなど。 Lodash では、データ型を決定する核心も Object.prototype.toString() メソッドです。

Object.prototype.toString.call(JSON) // => "[object JSON]"
この背後にある原理については、この記事をご覧ください。http://www.cnblogs.com/ziyunf...

4 その他 上記 3 つ。これはデータ型を決定する一般的な方法です。

配列の判断方法、NaNの判断方法、配列状のオブジェクトの判断方法、空オブジェクトの判断方法

などの質問も面接中に出てきます。この種の問題は比較的オープンであり、解決策は通常、判定データの中核となる特性を把握することで解決されます。

例: 配列のようなオブジェクトを判断します。

你先要知道 JS 中类数组对象是什么样子的,并寻求一个实际的参照物,比如 arguments 就是类数组对象。那么类数组对象具有的特点是:真值 & 对象 & 具有 length 属性 & length 为整数 & length 的范围大于等于 0,小于等于最大安全正整数(Number.MAX_SAFE_INTEGER)。

在你分析特点的时候,答案就呼之欲出了。【注意全面性】

数据类型如何转换

JS 数据类型的动态性将贯穿整个 JS 的学习,这是 JS 非常重要的特性,很多现象就是因为动态性的存在而成为 JS 独有。

正是由于动态性,JS 的数据类型可能在你毫无察觉的情况下,就发生了改变,直到运行时报错。

这里主要分析下面 8 种转换规则。

1、if 语句

if 语句中的类型转换是最常见的。

if (isTrue) {
    // ...
} else {}

在 if 语句中,会自动调用 Boolean() 转型函数对变量 isTrue 进行转换。

当 isTrue 的值是 null, undefined, 0, NaN, '' 时,都会转为 false。其余值除 false 本身外都会转为 true。

2、Number() 转型函数

我们重点关注 null undefined 以及字符串在 Number() 下的转换:

Number(null) // => 0
Number(undefined) // => NaN
Number('') // => 0
Number('123') // => 123
Number('123abc') // => NaN

注意和 parseInt() 对比。

3、parseInt()

parseInt(null) // => NaN
parseInt(undefined) // => NaN
parseInt('') // => NaN
parseInt('123') // => 123
parseInt('123abc') // => 123

4、==

这里需要注意的是:

null == undefined // => true

null == 0 // => false
undefined == false // => false

null 与 undefined 的相等性是由 ECMA-262 规定的,并且 null 与 undefined 在比较相等性时不能转换为其他任何值。

5、关系操作符

对于两个字符串的比较,是比较的字符编码值:

'B'  true

一个数值,另一个其他类型,都将转为数字进行比较。

两个布尔值转为数值进行比较。

对象,先调用 valueOf(),若不存在该方法,则调用 toString()。

6、加法

加法中特别注意的是,数字和字符串相加,将数字转为字符串。

'1' + 2 => // '12'
1 + 2 => // 3

对于对象和布尔值,调用它们的 toString() 方法得到对应的字符串值,然后进行字符串相加。对于 undefined 和 null 调用 String() 取得字符串 'undeifned' 和 'null'。

{ value: 1 } + true // => "[object Object]true"

7、减法

对于字符串、布尔值、null 或者 undefined,自动调用 Number(),转换结果若为 NaN,那么最终结果为 NaN。

对于对象,先调用 valueOf(),如果得到 NaN,结果为 NaN。如果没有 valueOf(),则调用 toString()。

8、乘法、除法

对于非数值,都会调用 Number() 转型函数。

变量提升与暂时性死区

JS 中有三种声明变量的方式:var, let, const。

var 声明变量最大的一个特点是存在变量提升。

console.log(a); // undefined
var a = 1;
console.log(a); // 1

第一个打印结果表示,在声明变量 a 之前,a 就已经可以访问了,只不过并未赋值。这就是变量提升现象。(具体原因,我放在后面分析作用域的时候来写)

let 和 const 就不存在这个问题,但是又引入了暂时性死区这样的概念。

/**
* 这上面都属于变量 a 的暂时性死区
* console.log(a) // => Reference Error
*/
let a = 1;
console.log(a); // => 1

即声明 a 之前,不能够访问 a,而直接报错。

而暂时性死区的出现又引出另外一个问题,即 typeof 不再安全。你可以参考这篇文章 http://es-discourse.com/t/why...

补充:一个经典面试题

for (var i = 0; i <p>我先不再这里展开分析,我打算放到异步与事件循环机制中去分析。不过这里将 var 替换成 let 可以作为一种解决方案。如果你有兴趣,也可以先去分析。</p><p>对于 const,这里再补充一点,用于加深对基本类型和引用类型的理解。</p><pre class="brush:php;toolbar:false">const a = 1;
const b = { value: 1 };

a = 2; // => Error
b.value = 2; // => 2
b = { value: 2 }; // => Error

本质上,const 并不是保证变量的值不得改动,而是变量指向的内存地址不得改动。

声明全局变量

直接通过 var 声明全局变量,这个全局变量会作为 window 对象的一个属性。

var a = 1;
window.a // => 1

在这里提出两个问题,一是 let 声明的全局变量会成为 window 的属性吗?二是 var 声明的全局变量和直接在 window 创建属性有没有区别?

先来回答第一问题。let 声明的全局变量不会成为 window 的属性。用什么来支撑这样的结论呢?在 ES6 中,对于 let 和 const 声明的变量从一开始就形成封闭作用域。想想之前的暂时性死区。

第二个问题,var 声明的全局变量和直接在 window 创建属性存在着本质的区别。先看下面的代码:

var a = 1;
window.a // => 1

window.b = 2;

delete window.a
delete window.b

window.a // => 1
window.b // => undefined

我们可以看到,直接创建在 window 上的属性可以被 delete 删除,而 var 创建的全局属性则不会。这是现象,通过现象看本质,二者本质上的区别在于:

var を使用して宣言されたグローバル変数の [[configurable]] データ属性の値は false であり、delete によって削除できません。オブジェクト上に直接作成された属性のデフォルト値 [[configurable]] は true です。つまり、属性は delete によって削除できます。 ([[configurable]] 属性については、後の記事でオブジェクトを分析するときに説明します)

概要

この記事の内容「データ型と変数」記事では、7つの主要なカテゴリが分析されました。

基本型、参照型、パラメーター転送方法、データ型の決定方法、データ型の変換方法、変数のプロモーションと一時的なデッド ゾーン、およびグローバル変数の宣言を確認しましょう。

これらは、学校の採用面接で高頻度にテストされるポイントであるだけでなく、JS を学習する上で必須の知識ポイントでもあります。

ヒント 1: 『JavaScript Advanced Programming』という本が「フロントエンドのバイブル」と呼ばれるのには理由があります。キャンパス採用の準備をしているあなたには非常に必要です! 本を100回読めば、その意味が明らかになる。 面接で出てくる JS 関連の知識ポイントのほとんどがこの本に含まれていることがわかります。

ヒント 2: 復習の準備の過程では、知識のモジュール性と相関性に注意してください。今日の「データ型と変数」モジュールなど、知識モジュールを自分で分割する能力が必要です。関連性とは、あらゆる知識が関連していることを意味します。たとえば、スコープやメモリなどのモジュールが関係します。

以上がJavaScript のデータ型と変数の分析 (例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。