1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

近年のJSで分からないこと

Last updated at Posted at 2023-01-29

個人用メモをそのまま公開します。

前提

jQuery時代のJavaScriptは分かるけど、それ以降の知識が曖昧なため、
VueとかNuxtとか書こうとすると、すぐにつまずく。

export default...は何?

JSでモジュール分割するための記法というのは分かる。

const { data } = ...は何?

複数の変数に代入するための記法と思うけど、1個のときもこの書き方を見る。

中括弧を使うのは、どういう意味?
オブジェクトを書くときの中括弧と同じか、文法的にはまったく別の意味か。

コード例

いま見てるチュートリアルのコードを例に疑問をまとめる。
JS、TS、Vueの疑問が混在してるけど構わない。
https://www.newt.so/docs/tutorials/get-contents-in-nuxt

<script lang="ts" setup>
// {}を削除しても動いたけど警告が出る: Default export is not declared in imported module
// Q1 {}は複数のときだけ必須というわけじゃなく、importの解釈に影響する?
// A1 {}の有無はデフォルトインポートかどうか。importの挙動に影響する。JSの仕様。
import type { Article } from '~/types/article'

// async/awaitが入れ子で複数出てきて混乱する
// awaitだから非同期処理を待ち、dataに代入してから次の行に進む、というのは分かる
// useAsyncDataはNuxtの機能
// Q2 {}を消してconst data = にすると取得結果が表示されなくなる。JS解釈が変わってVueに影響する?
// A2 {}を付けると戻り値のなかの特定のプロパティを取得する。ここではref型のdataプロパティが欲しいので、{}が必要。
const { data } = await useAsyncData('articles', async () => {
  // Q3 識別子を渡してないのにNewt用機能が返されるのが分からない。分かりやすい変数名にしてるだけ?
  // A3 {}でNuxtAppのnewtClientプロパティを取得している。変数名に$が付くのはよく分からない。Nuxtの仕様?
  const { $newtClient } = useNuxtApp()
  // asyncのなかでawaitしてる。
  // これはuseAsyncDataのハンドラのreturnで、戻り値がdataに入るのは分かる
  return await $newtClient.getContents<Article>({
    appUid: 'blog',
    modelUid: 'article',
    query: {
      // Q4 要素を削除してもエラーにならない。型定義の不一致も、SDKがうまいこと処理してくれる?
      // A4 よく分からない。ここまでチェックできないという感じかもしれない。
      select: ['_id', 'title', 'slug', 'body']
    }
  })
})
// Q5 .valueがあるということは、const {data}はrefになる?
// A5 だいたい合ってる。refになるというより、ref型であるdataプロパティを取得している。
const articles = data.value?.items
</script>

Q1 import

import typeはTypeScriptの仕様。型のみをインポートするためのTS記法。
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html

import type Foo, { Bar, Baz } from "some-module";
//     ~~~~~~~~~~~~~~~~~~~~~~
// error! A type-only import can specify a default import or named bindings, but not both.

{}なしはデフォルトインポート、{}つきは名前付きバインドと解釈されるみたい。

{}の解釈は、JSのimportの仕様がある

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import
{}つきは、エクスポートされたものから特定のオブジェクト等をインポートする。
{}なしは、デフォルトとしてエクスポートされたものをインポートする。

exportの仕様を見る

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export
一番最初に説明がある。

  1. 名前付きエクスポート (モジュールごとに 0 以上のエクスポート)
  2. デフォルトエクスポート (モジュールごとに 1 つのエクスポート)

それぞれの意味は簡単に理解できるけど、使い分けがよく分からない。
慣例とか書きやすさで適当にやればいい気がする。

値をひとつエクスポートしたい、あるいはモジュールでフォールバック先の値を持ちたい場合は、デフォルトエクスポートを使用するとよいでしょう。

Q2 const { data } = ...

分割代入というJS仕様。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20

const {data}は、戻り値のなかで、dataという名前の値を取得する記述。
{}なしにすると、戻り値そのものを受け取ることになるので、結果が変わって当然。

useAsyncData

https://nuxt.com/docs/api/composables/use-async-data/
useAsyncDataの戻り値はAsyncData型で、data以外もいくつかのプロパティがある。
dataはdata: Ref<DataT | null>と定義されてて、予想通りrefだった。

Q3 useNuxtApp

Nuxtの仕様
https://nuxt.com/docs/api/composables/use-nuxt-app

プラグインを定義して呼び出す方法
https://nuxt.com/docs/guide/directory-structure/plugins#automatically-providing-helpers

呼び出す時に$をつける理由が分からない。

Q4 型定義の不一致

NewtのAPIドキュメント
https://developers.newt.so/apis/cdn#tag/contents_methods/operation/getContents
JS用のSDK
https://github.com/Newt-Inc/newt-client-js

TypeScriptの型

TypeScriptで定義されたインターフェースは、コンパイルチェックに活用された後、JavaScriptコードを生成する過程で消されるため、インターフェースがJavaScript実行時に影響することはありません。

export interface Articleのなかを削除変更しても、エラーにならない。問題なく動く。
SDKの内部の作りによって、コンパイルチェックが及ばないのかもしれない。

感想

JSの分割代入が分かれば、ほとんどの疑問が解消した。

分割代入は、イメージ的にはこんなコードと同じ感じ。

// 分割代入
const { data } = get()

// 普通に書くと、こんな感じ
const data  = get().data
// 指定のデータだけ取得するという意味では、こんな感じもする
const data  = get('data')

左辺に識別子を書くという記法が、たぶん初めて経験することで、説明を見るまで全然分からなかった。

https://ja.javascript.info/destructuring-assignment#ref-1858
「入れ子構造の非構造化」以下の書き方が非常に強力。
ただ短いだけの記法じゃなく、広範囲に便利に使えそう。

翌日の感想

分割代入に感じた違和感

const { data } = get()

このコードの場合、getメソッドの中に書かれてる識別子を、左辺で使ってることに違和感があった。呼び出し元から、呼び出し先を覗き込んでいるような感じで、それまでのプログラミング観と相容れなかった。

でも、よく考えると、全然そういう話ではない。
getメソッドから受け取った戻り値を、呼び出し元で処理してるだけなので、getメソッドの中を覗き込んでいるわけではない。

// こう書けば、戻り値を処理してるだけなのは明白
const ret = get()
const { data } = ret

慣れないNuxtを前にして、必要以上に「分からない」と思い込んでたかもしれない。
そのせいで、一目で分からない記述に不思議な解釈をしようとしてた。

phpでも分割代入できるみたい

古いlistのイメージしかなかった。
この記事を見ると、JSの分割代入と同じようなことができるみたい。JS独自の仕様ではなかった。
https://qiita.com/okumurakengo/items/9c781a17c15ea2916566

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?