はじめに
前置き
次の質問を見て、すぐに答えられるかどうか考えてみてください。
- typeof
- いつ使う=== いつ使う===?
- window.onloadDOMContentLoadedとの違い?
- JSは10個の作成し、クリックすると対応するシリアル番号がポップアップ表示されます。
- 手書きスロットルスロットル、アンチシェイクデバウンス
- プロミスが解決する問題とは?
- 果てしない問いの海をどう見るか →変えてはいけないものは変えてはいけない。
- 次のトピックへのアプローチ方法→ トピック→知識ポイント→再びトピック
フロントエンド知識体系
- 知識体系とは?
効果的な学習への3つのステップ:知識体系を見つける、トレーニングできる、タイムリーなフィードバック。知識体系:構造化された知識の範囲。構造化され、整理され、拡張しやすい。 - 櫛のどの側面から?
W3C標準:html、css、DOM操作、BOM操作、AJAX、イベントバインディング。アプリケーションの標準。
ECMA262標準:es6のようなjsやesの言語の構文、変数の定義方法、関数やプロトタイプの定義方法、クロージャ、プロミス。
開発環境
ランタイム環境 - 知識体系
JS基本構文
JS-Web-API
開発環境
実行環境
JSの基本 - 変数型と計算
ちしんてん
可変タイプ
- 値型と参照型
let obj = 0x64;
let c = obj;
obj = 0xc8;
console.log(c);
グローバル環境であれ、機能環境であれ、値型はスタック上に存在します。スタックは上から下へ並びます。
let foo = { 'bar': 0x14 };
let c = foo;
c.bar = 0x15;
console.log(foo.bar);
ヒープは下から上に向かって配置されています。a と b はどちらもオブジェクト {age: 20} を指すメモリアドレスを格納しています。
- 一般的な値の種類
let a // undefined
const s = 'abc'
const n = 100
const b = true
const s = Symbol('s')
定数定義の定数はコピーしないとエラーになることに注意してください。
- 一般的な参照型
const foo = { 'x': 0x64 };
const c = [
'a',
'b',
'c'
];
const bar = null;
function b() {
}
- typeof
- すべての値タイプを認識
- 関数の識別
- 参照型かどうかの判定
// 全ての値タイプを決定する
let a ; typefof a // 'undefined'
const s = 'abc'; typeof s // 'string'
const n = 100; typeof n // 'number'
const b = true; typeof b // 'boolean'
const s = Symbol('s') typeof s // 'symbol'
// 判定関数
typeof console.log // 'function'
typeof function () {} // 'function'
// 参照タイプを認識する
typeof null // 'object'
typeof ['a', 'b'] // 'object'
typeof { x: 100 } // 'object'
- ディープコピー ローカルにサーバーをプロキシしてコードをデバッグしたい場合は、以下の方法と手順に従います。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Deepclone</title>
</head>
<body>
<p>テキストの一部</p>
<script type="text/javascript" src="./deepclone.js"></script>
</body>
</html>
6) deepclone.jsファイル
/**
*
*/
const obj1 = {
age: 20,
name: 'erina',
address: {
city: 'Tokyo'
},
arr: ['a','b','c']
}
const obj2 = obj1
obj2.address.city = 'Tokyo'
console.log(obj1.address.city) // Tokyo
/**
*
* @param {Object} obj コピーするオブジェクト
*/
function deepClone(obj = {}) {
// obj がオブジェクト、配列、または null でない場合は、ディープコピーを行わずに直接返す。
if(typeof obj !== 'object'
obj == null)
return obj
// 結果を初期化する
let result;
if(obj instanceof Array) {
result = []
} else {
result = {}
}
for (let key in obj) {
// key プロトタイプではないプロパティ
if(obj.hasOwnProperty(key)) {
//
result[key] = deepClone(obj[key])
}
}
// 結果を返す
return result
}
const obj3 = deepClone(obj1);
obj3.address.city = 'chendu'
console.log(obj3, obj1)
結果は以下の通り。
- 変数計算 - タイプ変換
- 文字列の接続
const bar = 0x64 + 0xa;
const foo = 0x64 + '10';
const obj = !false + '10';
- 演算子
100 == '100' // true
0 == '' // true
0 == false // true
false == '' // true
null == undefined // true
// == null他のすべては ==
const obj = { x: 100 }
if(obj.a == null) {}
// if(obj.a === null
obj.a === undefined){}
// ここでは、nullかもしれないし、undefinedかもしれない。null == すべてうまくいく。
- if文と論理演算
真の変数:!a ===真となる変数。
偽変数: !aa ===偽
// 以下は偽の変数である。これら以外はすべて本当の変数である。
!!0 === flase
!!NaN === false
!!'' === false
!!null === false
!!undefined === false
!!false === false
// if
// truly
const a = true
if (a) {
// ....
}
// falsely
const c = ''
if (c) {
// ....
}
// 論理的判断
console.log(10 && 0) // 0
console.log(''
'abc') // 'abc'
console.log(!window.abc) // true
- 問題点
- typeof
- いつ使う=== いつ使う===?
- ==
const b = {
'x': 0x64,
'y': 0xc8
};
const c = b;
let a = b.x;
c.x = 0x2;
console.log(b);
- ディープコピーの手書き
値型と参照型の判定に注意;
配列かオブジェクトかの判断に注意
再帰;
JSの基礎 - プロトタイプとプロトタイプ・チェイン
知識ポイントとトピック
問題
- 変数が配列かどうかを正確に判断するには?
- プラグインと拡張性を考慮したシンプルなjQueryの手書き
- クラスのプロトタイプ性、あなたはどう理解していますか?
ちしんてん
- クラスと継承
- タイプ判定Instanceof
- プロトタイプとプロトタイプ・チェーン
class
class
- constructor
- 属性
- メソッド
class obj {
constructor(bar, c) {
this.name = bar;
this.number = c;
}
.b() {
console.log(' ' + this.name + ' ' + this.number);
}
}
const a = new obj(' ', 0x64);
console.log(a);
const foo = new obj(' ', 0x64);
console.log(foo);
継承
多くのクラスがあり、それらのクラスにいくつかのパブリック属性がある場合、後でそれらを取り出して継承に使用することができます。
- extends 継承は extends を通して行われます。
- super は親クラスのコンストラクタ、つまり親クラスの構築処理を実行します。
- メソッド
class obj {
constructor(Foo) {
this.name = Foo;
}
.b() {
console.log(this.name + '\x20eat\x20something');
}
}
class bar extends obj {
constructor(Obj, B) {
super(Obj);
this.number = B;
}
.a() {
console.log(' ' + this.name + ' ' + this.number);
}
}
class A extends obj {
constructor(fOo, bAr) {
super(fOo);
this.foo = bAr;
}
.c() {
console.log(this.name + '\x20 \x20' + this.foo);
}
}
const Bar = new bar(' ', 0x64);
console.log(Bar);
Bar.a();
Bar.b();
const C = new A(' ', ' ');
console.log(C);
C.c();
C.b();
原形
タイプ判定-instanceof
// instanceof を使って、変数がどのクラスに属するか、どのコンストラクタに属するかを判断できる。
xialuo instanceof Student // true
xialuo instanceof Pepole // true Pepoleはxialuoの親クラスである
xialuo instanceof Object // true Objectは全てのクラスの親である
[] instanceof Array // true
[] instanceof Object // true Arrayもクラスであり、ObjectはArrayの親クラスであることが理解できる。
{} instanceof Object // true
原形
typeof People;
typeof Student;
console.log(xialuo.__proto__);
console.log(Student.prototype);
console.log(xialuo.__proto__ === Student.prototype);
- すべてのクラスは、明示的なプロトタイプの原型(このクラスを配置するメソッド)を持っています。
- 各インスタンスは暗黙のプロトタイプ __proto___ を持っています。
- インスタンスの __proto__ は、対応するクラスのプロトタイプを指します。
- プロトタイプベースの実行ルール:プロパティxialuo.nameを取得したり、メソッドxialuo.sayhi()を実行する際に、自身のプロパティやメソッドを探し、見つからない場合は自動的に_proto_に移動するようになりました。
プロトタイプの連鎖とinstanceof
console.log(Student.prototype.__proto__);
console.log(People.prototype);
console.log(People.prototype === Student.prototype.__proto__);
注:図によると、nameはxiaoluo自身の属性であり、sayHiメソッドはxiaoluo自身の属性ではないことがわかります。
xialuo.name;
xialuo.hasOwnProperty('name');
xialuo.hasOwnProperty('sayHi');
xialuo.foo();
xialuo.hasOwnProperty('hasOwnProperty');
では、hasOwnPropertyはどこから来たのでしょうか?
People.prototypeの__proto____はObject.prototypeを指し、Object.prototypeにはtoStringやhasOwnPropertyなどのメソッドがあります。
instanceofの原則:変数はその暗黙のプロトタイプに従って対応するクラスを見つけることができます。例えば
xialuo instanceof Array // false
- クラスはES6の構文仕様であり、ECMA委員会によって公開されています。
- ECMAが規定しているのは構文規則、つまりコードを記述するための仕様だけであり、それがどのように実装されるかは規定していません。
- 上記の実装はすべてV8エンジンの実装であり、主流の実装です。
質問と回答
- 変数が配列かどうかを正確に判断するには?a instanceof Array
- プラグインと拡張性を考慮したシンプルなjQueryのindex.htmlファイルを手書きします。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>jquery demo </title>
</head>
<body>
<p>テキストの一部 1</p>
<p>テキストの一部 2</p>
<p>テキストの一部 3</p>
<script type="text/javascript" src="./jquery-demo.js"></script>
</body>
</html>
jquery-demo.jsファイル
class jQuery {
constructor(selector) {
const result = document.querySelectorAll(selector)
const length = result.length
for(let i = 0; i < length; i++) {
this[i] = result[i]
}
this.length = length
this.selector = selector
}
get(index) {
return this[index]
}
each(fn) {
for(let i = 0; i < this.length; i++) {
const elem = this[i];
fn(elem)
}
}
// リスニング・メソッド
on(type, fn) {
return this.each(elem => {
elem.addEventListener(type, fn ,false)
})
}
// たくさん拡張できるDOM API
}
jQueryプラグインの拡張性を考える
jQuery.prototype.obj = function (bar) {
alert(bar);
};
jQuery.prototype.b = function (a) {
alert(a);
};
class b extends jQuery {
constructor(foo) {
super(foo);
}
.c(obj) {
}
.style(a) {
}
}
- クラスのプロトタイプ性、あなたはどう理解していますか?
JSの基本 - スコープとクロージャ
スコープと自由変数
ちしんてん
- スコープと自由変数
スコープ: a はグローバルにスコープされ、a1 は fn1 関数スコープ内に、a2 は fn2 関数スコープ内に、a3 は fn3 関数スコープ内にスコープされます。
let b = 0x0;
function foo() {
let bar = 0x64;
function c() {
let obj = 0xc8;
function B() { let Obj = 0x12c; return b + bar + obj + Obj;
}
B();
}
c();
}
foo();
スコープはグローバル・スコープ、ファンクション・スコープ、ブロック・レベル・スコープに分けられます。
if (!false) {
let obj = 0x64;
}
console.log(x);
フリー変数:現在のスコープでは定義されていないが、使用されている変数。変数が見つかるまで、上位のスコープで1レベルずつ検索されます。グローバルスコープで見つからない場合、XX is not defined というエラーが報告されます。
クロージャ
1)関数が引数として渡される場合、2)関数が戻り値として返される場合。
クロージャースコーピング:自由変数は、関数が実行される場所ではなく、関数が定義される場所、より上位のスコープで検索されます。実際には、クロージャ・スコープだけでなく、すべてのスコープですべてのフリー変数は、関数が定義されている場所で検索される。
function foo() {
const c = 0x64;
return function () {
console.log(c);
};
}
const obj = foo();
const bar = 0xc8;
obj();
function bar(c) {
let b = 0xc8;
c();
}
let obj = 0x64;
function foo() {
console.log(obj);
}
bar(foo);
this
- これ」の利用シーン
通常の関数として:ウィンドウを直接返す
call apply bindを使用:バインドされているものを渡します。
オブジェクトメソッドとして呼び出された場合:オブジェクト自身を返します。
クラスメソッドで呼び出された場合:現在のインスタンスそのものを返します。
アロー関数:親である thisのスコープを探します。
thisスコープ:thisがどのような値を取るかは、関数の実行時ではなく、実行時に決定されます。実行時ではありません。
function foo() {
console.log(this);
}
foo();
foo.call({ 'x': 0x64 });
const bar = foo.bind({ 'x': 0xc8 });
bar();
const obj = {
'name': ' ',
'foo'() {
console.log(this);
},
'wait'() {
console.log(this);
setTimeout(function () { console.log(this);
});
}
};
ここではsetTimeoutは通常の関数として呼び出され、setTimeout自体は関数として実行されます。オブジェクトzhangsanのsayHiメソッドやwaitメソッドとして実行されるわけではないので、thisオブジェクトはwindowです。
const tanakasan = {
name: ' ',
sayHi() {
// thisつまり、現在のオブジェクト
console.log(this)
},
waitAgain() {
setTimeout(() => {
// thisつまり、現在のオブジェクト
console.log(this)
})
}
}
アロー関数のスコープ:アロー関数は常に親スコープの thisの値を取ります。
class a {
constructor(obj) {
this.name = obj;
this.c = 0x14;
}
.b() {
console.log(this);
}
}
const foo = new a(' ');
foo.b();
質問と回答
- その "これ "のさまざまな適用シーンと評価方法とは?
- 手書きバインド機能
バインドの応用
function bar(obj, A, B) {
console.log('this', this);
console.log(obj, A, B);
return 'this\x20is\x20fn1';
}
const foo = bar.bind({ 'x': 0x64 });
const a = foo();
console.log(a);
bindはfn1のプロパティではないので、プロトタイプチェーンを調べてください。bind、call、applyはすべてFunctionのプロパティです。手書きバインド
Function.prototype.obj = function () {
const bar = Array.prototype.slice.call(arguments);
const foo = bar.shift();
const B = this;
return function () {
return B.apply(foo, bar);
};
};
function a(Foo, Obj, A) {
console.log('this', this);
console.log(Foo, Obj, A);
return 'this\x20is\x20fn1';
}
const c = a.obj({ 'x': 0x64 });
const b = c();
console.log(b);
返される結果は、上記のネイティブバインドの場合と同じです。
- クロージャのアプリケーションシナリオの実際の開発、例:データを非表示にするクロージャは、単純なキャッシュツールを行います。
function obj() {
const bar = {};
return {
'set': function (foo, a) { bar[foo] = a;
},
'get': function (Bar) { return bar[Bar];
}
};
}
const b = obj();
b.set('a', 0x64);
console.log(b.get('a'));
データは createCache 関数の範囲内にあり、外部からはアクセスできません。set または get を使用せずに data の値を変更または取得する方法はありません。
data.b に直接アクセスするとエラーになります。
- a'ラベルを10枚作成し、クリックするとシリアル番号がポップアップ表示されます。
// 10を作成する'<a>'タグを使用して、クリックされたときに対応するシリアル番号をポップアップ表示する
let i, a
for (i = 0; i < 10; i++) {
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function(e){
e.preventDefault()
alert(i)
})
}
document.body.appendChild(a);
なぜなら、alert(i)はクリックされたときに発生し、このときiは10になっているからです。これを解決するには?forの中にlet iを定義します。これはforループが発生するたびに生成されるブロックレベルのスコープです。上記とは異なり、上記のiはグローバル・スコープです。
// 10を作成する'<a>'タグを使用して、クリックされたときに対応するシリアル番号をポップアップ表示する
let a
for (let i = 0; i < 10; i++) {
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function(e){
e.preventDefault()
alert(i)
})
}
document.body.appendChild(a);
JS -
同期と非同期の違い
シングルスレッドで非同期
- JSはシングルスレッド言語であり、一度に一つのことしかできません。
- ブラウザとnodejsはすでにWeb WorkerのようなJS起動プロセスをサポートしています。
- JSはDOM構造を変更できるため、JSとDOMレンダリングは同じスレッドを共有します。
- 待ちが発生したときにメインをカード化することはできません。(非同期はシングルスレッドという文脈によって提案されたもので、シングルスレッドの欠点があるからこそ非同期がサポートされるべきなのです。
- 非同期
- 非同期は、コールバックに基づくコールバック関数という形で実装されます。
非同期と同期
- JSがシングルスレッド言語であることを踏まえ
- 非同期はコードの実行をブロックしません
- 同期がコード実行をブロック
console.log(0x64);
setTimeout(function () {
console.log(0xc8);
}, 0x3e8);
console.log(0x12c);
非同期実行はコールバック関数を通して行われ、非同期機能は次のコードの実行をブロックしません。
コールバック関数:function(){console.log(200)}。
console.log(0x64);
alert(0xc8);
console.log(0x12c);
まず100がプリントアウトされ、次に200がポップアップ表示されます。OKをクリックしないと300はプリントアウトされず、場所が詰まってしまいます。後ろのコードは実行されません。
- 同期と非同期の違いは何ですか?
- プロミスでイメージを読み込む手書き
- フロントエンドで非同期が使用されるシナリオは何ですか?
1) ajaxイメージロードのようなネットワークリクエスト
2) setTimeoutのような時限タスク
console.log('start');
$.get('./data1.json', function (c) {
console.log(c);
});
console.log('end');
startを表示し、ajaxでdata1.jsonをリクエストし、endを表示します。
console.log('start');
let c = document.createElement('img');
c.onload = function () {
console.log('loaded');
};
c.src = '/xxx.png';
console.log('end');
onloadはコールバック関数で、imgのsrcが代入されます。imgのsrcが代入されるとイメージの読み込みを開始し、イメージが読み込まれるとprint loadedとなります。
promise
// 最初のデータを取得する
$.get(url1, (data1) => {
console.log(data1)
// 2つ目のデータを取得する
$.get(url2, (data2) => {
console.log(data2)
// 3つ目のデータを取得する
$.get(url3, (data3) = >{
console.log(data3)
// さらにデータを取得し続ける
})
})
})
コールバック地獄地獄は何層にもわたって存在します。 だからプロミスが生まれたのです。
function getData(url) {
return new Promise((resolve, reject) => {
$.ajax({
url,
success(data) {
resolve(data)
},
error(err) {
reject(err)
}
})
})
}
const url1 = '/data1.json'
const url2 = '/data2.json'
const url3 = '/data3.json'
getData(url1).then(data1 => {
console.log(data1)
return getData(url2)
}).then(data2 => {
console.log(data2)
return getData(url3)
}).then(data3 => {
console.log(data3)
}).catch(err => cosnole.error(err))
質問と回答
- 同期と非同期の違いは何ですか?JSはシングルスレッド・ベースの言語です。非同期はコードの実行をブロックしませんが、同期はブロックします。
- プロミスでイメージを読み込む手書き
loadImg = (src) => {
return new Promise((resolve, reject) => {
const img = document.createElement('img');
img.onload = () => {
resolve(img)
}
img.onerror = () => {
const err = new Error(`イメージロードの失敗 ${src}`)
reject(err)
}
img.src = src
})
}
const url = 'https://.../--.pg';
loadImg(url).then(img => {
console.log(img.width)
return img
}).then(img => {
console.log(img.height)
}).catch(ex => console.error(ex))
- プロミスで複数のイメージを手書きで読み込み
loadImg = (src) => {
return new Promise((resolve, reject) => {
const img = document.createElement('img');
img.onload = () => {
resolve(img)
}
img.onerror = () => {
const err = new Error(`イメージロードの失敗 ${src}`)
reject(err)
}
img.src = src
})
}
const url1 = 'https://.../--.pg';
const url2 = 'https://...//?--=/,_,_,_/,_pg';
loadImg(url1).then(img1 => {
console.log(img1.width)
return img1
}).then(img1 => {
console.log(img1.height)
return loadImg(url2)
}).then(img2 => {
console.log(img2.width)
return img2
}).then(img2 => {
console.log(img2.height)
}).catch(ex => console.error(ex))
- setTimeout
console.log(0x1);
setTimeout(function () {
console.log(0x2);
}, 0x3e8);
console.log(0x3);
setTimeout(function () {
console.log(0x4);
}, 0x0);
console.log(0x5);
印刷の順番は1、3、5、4、2。
概要
- シングルスレッドと非同期、非同期と同期の違い
- フロントエンドの非同期アプリケーションシナリオ:ネットワークリクエストとタイムドタスク
- Promiseはコールバック地獄の入れ子問題を解決します。
JS-Web-API-DOM
JSの基本からJS-Web-API
- JSの基本、規定の構文
- JS Web API、ウェブ操作用API
- 前者は後者の基礎であり、この2つの組み合わせが唯一の実際の応用です。
JS Web API
- DOM
- BOM
- イベントバインディング
- AJAX
- 保存
DOM
現在、VueやReactなどのフレームワークが広く使われており、DOM操作がカプセル化されていますが、DOM操作はいつの時代もフロントエンドエンジニアの基本的な必須知識です。フレームワークだけ知っていてDOM操作を知らないフロントエンドプログラマーは長続きしません。
DOM
- 問題
DOMとはどのようなデータ構造ですか?
DOM操作のための一般的なAPIとは?
attr と property の違いは?
パフォーマンスを考慮して複数の DOM ノードを一度に挿入するには? - 知識ポイント
DOMの本質:html言語から解析されたツリー構造。
DOM ノードの操作
1)DOMノードの取得
const b = document.getElementById('div1');
const bar = document.getElementsByTagName('div');
console.log(bar.length);
console.log(bar[0x0]);
const a = document.getElementsByClassName('.container');
const c = document.querySelectorAll('p');
2) DOM ノード属性
const b = document.obj('p');
const c = pLsit[0x0];
c.setAttribute('data-name', 'imooc');
c.getAttribute('data-name');
c.setAttribute('style', 'font-size:30px;');
c.getAttribute('style');
3) DOMノードのプロパティ
DOM 要素を取得し、js オブジェクト プロパティの形式で内部の style、className、nodeName を操作します。
const c = document.querySelectorAll('p');
const b = c[0x0];
console.log(b.style.width);
b.style.width = '100px';
console.log(b.className);
b.className = 'p1';
console.log(b.nodeName);
console.log(b.nodeType);
DOM構造の操作
1) ノードの追加/挿入
const b = document.getElementById('div1');
const foo = document.createElement('p');
foo.innerHTML = 'this\x20is\x20p1';
b.appendChild(foo);
const a = document.getElementById('p2');
b.c(a);
2) 子要素のリストと親要素の取得
// 親要素を取得する
const div1 = document.getElementById('div1')
const parent = div1.parentNode
// 子要素のリストを取得する
const div1 = document.getElementById('div1')
console.log(div1.childNodes)
const div1ChildNodesP = Array.prototype.slice.call(div1.childNodes).filter(child => child.nodeType === 1)
3) ノードの削除
const foo = document.getElementById('div1');
const bar = foo.childNodes;
foo.removeChild(bar[0x0]);
DOMパフォーマンス
- DOM操作は非常に「高価」なので、頻繁なDOM操作は避けてください。
- DOM
// DOMクエリの結果をキャッシュしない
for (let i=0; i<document.getElementsByTagName('p').length; i++) {
// ループするたびに長さを計算し、頻繁にDOMクエリを行う。
}
// DOMクエリの結果をキャッシュする
const pList = document.getElementsByTagName('p')
const length = pList.length
for (let i=0; i< length; i++) {
// キャッシュの長さ、1つのDOMクエリのみ
}
- 頻繁な操作を1回限りの操作に置き換え
const listNode = document.getElementById('list')
// 挿入を実行する
for(let i=0; i<10; i++) {
const li = document.createElement('li')
li.innerHTML = `List item ${i}`
// 毎回、頻繁にDOMを操作する
listNode.appendChild(li)
}
// =>
const listNode = document.getElementById('list')
// まだDOMツリーに挿入されていないドキュメントフラグメントを作成する。
const frag = document.createDocumentFragment()
// 挿入を実行する
for(let i=0; i<10; i++) {
const li = document.createElement('li')
li.innerHTML = `List item ${i}`
frag.appendChild(li)
}
// これがすべて終わったら、DOMツリーに挿入する
listNode.aapendChild(frag)
- 質問と回答
- DOMはどのデータ構造ですか?
ツリー - DOM操作の一般的なAPIは何ですか?
DOMノード操作とDOM構造操作 - attrとpropertyの違いは何ですか?
property: オブジェクトの属性を変更しても、html構造には反映されません。
attribute:htmlの属性を変更します。
どちらもDOMの再レンダリングを引き起こす可能性があります。
- DOMはどのデータ構造ですか?
- 概要
- DOM
- DOMノード操作
- DOM構造の操作
- DOM
JS-Web-API-BOM
BOM操作
ちしんてん
- ナビゲータ ブラウザ情報
const c = navigator.userAgent;
const b = c.indexOf('Chrome');
console.log(b);
- screen 画面情報
console.log(screen.width);
console.log(screen.height);
- ロケーションアドレス情報、URL情報の分析
console.log(location.href);
console.log(location.protocol);
console.log(location.pathname);
console.log(location.search);
console.log(location.hash);
console.log(location.host);
- 歴史 歴史の閲覧、前進と後退
history.back()
history.forward()
問題
- ブラウザの種類を認識する方法
const a = navigator.userAgent;
const foo = a.indexOf('Chrome');
console.log(foo);
- 分解されたurlの各部分の分析
console.log(location.href);
console.log(location.protocol);
console.log(location.pathname);
console.log(location.search);
console.log(location.hash);
console.log(location.host);
JS-Web-API-Events
イベントバインディングとイベントバブリング
イベントバインディング
const btn = document.getElementById('btn1')
btn.addEventListener('click', evet => {
console.log('clicked')
})
汎用イベントのバインディング
function bindEvent(elem,type,fn) {
elem.addEventListener(type, fn)
}
const a = document.getElementById('link1')
bindEvent(a, 'click', e => {
console.log(event.target) // <a id='link1>接続</a>
e.preventDefault() // デフォルトの動作をブロックする
alert('clicked')
})
イベントバブリング
<body>
<div id="div1">
<p id="p1"> </p>
<p id="p2"> </p>
<p id="p3"> </p>
<p id="p4"> </p>
</div>
<div id="div2">
<p id="p5> </p>
<p id="p6>
</div>
</body>
const foo = document.getElementById('p1');
const a = document.body;
bindEvent(foo, 'click');
イベントエージェント
イベントプロキシは、イベントバブリングメカニズムを使用して、イベントプロキシを実装するために行うイベントバブリングに基づいています。
<div id="div1">
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
</div>
<button>クリックしてaタグを追加する</button>
const div1 = document.getElementById('div1');
div1.addEventLisener('click', e => {
event.preventDefault() // デフォルトのジャンプ動作をブロックする
const target = e.target
if(e.nodeName === 'A') {
alert(target.innerHTML)
}
})
- シンプルなコード
- ブラウザのメモリ使用量の削減
- 乱用厳禁
- 汎用イベントバブリングプロキシ関数
// 通常のバインディング
const btn1 = document.getElementById('btn1')
bindEvent(btn1, 'click', function(event) {
event.preventDefault() // デフォルトの動作をブロックする
alert(this.innerHTML)
})
// プロキシバインディング
const div3 = document.getElemntById('div3')
bindEvent(div3, 'click', 'a', function(event) {
event.preventDefault()
alert(this.innerHTML)
})
// => 汎用関数
function bindEvent(elem, type, selector, fn) {
if(fn == null) {
// fnnullの場合、3つのパラメータしか渡されなかったことを意味する。
fn = selector;
selector = null;
}
elem.addEventListener(type, event => {
const target = event.target;
if(selector) {
// プロキシバインディング
if(target.matches(selector)) {
fn.call(target, event)
}
} else {
// 通常のバインディング
fn.call(target, event)
}
})
}
質疑応答とまとめ
- 汎用イベント・リスナー関数を書く
- イベント・バブリングの流れを説明
- DOM構造の操作
- イベントはトリガー要素に沿ってバブルアップします。
- シナリオ: エージェント
- イメージの無限ドロップダウン・リストで、各イメージのクリックをリッスンするには?
- イベントプロキシ
- e.target を使ってトリガーとなる要素を取得します。
- matchesを使用して、要素がトリガーされたかどうかを判断します。



