diff --git a/.stfolder/syncthing-folder-ed52c7.txt b/.stfolder/syncthing-folder-ed52c7.txt new file mode 100755 index 0000000000..8119572cfe --- /dev/null +++ b/.stfolder/syncthing-folder-ed52c7.txt @@ -0,0 +1,5 @@ +# This directory is a Syncthing folder marker. +# Do not delete. + +folderID: zh.javascript.info +created: 2024-09-17T00:54:09+08:00 diff --git a/.stignore b/.stignore new file mode 100755 index 0000000000..6b8710a711 --- /dev/null +++ b/.stignore @@ -0,0 +1 @@ +.git diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100755 index 0000000000..6a7cc47eab --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Chrome", + "request": "launch", + "type": "chrome", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + }, + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${file}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100755 index 0000000000..e438494dec --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,27 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "echo", + "type": "shell", + "command": "echo Hello ${file}" + }, + { + "label": "replace ALERT", + "type": "shell", + "command": "d:\\git\\usr\\bin\\sed -i 's/alert/console.log/g' ${file}" + }, + { + "label": "gvim", + "type": "shell", + "command": "D:/Vim/vim91/gvim.exe ${file}" + } + { + "label": "git add", + "type": "shell", + "command": "D:/Git/mingw64/libexec/git-core/git.exe add ${file}" + } + ] +} diff --git a/1-js/05-data-types/03-string/1.js b/1-js/05-data-types/03-string/1.js new file mode 100755 index 0000000000..85153fef44 --- /dev/null +++ b/1-js/05-data-types/03-string/1.js @@ -0,0 +1,5 @@ + +let str = 'Hi'; + +str[0] = 'h'; // error +console.log( str[0] ); // 不成功 diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index 8d381f8e24..ef40df83c6 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -186,7 +186,7 @@ for (let char of "Hello") { let str = 'Hi'; str[0] = 'h'; // error -alert( str[0] ); // 无法运行 +alert( str[0] ); // 没成功 ``` 通常的解决方法是创建一个新的字符串,并将其分配给 `str` 而不是以前的字符串。 diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md old mode 100644 new mode 100755 diff --git a/1-js/05-data-types/04-array/test.js b/1-js/05-data-types/04-array/test.js new file mode 100755 index 0000000000..09fa71ced7 --- /dev/null +++ b/1-js/05-data-types/04-array/test.js @@ -0,0 +1,3 @@ + +console.log(1); +console.log(2); diff --git a/1-js/05-data-types/05-array-methods/1.js b/1-js/05-data-types/05-array-methods/1.js new file mode 100755 index 0000000000..dbfa3d1272 --- /dev/null +++ b/1-js/05-data-types/05-array-methods/1.js @@ -0,0 +1,22 @@ + +let army = { + minAge: 18, + maxAge: 27, + canJoin(user) { + return user.age >= this.minAge && user.age < this.maxAge; + } +}; + +let users = [ + {age: 16}, + {age: 20}, + {age: 23}, + {age: 30} +]; + +// 找到 army.canJoin 返回 true 的 user +let soldiers = users.filter(army.canJoin, army); + +console.log(soldiers.length); // 2 +console.log(soldiers[0].age); // 20 +console.log(soldiers[1].age); // 23 diff --git a/1-js/05-data-types/05-array-methods/article.md b/1-js/05-data-types/05-array-methods/article.md old mode 100644 new mode 100755 diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md old mode 100644 new mode 100755 diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md old mode 100644 new mode 100755 diff --git a/1-js/05-data-types/08-weakmap-weakset/1.js b/1-js/05-data-types/08-weakmap-weakset/1.js new file mode 100755 index 0000000000..231cefa5d1 --- /dev/null +++ b/1-js/05-data-types/08-weakmap-weakset/1.js @@ -0,0 +1,14 @@ + +let john = { name: "John" }; + +let weakMap = new WeakMap(); +weakMap.set(john, "..."); + +john = null; // 覆盖引用 + +console.log(weakMap); +// WeakMap { } + +// console.log(weakMap.get()) + +// john 被从内存中删除了! diff --git a/1-js/05-data-types/08-weakmap-weakset/article.md b/1-js/05-data-types/08-weakmap-weakset/article.md old mode 100644 new mode 100755 diff --git a/1-js/05-data-types/12-json/1.js b/1-js/05-data-types/12-json/1.js new file mode 100755 index 0000000000..8b13789179 --- /dev/null +++ b/1-js/05-data-types/12-json/1.js @@ -0,0 +1 @@ + diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md old mode 100644 new mode 100755 diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md old mode 100644 new mode 100755 diff --git a/1-js/06-advanced-functions/06-function-object/1.js b/1-js/06-advanced-functions/06-function-object/1.js new file mode 100755 index 0000000000..f0439b73a0 --- /dev/null +++ b/1-js/06-advanced-functions/06-function-object/1.js @@ -0,0 +1,20 @@ + +let sayHi = function() { + console.log("Hi"); + }; + + console.log(sayHi); + console.log(sayHi.name); // sayHi(有名字!) + + let aaa = sayHi; + console.log(aaa); // still sayHi, sure. + aaa(); + + let qqq = function(){ + console.log("q"); + }; + console.log(qqq.name); + + let ann = () => { console.log("a"); }; + console.log(ann.name); + ann(); diff --git a/1-js/06-advanced-functions/06-function-object/article.md b/1-js/06-advanced-functions/06-function-object/article.md old mode 100644 new mode 100755 diff --git a/1-js/06-advanced-functions/06-function-object/func-obj1.js b/1-js/06-advanced-functions/06-function-object/func-obj1.js new file mode 100755 index 0000000000..e353bf01c7 --- /dev/null +++ b/1-js/06-advanced-functions/06-function-object/func-obj1.js @@ -0,0 +1,13 @@ + +function sayHi() { + console.log("Hi"); + + // 计算调用次数 + sayHi.counter++; +} +sayHi.counter = 0; // 初始值 + +sayHi(); // Hi +sayHi(); // Hi + +console.log( `Called ${sayHi.counter} times` ); // Called 2 times diff --git a/1-js/06-advanced-functions/06-function-object/func-obj2.js b/1-js/06-advanced-functions/06-function-object/func-obj2.js new file mode 100755 index 0000000000..9e7cc4ed39 --- /dev/null +++ b/1-js/06-advanced-functions/06-function-object/func-obj2.js @@ -0,0 +1,17 @@ + +function makeCounter() { + // 不需要这个了 + // let count = 0 + + function counter() { + return counter.count++; + }; + + counter.count = 0; + + return counter; +} + +let ct = makeCounter(); +console.log( ct() ); // 0 +console.log( ct() ); // 1 diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md old mode 100644 new mode 100755 diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/timeout1.js b/1-js/06-advanced-functions/08-settimeout-setinterval/timeout1.js new file mode 100755 index 0000000000..92d93cf960 --- /dev/null +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/timeout1.js @@ -0,0 +1,10 @@ + +let start = Date.now(); +let times = []; + +setTimeout(function run() { + times.push(Date.now() - start); // 保存前一个调用的延时 + + if (start + 100 < Date.now()) console.log(times); // 100 毫秒之后,显示延时信息 + else setTimeout(run); // 否则重新调度 +}); diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md old mode 100644 new mode 100755 diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/deco0.js b/1-js/06-advanced-functions/09-call-apply-decorators/deco0.js new file mode 100755 index 0000000000..d0cf1a1249 --- /dev/null +++ b/1-js/06-advanced-functions/09-call-apply-decorators/deco0.js @@ -0,0 +1,29 @@ + +function slow(x) { + // 这里可能会有重负载的 CPU 密集型工作 + console.log(`Called with ${x}`); + return x; +} + +function cachingDecorator(func) { + let cache = new Map(); + + return function(x) { + if (cache.has(x)) { // 如果缓存中有对应的结果 + return cache.get(x); // 从缓存中读取结果 + } + + let result = func(x); // 否则就调用 func + + cache.set(x, result); // 然后将结果缓存(记住)下来 + return result; + }; +} + +slow = cachingDecorator(slow); + +console.log( slow(1) ); // slow(1) 被缓存下来了,并返回结果 +console.log( "Again: " + slow(1) ); // 返回缓存中的 slow(1) 的结果 + +console.log( slow(2) ); // slow(2) 被缓存下来了,并返回结果 +console.log( "Again: " + slow(2) ); // 返回缓存中的 slow(2) 的结果 diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/deco1.js b/1-js/06-advanced-functions/09-call-apply-decorators/deco1.js new file mode 100755 index 0000000000..2517487e1b --- /dev/null +++ b/1-js/06-advanced-functions/09-call-apply-decorators/deco1.js @@ -0,0 +1,34 @@ + +let worker = { + + someMethod() { + return 1; + }, + + slow(x) { + // 可怕的 CPU 过载任务 + console.log("Called with " + x); + return x * this.someMethod(); // (*) + } + +}; + +// 和之前例子中的代码相同 +function cachingDecorator(func) { + let cache = new Map(); + return function(x) { + if (cache.has(x)) { + return cache.get(x); + } + + let result = func(x); // (**) + cache.set(x, result); + return result; + }; +} + +console.log( worker.slow(1) ); // 原始方法有效 + +worker.slow = cachingDecorator(worker.slow); // 现在对其进行缓存 + +console.log( worker.slow(2) ); // 蛤!Error: Cannot read property 'someMethod' of undefined diff --git a/1-js/06-advanced-functions/10-bind/article.md b/1-js/06-advanced-functions/10-bind/article.md old mode 100644 new mode 100755 diff --git a/1-js/06-advanced-functions/10-bind/bind1.js b/1-js/06-advanced-functions/10-bind/bind1.js new file mode 100755 index 0000000000..b7bea6c928 --- /dev/null +++ b/1-js/06-advanced-functions/10-bind/bind1.js @@ -0,0 +1,11 @@ + +let user = { + firstName: "John" +}; + +function f1() { + console.log(this.firstName); +} + +let funcUser = f1.bind(user); +funcUser(); // John diff --git a/1-js/07-object-properties/01-property-descriptors/prop-desc-config.js b/1-js/07-object-properties/01-property-descriptors/prop-desc-config.js new file mode 100755 index 0000000000..4d86ee5220 --- /dev/null +++ b/1-js/07-object-properties/01-property-descriptors/prop-desc-config.js @@ -0,0 +1,42 @@ + +console.log(Math.PI); + +let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI'); + +console.log( JSON.stringify(descriptor, null, 2 ) ); +/* +{ + "value": 3.141592653589793, + "writable": false, + "enumerable": false, + "configurable": false +} +*/ + +Math.PI = 3; // Error,因为其 writable: false + +console.log(Math.PI); +// 3.141592653589793 + +// Error,因为 configurable: false +// Object.defineProperty(Math, "PI", { writable: true }); +// TypeError: Cannot redefine property: PI + + + + +let user = { + name: "John" +}; + +Object.defineProperty(user, "name", { + configurable: false +}); + +user.name = "Pete"; // 正常工作 +console.log(user); +// { name: 'Pete' } + +delete user.name; // Error +console.log(user); +// { name: 'Pete' } diff --git a/1-js/07-object-properties/01-property-descriptors/prop-desc.js b/1-js/07-object-properties/01-property-descriptors/prop-desc.js new file mode 100755 index 0000000000..3f40e9d2a9 --- /dev/null +++ b/1-js/07-object-properties/01-property-descriptors/prop-desc.js @@ -0,0 +1,16 @@ + +let user = { + name: "John" +}; + +let descriptor = Object.getOwnPropertyDescriptor(user, 'name'); + +console.log( JSON.stringify(descriptor, null, 2 ) ); +/* 属性描述符: +{ + "value": "John", + "writable": true, + "enumerable": true, + "configurable": true +} +*/ diff --git a/1-js/07-object-properties/01-property-descriptors/prop-desc2.js b/1-js/07-object-properties/01-property-descriptors/prop-desc2.js new file mode 100755 index 0000000000..865af90595 --- /dev/null +++ b/1-js/07-object-properties/01-property-descriptors/prop-desc2.js @@ -0,0 +1,63 @@ + +let user = {}; + +Object.defineProperty(user, "name", { + value: "John" +}); + +let descriptor = Object.getOwnPropertyDescriptor(user, 'name'); + +console.log( JSON.stringify(descriptor, null, 2 ) ); +/* +{ + "value": "John", + "writable": false, + "enumerable": false, + "configurable": false +} + */ + +console.log(user); +// {} + + +Object.defineProperty(user, "addr", { + value: "221B", + enumerable: true, +}); +console.log(user); +// { addr: '221B' } + +user.name = "rose"; +// no effect +console.log(user); +// { addr: '221B' } + +user.addr="13F" +// no effect +console.log(user); +// { addr: '221B' } + +Object.defineProperty(user, "nick", { + value: "nnn", + enumerable: true, +// configurable: true, + writable: true, +}); +console.log(user); +// { addr: '221B', nick: 'nnn' } + +user.nick="mmm"; +console.log(user); +// { addr: '221B', nick: 'mmm' } + +Object.defineProperty(user, "ROAttr", { + value : "init val", + enumerable: true, + writable: false, +}); +console.log(user); +// { addr: '221B', nick: 'mmm', ROAttr: 'init val' } +user.ROAttr = "failing change"; +console.log(user); +// { addr: '221B', nick: 'mmm', ROAttr: 'init val' } diff --git a/1-js/07-object-properties/01-property-descriptors/prop-desc3.js b/1-js/07-object-properties/01-property-descriptors/prop-desc3.js new file mode 100755 index 0000000000..fe7c04e548 --- /dev/null +++ b/1-js/07-object-properties/01-property-descriptors/prop-desc3.js @@ -0,0 +1,19 @@ + +let user = { + name: "John", + toString() { + return this.name; + } +}; + +// 默认情况下,我们的两个属性都会被列出: +for (let key in user) console.log(key); // name, toString + +console.log('after'); + +Object.defineProperty(user, "toString", { + enumerable: false +}); +for (let key in user) console.log(key); // name + +console.log(Object.keys(user)); // name diff --git a/1-js/07-object-properties/02-property-accessors/get-set.js b/1-js/07-object-properties/02-property-accessors/get-set.js new file mode 100755 index 0000000000..e02480cb93 --- /dev/null +++ b/1-js/07-object-properties/02-property-accessors/get-set.js @@ -0,0 +1,22 @@ + +let user = { + name: "John", + surname: "Smith", + + get fullName() { + console.log("in getter"); + return `${this.name} ${this.surname}`; + }, + + set fullName(value) { + console.log("in setter"); + [this.name, this.surname] = value.split(" "); + } +}; + +// set fullName 将以给定值执行 +user.fullName = "Alice Cooper"; + +console.log(user.name); // Alice +console.log(user.surname); // Cooper +console.log(user.fullName) \ No newline at end of file diff --git a/1-js/07-object-properties/02-property-accessors/get-set2.js b/1-js/07-object-properties/02-property-accessors/get-set2.js new file mode 100755 index 0000000000..bd9a59a4ec --- /dev/null +++ b/1-js/07-object-properties/02-property-accessors/get-set2.js @@ -0,0 +1,21 @@ + +let user = { + name: "John", + surname: "Smith" +}; + +Object.defineProperty(user, 'fullName', { + get() { + console.log("get fullname"); + return `${this.name} ${this.surname}`; + }, + + set(value) { + console.log("set fullname"); + [this.name, this.surname] = value.split(" "); + } +}); + +console.log(user.fullName); // John Smith + +for(let key in user) console.log(key); // name, surname diff --git a/1-js/07-object-properties/02-property-accessors/get.js b/1-js/07-object-properties/02-property-accessors/get.js new file mode 100755 index 0000000000..f8fe2e7e36 --- /dev/null +++ b/1-js/07-object-properties/02-property-accessors/get.js @@ -0,0 +1,15 @@ + +let user = { + name: "John", + surname: "Smith", + + get fullName() { + console.log("in getter"); + return `${this.name} ${this.surname}`; + } +}; + +console.log(user.fullName); // John Smith + +user.fullName = "Test"; // Error(属性只有一个 getter) +console.log(user.fullName); // John Smith diff --git a/1-js/07-object-properties/02-property-accessors/set1.js b/1-js/07-object-properties/02-property-accessors/set1.js new file mode 100755 index 0000000000..01ba09c5f4 --- /dev/null +++ b/1-js/07-object-properties/02-property-accessors/set1.js @@ -0,0 +1,22 @@ + +let user = { + get name() { + return this._name; + }, + + set name(value) { + if (value.length < 4) { + console.log("Name is too short, need at least 4 characters"); + return; + } + this._name = value; + } +}; + +user.name = "Pete"; +console.log(user.name); // Pete + +user.name = ""; // Name 太短了…… + +console.log(user._name); +// Pete diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto0.js b/1-js/08-prototypes/01-prototype-inheritance/proto0.js new file mode 100755 index 0000000000..b7e75cd1a1 --- /dev/null +++ b/1-js/08-prototypes/01-prototype-inheritance/proto0.js @@ -0,0 +1,21 @@ + +let Animal = { + walk(){ console.log('walk'); } +}; + +console.log("A _ ", Animal.__proto__); +// [Object: null prototype] {} + + +console.log("A p ", Animal.prototype); +// undefined + + +let Rabbit = { + __proto__: Animal, +}; +console.log("R _ ", Rabbit.__proto__); +// {} + +console.log("R p ", Rabbit.prototype); +// undefined diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto1.js b/1-js/08-prototypes/01-prototype-inheritance/proto1.js new file mode 100755 index 0000000000..b2924a56cc --- /dev/null +++ b/1-js/08-prototypes/01-prototype-inheritance/proto1.js @@ -0,0 +1,77 @@ + +let animal = { + eats: true, + + walk() { + console.log("Animal walk"); + } +}; + +let rabbit = { + jumps: true +}; + +console.log("animal ", animal); +console.log("rabbit ", rabbit); +/* +animal { eats: true } +rabbit { jumps: true } +*/ + +console.log(rabbit.__proto__); +// [Object: null prototype] {} + +console.log(animal.__proto__); +// [Object: null prototype] {} + +rabbit.__proto__ = animal; +console.log("rp ", rabbit.__proto__); +// { eats: true } +console.log("r2 ", rabbit); +// r2 { jumps: true } + +console.log(rabbit.jumps); +console.log(rabbit.eats); + +rabbit.walk(); + +// Object.keys 只返回自己的 key +console.log("keys ", Object.keys(rabbit)); // jumps + +// for..in 会遍历自己以及继承的键 +console.log("for in"); +for(let prop in rabbit) console.log(prop); // jumps,然后是 eats + +console.log("check own"); +for(let prop in rabbit) { + let isOwn = rabbit.hasOwnProperty(prop); + + if (isOwn) { + console.log(`Our: ${prop}`); // Our: jumps + } else { + console.log(`Inherited: ${prop}`); // Inherited: eats + } +} + + + + +console.log("longEar:"); + +let longEar = { + earLen: 10, + __proto__: rabbit, +}; +console.log(longEar.jumps); +longEar.walk(); + + +// let A = { +// __proto__: B, +// // ReferenceError: Cannot access 'B' before initialization +// } + +// let B = { +// __proto__: A, +// } + diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto2.js b/1-js/08-prototypes/01-prototype-inheritance/proto2.js new file mode 100755 index 0000000000..82c792d849 --- /dev/null +++ b/1-js/08-prototypes/01-prototype-inheritance/proto2.js @@ -0,0 +1,17 @@ + +let animal = { + eats: true, + walk() { + console.log("Animal walk"); + } +}; + +let rabbit = { + __proto__: animal +}; + +rabbit.walk = function() { + console.log("Rabbit! Bounce-bounce!"); +}; + +rabbit.walk(); // Rabbit! Bounce-bounce! diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto3.js b/1-js/08-prototypes/01-prototype-inheritance/proto3.js new file mode 100755 index 0000000000..192e1dfc2e --- /dev/null +++ b/1-js/08-prototypes/01-prototype-inheritance/proto3.js @@ -0,0 +1,31 @@ + +let user = { + name: "John", + surname: "Smith", + + set fullName(value) { + console.log("setter ", value, " for ", this); + [this.name, this.surname] = value.split(" "); + }, + + get fullName() { + console.log("getter for ", this); + return `${this.name} ${this.surname}`; + } +}; + +let admin = { + __proto__: user, + isAdmin: true +}; + +console.log(user); +console.log(admin); + +console.log(admin.fullName); // John Smith (*) + +// setter triggers! +admin.fullName = "Alice Cooper"; // (**) + +console.log(admin.fullName); // Alice Cooper,admin 的内容被修改了 +console.log(user.fullName); // John Smith,user 的内容被保护了 diff --git a/1-js/08-prototypes/01-prototype-inheritance/this1.js b/1-js/08-prototypes/01-prototype-inheritance/this1.js new file mode 100755 index 0000000000..a754c6d0ec --- /dev/null +++ b/1-js/08-prototypes/01-prototype-inheritance/this1.js @@ -0,0 +1,37 @@ + +// animal 有一些方法 +let animal = { + walk() { + if (!this.isSleeping) { + console.log(`I walk`); + } + }, + sleep() { + this.isSleeping = true; + } +}; + +let rabbit = { + name: "White Rabbit", + __proto__: animal +}; + +console.log(animal); +console.log(rabbit); +/* +{ walk: [Function: walk], sleep: [Function: sleep] } +{ name: 'White Rabbit' } + */ + +// 修改 rabbit.isSleeping +rabbit.sleep(); + +console.log(animal); +console.log(rabbit); +/* +{ walk: [Function: walk], sleep: [Function: sleep] } +{ name: 'White Rabbit', isSleeping: true } + */ + +console.log(rabbit.isSleeping); // true +console.log(animal.isSleeping); // undefined(原型中没有此属性) diff --git a/1-js/08-prototypes/02-function-prototype/2.js b/1-js/08-prototypes/02-function-prototype/2.js new file mode 100755 index 0000000000..849c48e4ba --- /dev/null +++ b/1-js/08-prototypes/02-function-prototype/2.js @@ -0,0 +1,23 @@ + +function Rabbit() {} +// 默认: +// Rabbit.prototype = { constructor: Rabbit } + +console.log( Rabbit.prototype); +// {} +console.log( Rabbit.prototype.constructor); +// [Function: Rabbit] + +// !! attention +console.log(Rabbit.constructor); +// [Function: Function] + +console.log( Rabbit.prototype.constructor == Rabbit ); // true + + +console.log(Rabbit.__proto__); // {} +console.log(Rabbit.__proto__ == Function.prototype); // true + +console.log(Rabbit.__proto__.prototype); // undefined +console.log(Rabbit.__proto__.constructor); // [Function: Function] + diff --git a/1-js/08-prototypes/02-function-prototype/3.js b/1-js/08-prototypes/02-function-prototype/3.js new file mode 100755 index 0000000000..871716b32d --- /dev/null +++ b/1-js/08-prototypes/02-function-prototype/3.js @@ -0,0 +1,11 @@ + +function Rabbit() {} +// 默认: +// Rabbit.prototype = { constructor: Rabbit } + +let rabbit = new Rabbit(); // 继承自 {constructor: Rabbit} + +console.log(rabbit.constructor); +// [Function: Rabbit] + +console.log(rabbit.constructor == Rabbit); // true (from prototype) diff --git a/1-js/08-prototypes/02-function-prototype/4.js b/1-js/08-prototypes/02-function-prototype/4.js new file mode 100755 index 0000000000..04f801d362 --- /dev/null +++ b/1-js/08-prototypes/02-function-prototype/4.js @@ -0,0 +1,9 @@ + +function Rabbit(name) { + this.name = name; + console.log(name); +} + +let rabbit = new Rabbit("White Rabbit"); + +let rabbit2 = new rabbit.constructor("Black Rabbit"); diff --git a/1-js/08-prototypes/02-function-prototype/5.js b/1-js/08-prototypes/02-function-prototype/5.js new file mode 100755 index 0000000000..f0a562ade5 --- /dev/null +++ b/1-js/08-prototypes/02-function-prototype/5.js @@ -0,0 +1,16 @@ + +function Rabbit() {} + +console.log( Rabbit.prototype.constructor); +// [Function: Rabbit] + + +Rabbit.prototype = { + jumps: true +}; + +console.log( Rabbit.prototype.constructor); +// [Function: Object] + +let rabbit = new Rabbit(); +console.log(rabbit.constructor === Rabbit); // false diff --git a/1-js/08-prototypes/02-function-prototype/6.js b/1-js/08-prototypes/02-function-prototype/6.js new file mode 100755 index 0000000000..cc8335f707 --- /dev/null +++ b/1-js/08-prototypes/02-function-prototype/6.js @@ -0,0 +1,10 @@ + +function Rabbit() {} + +// 不要将 Rabbit.prototype 整个覆盖 +// 可以向其中添加内容 +Rabbit.prototype.jumps = true +// 默认的 Rabbit.prototype.constructor 被保留了下来 + +console.log( Rabbit.prototype.constructor); +// [Function: Rabbit] diff --git a/1-js/08-prototypes/02-function-prototype/func-proto.js b/1-js/08-prototypes/02-function-prototype/func-proto.js new file mode 100755 index 0000000000..720d719865 --- /dev/null +++ b/1-js/08-prototypes/02-function-prototype/func-proto.js @@ -0,0 +1,17 @@ + +let animal = { + eats: true +}; + +function Rabbit(name) { + this.name = name; +} + +Rabbit.prototype = animal; + +let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal + +console.log(rabbit); +console.log(rabbit.__proto__); + +console.log( rabbit.eats ); // true diff --git a/1-js/08-prototypes/03-native-prototypes/1.js b/1-js/08-prototypes/03-native-prototypes/1.js new file mode 100755 index 0000000000..f465ff57a8 --- /dev/null +++ b/1-js/08-prototypes/03-native-prototypes/1.js @@ -0,0 +1,21 @@ + +let obj = {}; +console.log( obj ); // "[object Object]" ? + +console.log(obj.toString); +console.log(obj.toStringxxx); +/* +{} +[Function: toString] +undefined +*/ + +console.log(obj.__proto__); +// [Object: null prototype] {} + +console.log(obj.__proto__ === Object.prototype); // true + +console.log(obj.toString === obj.__proto__.toString); //true +console.log(obj.toString === Object.prototype.toString); //true + +console.log(Object.prototype.__proto__); // null diff --git a/1-js/08-prototypes/03-native-prototypes/2.js b/1-js/08-prototypes/03-native-prototypes/2.js new file mode 100755 index 0000000000..af92478abb --- /dev/null +++ b/1-js/08-prototypes/03-native-prototypes/2.js @@ -0,0 +1,31 @@ + +let arr = [1, 2, 3]; + +console.log(arr); +// [ 1, 2, 3 ] + +console.log(arr.__proto__); +// Object(0) [] + +// 它继承自 Array.prototype? +console.log( arr.__proto__ === Array.prototype ); // true + +// 接下来继承自 Object.prototype? +console.log( arr.__proto__.__proto__ === Object.prototype ); // true + +// 原型链的顶端为 null。 +console.log( arr.__proto__.__proto__.__proto__ ); // null + +console.log(Array.prototype); +// Object(0) [] + +console.log(Array.__proto__); +// {} + + +console.log(arr.toString()); +// 1,2,3 + +console.log(arr.toString); +// [Function: toString] +// Array.toString() diff --git a/1-js/08-prototypes/03-native-prototypes/3.js b/1-js/08-prototypes/03-native-prototypes/3.js new file mode 100755 index 0000000000..a6f3d720fa --- /dev/null +++ b/1-js/08-prototypes/03-native-prototypes/3.js @@ -0,0 +1,16 @@ + +// 更改原生原型 +// not recommended + +String.prototype.show = function() { + console.log(this); +}; + +"BOOM!".show(); // BOOM! +// [String: 'BOOM!'] + +String.prototype.show = function() { + console.log("again ", this); +}; +"BOOM!".show(); +// again [String: 'BOOM!'] diff --git a/1-js/08-prototypes/03-native-prototypes/borrow copy 2.js b/1-js/08-prototypes/03-native-prototypes/borrow copy 2.js new file mode 100755 index 0000000000..10bb308c08 --- /dev/null +++ b/1-js/08-prototypes/03-native-prototypes/borrow copy 2.js @@ -0,0 +1,15 @@ + +let obj = { + 0: "Hello", + 1: "world!", + length: 3, +}; + +// console.log( obj.join(',') ); +// TypeError: obj.join is not a function + + +obj.join = Array.prototype.join; + +console.log( obj.join(',') ); +// Hello,world!, diff --git a/1-js/08-prototypes/03-native-prototypes/borrow copy.js b/1-js/08-prototypes/03-native-prototypes/borrow copy.js new file mode 100755 index 0000000000..29dee8b0aa --- /dev/null +++ b/1-js/08-prototypes/03-native-prototypes/borrow copy.js @@ -0,0 +1,15 @@ + +let obj = { + 0: "Hello", + 1: "world!", + 2: "you", + length: 2, +}; + +// console.log( obj.join(',') ); +// TypeError: obj.join is not a function + + +obj.join = Array.prototype.join; + +console.log( obj.join(',') ); // Hello,world! diff --git a/1-js/08-prototypes/03-native-prototypes/borrow.js b/1-js/08-prototypes/03-native-prototypes/borrow.js new file mode 100755 index 0000000000..d104401e0c --- /dev/null +++ b/1-js/08-prototypes/03-native-prototypes/borrow.js @@ -0,0 +1,14 @@ + +let obj = { + 0: "Hello", + 1: "world!", + length: 2, +}; + +// console.log( obj.join(',') ); +// TypeError: obj.join is not a function + + +obj.join = Array.prototype.join; + +console.log( obj.join(',') ); // Hello,world! diff --git a/1-js/08-prototypes/03-native-prototypes/polyfill.js b/1-js/08-prototypes/03-native-prototypes/polyfill.js new file mode 100755 index 0000000000..70aada1c97 --- /dev/null +++ b/1-js/08-prototypes/03-native-prototypes/polyfill.js @@ -0,0 +1,14 @@ + +if (!String.prototype.repeat) { // 如果这儿没有这个方法 + // 那就在 prototype 中添加它 + + String.prototype.repeat = function(n) { + // 重复传入的字符串 n 次 + + // 实际上,实现代码比这个要复杂一些(完整的方法可以在规范中找到) + // 但即使是不够完美的 polyfill 也常常被认为是足够好的 + return new Array(n + 1).join(this); + }; +} + +console.log( "La".repeat(3) ); // LaLaLa diff --git a/1-js/08-prototypes/04-prototype-methods/2.js b/1-js/08-prototypes/04-prototype-methods/2.js new file mode 100755 index 0000000000..05d6326e22 --- /dev/null +++ b/1-js/08-prototypes/04-prototype-methods/2.js @@ -0,0 +1,22 @@ + +let animal = { + eats: true +}; + +let rabbit = Object.create(animal, { + jumps: { + value: true + } +}); + +console.log(rabbit); +// {} + +console.log(rabbit.jumps); // true + +console.log(rabbit.__proto__); +// { eats: true } +// = animal + +/* +*/ \ No newline at end of file diff --git a/1-js/08-prototypes/04-prototype-methods/3.js b/1-js/08-prototypes/04-prototype-methods/3.js new file mode 100755 index 0000000000..bd3a46558e --- /dev/null +++ b/1-js/08-prototypes/04-prototype-methods/3.js @@ -0,0 +1,9 @@ + +let chineseDictionary = Object.create(null); +chineseDictionary.hello = "你好"; +chineseDictionary.bye = "再见"; + +console.log(Object.keys(chineseDictionary)); // hello,bye + +console.log(Object.keys); +// [Function: keys] diff --git a/1-js/08-prototypes/04-prototype-methods/set-proto.js b/1-js/08-prototypes/04-prototype-methods/set-proto.js new file mode 100755 index 0000000000..0e8f55ec4f --- /dev/null +++ b/1-js/08-prototypes/04-prototype-methods/set-proto.js @@ -0,0 +1,13 @@ + +let animal = { + eats: true +}; + +// 创建一个以 animal 为原型的新对象 +let rabbit = Object.create(animal); // 与 {__proto__: animal} 相同 + +console.log(rabbit.eats); // true + +console.log(Object.getPrototypeOf(rabbit) === animal); // true + +Object.setPrototypeOf(rabbit, {}); // 将 rabbit 的原型修改为 {} diff --git a/1-js/09-classes/01-class/1.js b/1-js/09-classes/01-class/1.js new file mode 100755 index 0000000000..e4853d982c --- /dev/null +++ b/1-js/09-classes/01-class/1.js @@ -0,0 +1,32 @@ + +class User { + + constructor(name) { + console.log("constr"); + this.name = name; + } + + sayHi() { + console.log(this.name); + } + +} + +// 用法: +let user = new User("John"); +user.sayHi(); + +console.log(typeof user); // object +console.log(typeof User); // function !! + +// class 是一个函数 +console.log(typeof User); // function + +// ...或者,更确切地说,是 constructor 方法 +console.log(User === User.prototype.constructor); // true + +// 方法在 User.prototype 中,例如: +console.log(User.prototype.sayHi); // sayHi 方法的代码 (only shows in browser) + +// 在原型中实际上有两个方法 +console.log(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi diff --git a/1-js/09-classes/01-class/2.js b/1-js/09-classes/01-class/2.js new file mode 100755 index 0000000000..cf5edd3c96 --- /dev/null +++ b/1-js/09-classes/01-class/2.js @@ -0,0 +1,14 @@ + +// “命名类表达式(Named Class Expression)” +// (规范中没有这样的术语,但是它和命名函数表达式类似) +let User = class MyClass { + sayHi() { + console.log(MyClass); // MyClass 这个名字仅在类内部可见 + } +}; + +new User().sayHi(); // 正常运行,显示 MyClass 中定义的内容 +// [class MyClass] +// in nodejs + +// console.log(MyClass); // error,MyClass 在外部不可见 diff --git a/1-js/09-classes/01-class/3.js b/1-js/09-classes/01-class/3.js new file mode 100755 index 0000000000..423dd99d2b --- /dev/null +++ b/1-js/09-classes/01-class/3.js @@ -0,0 +1,26 @@ + +class User { + + constructor(name) { + // 调用 setter + this.name = name; + } + + get name() { + return this._name; + } + + set name(value) { + if (value.length < 4) { + console.log("Name is too short."); + return; + } + this._name = value; + } + +} + +let user = new User("John"); +console.log(user.name); // John + +user = new User(""); // Name is too short. diff --git a/1-js/09-classes/01-class/4.js b/1-js/09-classes/01-class/4.js new file mode 100755 index 0000000000..6168cdff2b --- /dev/null +++ b/1-js/09-classes/01-class/4.js @@ -0,0 +1,10 @@ + +class User { + + ['say' + 'Hi']() { + console.log("Hello"); + } + +} + +new User().sayHi(); diff --git a/1-js/09-classes/01-class/this-fix.js b/1-js/09-classes/01-class/this-fix.js new file mode 100755 index 0000000000..fe9c55a45a --- /dev/null +++ b/1-js/09-classes/01-class/this-fix.js @@ -0,0 +1,14 @@ + +class Button { + constructor(value) { + this.value = value; + } + click = () => { + console.log(this); + console.log(this.value); + } +} + +let button = new Button("hello"); + +setTimeout(button.click, 1000); // hello diff --git a/1-js/09-classes/01-class/this.js b/1-js/09-classes/01-class/this.js new file mode 100755 index 0000000000..55a1109a30 --- /dev/null +++ b/1-js/09-classes/01-class/this.js @@ -0,0 +1,34 @@ + +class Button { + constructor(value) { + this.value = value; + } + + click() { + console.log(this); + console.log(this.value); + } +} + +let button = new Button("hello"); + +button.click(); + +setTimeout(button.click, 1000); // undefined +// now "this" shows: +/* +Timeout { + _idleTimeout: 1000, + _idlePrev: null, + _idleNext: null, + _idleStart: 160, + _onTimeout: [Function: click], + _timerArgs: undefined, + _repeat: null, + _destroyed: false, + [Symbol(refed)]: true, + [Symbol(kHasPrimitive)]: false, + [Symbol(asyncId)]: 5, + [Symbol(triggerId)]: 1 +} +*/ \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/.vscode/tasks.json b/1-js/09-classes/02-class-inheritance/.vscode/tasks.json new file mode 100755 index 0000000000..af3797519c --- /dev/null +++ b/1-js/09-classes/02-class-inheritance/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "echo", + "type": "shell", + "command": "echo Hello ${file}" + }, + { + "label": "replace ALERT", + "type": "shell", + "command": "d:\\git\\usr\\bin\\sed -i 's/alert(/console.log(/g' ${file}" + } + ] +} \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/1.js b/1-js/09-classes/02-class-inheritance/1.js new file mode 100755 index 0000000000..bd0e22251a --- /dev/null +++ b/1-js/09-classes/02-class-inheritance/1.js @@ -0,0 +1,10 @@ + +function f(phrase) { + return class { + sayHi() { console.log(phrase); } + }; +} + +class User extends f("Hello") {} + +new User().sayHi(); // Hello diff --git a/1-js/09-classes/02-class-inheritance/2.js b/1-js/09-classes/02-class-inheritance/2.js new file mode 100755 index 0000000000..10a89a9e6b --- /dev/null +++ b/1-js/09-classes/02-class-inheritance/2.js @@ -0,0 +1,39 @@ + +class Animal { + + constructor(name) { + this.speed = 0; + this.name = name; + } + + run(speed) { + this.speed = speed; + console.log(`${this.name} runs with speed ${this.speed}.`); + } + + stop() { + this.speed = 0; + console.log(`${this.name} stands still.`); + } + +} + +class Rabbit extends Animal { + hide() { + console.log(`${this.name} hides!`); + } + + stop() { + super.stop(); // 调用父类的 stop + this.hide(); // 然后 hide + } +} + +let rabbit = new Rabbit("White Rabbit"); + +rabbit.run(5); // White Rabbit runs with speed 5. +rabbit.stop(); // White Rabbit stands still. White Rabbit hides! + +// setTimeout(function() { super.stop() }, 1000); +// SyntaxError: 'super' keyword unexpected here + diff --git a/1-js/09-classes/02-class-inheritance/3.js b/1-js/09-classes/02-class-inheritance/3.js new file mode 100755 index 0000000000..1f779706e6 --- /dev/null +++ b/1-js/09-classes/02-class-inheritance/3.js @@ -0,0 +1,25 @@ + +class Animal { + + constructor(name) { + this.speed = 0; + this.name = name; + } + + // ... +} + +class Rabbit extends Animal { + + constructor(name, earLength) { + super(name); + this.earLength = earLength; + } + + // ... +} + +// 现在可以了 +let rabbit = new Rabbit("White Rabbit", 10); +console.log(rabbit.name); // White Rabbit +console.log(rabbit.earLength); // 10 diff --git a/1-js/09-classes/02-class-inheritance/4.js b/1-js/09-classes/02-class-inheritance/4.js new file mode 100755 index 0000000000..c726454317 --- /dev/null +++ b/1-js/09-classes/02-class-inheritance/4.js @@ -0,0 +1,29 @@ + +class Animal { + name = 'animal'; + + constructor() { + console.log("constr ", this.name); // (*) + } +} + +class Rabbit extends Animal { + name = 'rabbit'; + + constructor(){ + super(); + console.log("name ", this.name); // rabbit + } +} + +let a = new Animal(); // animal +let r = new Rabbit(); // animal + +console.log(a); +console.log(r); + +/* +Animal { name: 'animal' } +Rabbit { name: 'rabbit' } +*/ + diff --git a/1-js/09-classes/03-static-properties-methods/1.js b/1-js/09-classes/03-static-properties-methods/1.js new file mode 100755 index 0000000000..d05ce87750 --- /dev/null +++ b/1-js/09-classes/03-static-properties-methods/1.js @@ -0,0 +1,8 @@ + +class User { + static staticMethod() { + console.log(this === User); + } +} + +User.staticMethod(); // true diff --git a/1-js/09-classes/03-static-properties-methods/2.js b/1-js/09-classes/03-static-properties-methods/2.js new file mode 100755 index 0000000000..bbb9181623 --- /dev/null +++ b/1-js/09-classes/03-static-properties-methods/2.js @@ -0,0 +1,22 @@ + +class Article { + constructor(title, date) { + this.title = title; + this.date = date; + } + + static compare(articleA, articleB) { + return articleA.date - articleB.date; + } +} + +// 用法 +let articles = [ + new Article("HTML", new Date(2019, 1, 1)), + new Article("CSS", new Date(2019, 0, 1)), + new Article("JavaScript", new Date(2019, 11, 1)) +]; + +articles.sort(Article.compare); + +console.log( articles[0].title ); // CSS diff --git a/1-js/09-classes/03-static-properties-methods/3.js b/1-js/09-classes/03-static-properties-methods/3.js new file mode 100755 index 0000000000..275ba98c25 --- /dev/null +++ b/1-js/09-classes/03-static-properties-methods/3.js @@ -0,0 +1,20 @@ + +class Article { + constructor(title, date) { + this.title = title; + this.date = date; + } + + static createTodays() { + // 记住 this = Article + return new this("Today's digest", new Date()); + } +} + +let article = Article.createTodays(); + +// console.log( article.title ); // Today's digest +console.log( article); + +// article.createTodays(); +// TypeError: article.createTodays is not a function diff --git a/1-js/09-classes/03-static-properties-methods/4.js b/1-js/09-classes/03-static-properties-methods/4.js new file mode 100755 index 0000000000..a6bf7d9234 --- /dev/null +++ b/1-js/09-classes/03-static-properties-methods/4.js @@ -0,0 +1,37 @@ + +class Animal { + static planet = "Earth"; + + constructor(name, speed) { + this.speed = speed; + this.name = name; + } + + run(speed = 0) { + this.speed += speed; + console.log(`${this.name} runs with speed ${this.speed}.`); + } + + static compare(animalA, animalB) { + return animalA.speed - animalB.speed; + } + +} + +// 继承于 Animal +class Rabbit extends Animal { + hide() { + console.log(`${this.name} hides!`); + } +} + +let rabbits = [ + new Rabbit("White Rabbit", 10), + new Rabbit("Black Rabbit", 5) +]; + +rabbits.sort(Rabbit.compare); + +rabbits[0].run(); // Black Rabbit runs with speed 5. + +console.log(Rabbit.planet); // Earth diff --git a/1-js/09-classes/04-private-protected-properties-methods/1.js b/1-js/09-classes/04-private-protected-properties-methods/1.js new file mode 100755 index 0000000000..2fbf4a6953 --- /dev/null +++ b/1-js/09-classes/04-private-protected-properties-methods/1.js @@ -0,0 +1,35 @@ + +class CoffeeMachine { + _waterAmount = 0; + + set waterAmount(value) { + if (value < 0) { + value = 0; + } + this._waterAmount = value; + } + + get waterAmount() { + return this._waterAmount; + } + + constructor(power) { + this._power = power; + } + +} + +// 创建咖啡机 +let coffeeMachine = new CoffeeMachine(100); + +console.log(coffeeMachine); +// CoffeeMachine { _waterAmount: 0, _power: 100 } + +// 加水 +coffeeMachine.waterAmount = -10; // _waterAmount 将变为 0,而不是 -10 + + +coffeeMachine._waterAmount = 3; +// still can change +console.log(coffeeMachine); +// CoffeeMachine { _waterAmount: 3, _power: 100 } diff --git a/1-js/09-classes/04-private-protected-properties-methods/priv-test.js b/1-js/09-classes/04-private-protected-properties-methods/priv-test.js new file mode 100755 index 0000000000..ebcf3543ab --- /dev/null +++ b/1-js/09-classes/04-private-protected-properties-methods/priv-test.js @@ -0,0 +1,23 @@ + +class CoffeeMachine { + #waterLimit = 200; + + #fixWaterAmount(value) { + if (value < 0) return 0; + if (value > this.#waterLimit) return this.#waterLimit; + } + + setWaterAmount(value) { + this.#waterLimit = this.#fixWaterAmount(value); + } +} + +let coffeeMachine = new CoffeeMachine(); + +// 不能从类的外部访问类的私有属性和方法 +// coffeeMachine.#fixWaterAmount(123); // Error +// SyntaxError: Private field '#fixWaterAmount' must be declared in an enclosing class + + +// coffeeMachine.#waterLimit = 1000; // Error +// SyntaxError: Private field '#waterLimit' must be declared in an enclosing class diff --git a/1-js/09-classes/05-extend-natives/1.js b/1-js/09-classes/05-extend-natives/1.js new file mode 100755 index 0000000000..089f9c147d --- /dev/null +++ b/1-js/09-classes/05-extend-natives/1.js @@ -0,0 +1,21 @@ + +// 给 PowerArray 新增了一个方法(可以增加更多) +class PowerArray extends Array { + isEmpty() { + console.log("check len ", this.length); + return this.length === 0; + } +} + +let arr = new PowerArray(1, 2, 5, 10, 50); +console.log(arr.isEmpty()); // false + +let filteredArr = arr.filter(item => item >= 10); +console.log(filteredArr); // 10, 50 +console.log(filteredArr.isEmpty()); // false + + +let a1=[1,2,3]; +console.log(a1.length); +// console.log(a1.isEmpty()); +// TypeError: a1.isEmpty is not a function diff --git a/1-js/09-classes/06-instanceof/1.js b/1-js/09-classes/06-instanceof/1.js new file mode 100755 index 0000000000..2f3aa9f13a --- /dev/null +++ b/1-js/09-classes/06-instanceof/1.js @@ -0,0 +1,37 @@ + +let obj = {}; + +console.log(obj); // [object Object] +console.log(obj.toString()); // 同上 +/* +{} +[object Object] +*/ + +// console.log(obj.prototype); +console.log("_ ", obj.__proto__); +// _ [Object: null prototype] {} + + + +// 方便起见,将 toString 方法复制到一个变量中 +let objectToString = Object.prototype.toString; + +// 它是什么类型的? +let arr = []; + +console.log("tos ", objectToString.call(arr) ); // [object Array] + +console.log("_ ", arr.__proto__); +// _ Object(0) [] + + +console.log(objectToString.call(obj)); +// [object Object] + + +let user = { + [Symbol.toStringTag]: "User" +}; + +console.log( {}.toString.call(user) ); // [object User] diff --git a/1-js/09-classes/06-instanceof/2.js b/1-js/09-classes/06-instanceof/2.js new file mode 100755 index 0000000000..c1f3bbc91d --- /dev/null +++ b/1-js/09-classes/06-instanceof/2.js @@ -0,0 +1,7 @@ + +// 特定于环境的对象和类的 toStringTag: +// console.log( window[Symbol.toStringTag]); // Window +// console.log( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest + +console.log( {}.toString.call(window) ); // [object Window] +console.log( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest] diff --git a/1-js/09-classes/07-mixins/1.js b/1-js/09-classes/07-mixins/1.js new file mode 100755 index 0000000000..c964b96685 --- /dev/null +++ b/1-js/09-classes/07-mixins/1.js @@ -0,0 +1,23 @@ + +// mixin +let sayHiMixin = { + sayHi() { + console.log(`Hello ${this.name}`); + }, + sayBye() { + console.log(`Bye ${this.name}`); + } +}; + +// 用法: +class User { + constructor(name) { + this.name = name; + } +} + +// 拷贝方法 +Object.assign(User.prototype, sayHiMixin); + +// 现在 User 可以打招呼了 +new User("Dude").sayHi(); // Hello Dude! diff --git a/1-js/09-classes/07-mixins/2.js b/1-js/09-classes/07-mixins/2.js new file mode 100755 index 0000000000..da29d8915d --- /dev/null +++ b/1-js/09-classes/07-mixins/2.js @@ -0,0 +1,30 @@ + +let sayMixin = { + say(phrase) { + console.log("root say ", phrase); + } +}; + +let sayHiMixin = { + __proto__: sayMixin, // (或者,我们可以在这儿使用 Object.setPrototypeOf 来设置原型) + + sayHi() { + // 调用父类方法 + super.say(`Hello ${this.name}`); // (*) + }, + sayBye() { + super.say(`Bye ${this.name}`); // (*) + } +}; + +class User { + constructor(name) { + this.name = name; + } +} + +// 拷贝方法 +Object.assign(User.prototype, sayHiMixin); + +// 现在 User 可以打招呼了 +new User("Dude").sayHi(); // Hello Dude! diff --git a/1-js/09-classes/07-mixins/3.js b/1-js/09-classes/07-mixins/3.js new file mode 100755 index 0000000000..a9bb624cba --- /dev/null +++ b/1-js/09-classes/07-mixins/3.js @@ -0,0 +1,62 @@ + +let eventMixin = { + /** + * 订阅事件,用法: + * menu.on('select', function(item) { ... } + */ + on(eventName, handler) { + if (!this._eventHandlers) this._eventHandlers = {}; + if (!this._eventHandlers[eventName]) { + this._eventHandlers[eventName] = []; + } + this._eventHandlers[eventName].push(handler); + }, + + /** + * 取消订阅,用法: + * menu.off('select', handler) + */ + off(eventName, handler) { + let handlers = this._eventHandlers?.[eventName]; + if (!handlers) return; + for (let i = 0; i < handlers.length; i++) { + if (handlers[i] === handler) { + handlers.splice(i--, 1); + } + } + }, + + /** + * 生成具有给定名称和数据的事件 + * this.trigger('select', data1, data2); + */ + trigger(eventName, ...args) { + if (!this._eventHandlers?.[eventName]) { + return; // 该事件名称没有对应的事件处理程序(handler) + } + + // 调用事件处理程序(handler) + this._eventHandlers[eventName].forEach(handler => handler.apply(this, args)); + } +}; + + + + +// 创建一个 class +class Menu { + choose(value) { + this.trigger("select", value); + } +} +// 添加带有事件相关方法的 mixin +Object.assign(Menu.prototype, eventMixin); + +let menu = new Menu(); + +// 添加一个事件处理程序(handler),在被选择时被调用: +menu.on("select", value => console.log(`Value selected: ${value}`)); + +// 触发事件 => 运行上述的事件处理程序(handler)并显示: +// 被选中的值:123 +menu.choose("123"); diff --git a/1-js/10-error-handling/1-try-catch/1.js b/1-js/10-error-handling/1-try-catch/1.js new file mode 100755 index 0000000000..370785e9a1 --- /dev/null +++ b/1-js/10-error-handling/1-try-catch/1.js @@ -0,0 +1,14 @@ + +try { + + console.log('开始执行 try 中的内容'); // (1) <-- + + // ...这里没有 error + + console.log('try 中的内容执行完毕'); // (2) <-- + +} catch (err) { + + console.log('catch 被忽略,因为没有 error'); // (3) + +} diff --git a/1-js/10-error-handling/1-try-catch/2.js b/1-js/10-error-handling/1-try-catch/2.js new file mode 100755 index 0000000000..aa2a575c40 --- /dev/null +++ b/1-js/10-error-handling/1-try-catch/2.js @@ -0,0 +1,14 @@ + +try { + + console.log('开始执行 try 中的内容'); // (1) <-- + + lalala; // error,变量未定义! + + console.log('try 的末尾(未执行到此处)'); // (2) + +} catch (err) { + + console.log(`出现了 error!`, err); // (3) <-- + +} diff --git a/1-js/10-error-handling/1-try-catch/3.js b/1-js/10-error-handling/1-try-catch/3.js new file mode 100755 index 0000000000..88d59b6c4b --- /dev/null +++ b/1-js/10-error-handling/1-try-catch/3.js @@ -0,0 +1,14 @@ + +let json = "{ bad json }"; + +try { + + let user = JSON.parse(json); // <-- 当出现 error 时... + console.log( user.name ); // 不工作 + +} catch (err) { + // ...执行会跳转到这里并继续执行 + console.log( "很抱歉,数据有错误,我们会尝试再请求一次。" ); + console.log( err.name ); + console.log( err.message ); +} diff --git a/1-js/10-error-handling/1-try-catch/4.js b/1-js/10-error-handling/1-try-catch/4.js new file mode 100755 index 0000000000..9b40cf1d1e --- /dev/null +++ b/1-js/10-error-handling/1-try-catch/4.js @@ -0,0 +1,9 @@ + +try { + console.log( 'try' ); + if (confirm('Make an error?')) BAD_CODE(); +} catch (err) { + console.log( 'catch', err ); +} finally { + console.log( 'finally' ); +} diff --git a/1-js/10-error-handling/1-try-catch/5.js b/1-js/10-error-handling/1-try-catch/5.js new file mode 100755 index 0000000000..aebd32f231 --- /dev/null +++ b/1-js/10-error-handling/1-try-catch/5.js @@ -0,0 +1,14 @@ + +function func() { + + try { + return 1; + + } catch (err) { + /* ... */ + } finally { + console.log( 'finally' ); + } +} + +console.log( func() ); // 先执行 finally 中的 alert,然后执行这个 alert diff --git a/1-js/10-error-handling/2-custom-errors/1.js b/1-js/10-error-handling/2-custom-errors/1.js new file mode 100755 index 0000000000..955ac260c8 --- /dev/null +++ b/1-js/10-error-handling/2-custom-errors/1.js @@ -0,0 +1,19 @@ + +class MyError extends Error { + constructor(message) { + super(message); // (1) + this.name = "MyError"; // (2) + } +} + +function test() { + throw new MyError("Whoops!"); +} + +try { + test(); +} catch(err) { + console.log(err.message); // Whoops! + console.log(err.name); // MyError + console.log(err.stack); // 一个嵌套调用的列表,每个调用都有对应的行号 +} diff --git a/1-js/10-error-handling/2-custom-errors/2.js b/1-js/10-error-handling/2-custom-errors/2.js new file mode 100755 index 0000000000..0d98baffd0 --- /dev/null +++ b/1-js/10-error-handling/2-custom-errors/2.js @@ -0,0 +1,49 @@ + +class ValidationError extends Error { + constructor(message) { + super(message); + this.name = "ValidationError"; + } +} + +class PropertyRequiredError extends ValidationError { + constructor(property) { + super("No property: " + property); + this.name = "PropertyRequiredError"; + this.property = property; + } +} + +// 用法 +function readUser(json) { + let user = JSON.parse(json); + + if (!user.age) { + throw new PropertyRequiredError("age"); + } + if (!user.name) { + throw new PropertyRequiredError("name"); + } + + return user; +} + +console.log("blank ", new PropertyRequiredError()); +// blank PropertyRequiredError: No property: undefined + + +// try..catch 的工作示例 + +try { + let user = readUser('{ "age": 25 }'); +} catch (err) { + if (err instanceof ValidationError) { + console.log("Invalid data: " + err.message); // Invalid data: No property: name + console.log(err.name); // PropertyRequiredError + console.log(err.property); // name + } else if (err instanceof SyntaxError) { + console.log("JSON Syntax Error: " + err.message); + } else { + throw err; // 未知 error,将其再次抛出 + } +} diff --git a/1-js/10-error-handling/2-custom-errors/3.js b/1-js/10-error-handling/2-custom-errors/3.js new file mode 100755 index 0000000000..6fd892d4e4 --- /dev/null +++ b/1-js/10-error-handling/2-custom-errors/3.js @@ -0,0 +1,23 @@ + +class MyError extends Error { + constructor(message) { + super(message); + + console.log("constr ", this.constructor); + // constr [class PropertyRequiredError extends ValidationError] + + this.name = this.constructor.name; + } +} + +class ValidationError extends MyError { } + +class PropertyRequiredError extends ValidationError { + constructor(property) { + super("No property: " + property); + this.property = property; + } +} + +// name 是对的 +console.log( new PropertyRequiredError("field").name ); // PropertyRequiredError diff --git a/1-js/11-async/02-promise-basics/1.js b/1-js/11-async/02-promise-basics/1.js new file mode 100755 index 0000000000..9a5e8c29fa --- /dev/null +++ b/1-js/11-async/02-promise-basics/1.js @@ -0,0 +1,13 @@ + +let promise = new Promise(function(resolve, reject) { + setTimeout(() => resolve("done!"), 1200); + +// setTimeout(() => reject("sim err!"), 1100); + setTimeout(() => reject(new Error("sim err!")), 1100); +}); + +// resolve 运行 .then 中的第一个函数 +promise.then( + result => console.log(result), // + error => console.log(error) // +); diff --git a/1-js/11-async/02-promise-basics/err-only.js b/1-js/11-async/02-promise-basics/err-only.js new file mode 100755 index 0000000000..f9f9fed52a --- /dev/null +++ b/1-js/11-async/02-promise-basics/err-only.js @@ -0,0 +1,7 @@ + +let promise = new Promise((resolve, reject) => { + setTimeout(() => reject(new Error("Whoops!")), 1000); +}); + +// .catch(f) 与 promise.then(null, f) 一样 +promise.catch(console.log); // 1 秒后显示 "Error: Whoops!" diff --git a/1-js/11-async/02-promise-basics/finally.js b/1-js/11-async/02-promise-basics/finally.js new file mode 100755 index 0000000000..16da4eba86 --- /dev/null +++ b/1-js/11-async/02-promise-basics/finally.js @@ -0,0 +1,6 @@ + +new Promise((resolve, reject) => { + setTimeout(() => resolve("value"), 2000) +}) + .finally(() => console.log("Promise ready")) // 先触发 + .then(result => console.log(result)); // <-- .then 显示 "value" diff --git a/1-js/11-async/02-promise-basics/finally2.js b/1-js/11-async/02-promise-basics/finally2.js new file mode 100755 index 0000000000..b9bcda0df1 --- /dev/null +++ b/1-js/11-async/02-promise-basics/finally2.js @@ -0,0 +1,7 @@ + +new Promise((resolve, reject) => { + throw new Error("error"); +}) + .finally(() => console.log("Promise ready")) // 先触发 + .catch(err => console.log(err)); // <-- .catch 显示这个 error + \ No newline at end of file diff --git a/1-js/11-async/02-promise-basics/suc-only.js b/1-js/11-async/02-promise-basics/suc-only.js new file mode 100755 index 0000000000..c9da27c3fa --- /dev/null +++ b/1-js/11-async/02-promise-basics/suc-only.js @@ -0,0 +1,6 @@ + +let promise = new Promise(resolve => { + setTimeout(() => resolve("done!"), 1000); +}); + +promise.then(console.log); // 1 秒后显示 "done!" diff --git a/1-js/11-async/03-promise-chaining/chain.js b/1-js/11-async/03-promise-chaining/chain.js new file mode 100755 index 0000000000..0262310259 --- /dev/null +++ b/1-js/11-async/03-promise-chaining/chain.js @@ -0,0 +1,21 @@ + +new Promise(function(resolve, reject) { + + setTimeout(() => resolve(1), 500); // (*) + +}).then(function(result) { // (**) + + console.log(result); // 1 + return result * 2; + +}).then(function(result) { // (***) + + console.log(result); // 2 + return result * 2; + +}).then(function(result) { + + console.log(result); // 4 + return result * 2; + +}); diff --git a/1-js/11-async/03-promise-chaining/fetch-goserver.js b/1-js/11-async/03-promise-chaining/fetch-goserver.js new file mode 100755 index 0000000000..9a1d5ed261 --- /dev/null +++ b/1-js/11-async/03-promise-chaining/fetch-goserver.js @@ -0,0 +1,6 @@ + +fetch("http://localhost:8090/data", { + method: "POST", + body: "xxx" + }); + diff --git a/1-js/11-async/03-promise-chaining/fetch.js b/1-js/11-async/03-promise-chaining/fetch.js new file mode 100755 index 0000000000..e18d7928ef --- /dev/null +++ b/1-js/11-async/03-promise-chaining/fetch.js @@ -0,0 +1,12 @@ + +fetch('https://zh.javascript.info/article/promise-chaining/user.json') + // 当远程服务器响应时,下面的 .then 开始执行 + .then(function(response) { + // 当 user.json 加载完成时,response.text() 会返回一个新的 promise + // 该 promise 以加载的 user.json 为 result 进行 resolve + return response.text(); + }) + .then(function(text) { + // ……这是远程文件的内容 + console.log(text); // {"name": "iliakan", "isAdmin": true} + }); diff --git a/1-js/11-async/03-promise-chaining/fetch2.js b/1-js/11-async/03-promise-chaining/fetch2.js new file mode 100755 index 0000000000..bc0226582f --- /dev/null +++ b/1-js/11-async/03-promise-chaining/fetch2.js @@ -0,0 +1,4 @@ + +fetch('https://zh.javascript.info/article/promise-chaining/user.json') +.then(response => response.json()) +.then(user => console.log(user.name)); // iliakan,获取到了用户名 \ No newline at end of file diff --git a/1-js/11-async/03-promise-chaining/not-chain.js b/1-js/11-async/03-promise-chaining/not-chain.js new file mode 100755 index 0000000000..9b22fe4fb0 --- /dev/null +++ b/1-js/11-async/03-promise-chaining/not-chain.js @@ -0,0 +1,19 @@ + +let promise = new Promise(function(resolve, reject) { + setTimeout(() => resolve(1), 500); +}); + +promise.then(function(result) { + console.log(result); // 1 + return result * 2; +}); + +promise.then(function(result) { + console.log(result); // 1 + return result * 2; +}); + +promise.then(function(result) { + console.log(result); // 1 + return result * 2; +}); diff --git a/1-js/11-async/03-promise-chaining/prom-ret.js b/1-js/11-async/03-promise-chaining/prom-ret.js new file mode 100755 index 0000000000..f3f0023ede --- /dev/null +++ b/1-js/11-async/03-promise-chaining/prom-ret.js @@ -0,0 +1,27 @@ + +new Promise(function(resolve, reject) { + // console.log(this); + + setTimeout(() => resolve(1), 500); + +}).then(function(result) { + + console.log(result); // 1 + + return new Promise((resolve, reject) => { // (*) + setTimeout(() => resolve(result * 2), 500); + }); + +}).then(function(result) { // (**) + + console.log(result); // 2 + + return new Promise((resolve, reject) => { + setTimeout(() => resolve(result * 2), 500); + }); + +}).then(function(result) { + + console.log(result); // 4 + +}); diff --git a/1-js/11-async/03-promise-chaining/thenable.js b/1-js/11-async/03-promise-chaining/thenable.js new file mode 100755 index 0000000000..8846c757b1 --- /dev/null +++ b/1-js/11-async/03-promise-chaining/thenable.js @@ -0,0 +1,17 @@ + +class Thenable { + constructor(num) { + this.num = num; + } + then(resolve, reject) { + console.log("resolve is ", resolve); // function() { native code } + // 1 秒后使用 this.num*2 进行 resolve + setTimeout(() => resolve(this.num * 2), 1000); // (**) + } +} + +new Promise(resolve => resolve(1)) + .then(result => { + return new Thenable(result); // (*) + }) + .then(console.log); // 1000ms 后显示 2 diff --git a/1-js/11-async/04-promise-error-handling/no-catch.js b/1-js/11-async/04-promise-error-handling/no-catch.js new file mode 100755 index 0000000000..37e7618b39 --- /dev/null +++ b/1-js/11-async/04-promise-error-handling/no-catch.js @@ -0,0 +1,7 @@ + +new Promise(function() { + noSuchFunction(); // 这里出现 error(没有这个函数) + }) + .then(() => { + // 一个或多个成功的 promise 处理程序 + }); // 尾端没有 .catch! diff --git a/1-js/11-async/05-promise-api/1.js b/1-js/11-async/05-promise-api/1.js new file mode 100755 index 0000000000..767134acfb --- /dev/null +++ b/1-js/11-async/05-promise-api/1.js @@ -0,0 +1,6 @@ + +Promise.all([ + new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1 + new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2 + new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3 + ]).then(console.log); // 1,2,3 当上面这些 promise 准备好时:每个 promise 都贡献了数组中的一个元素 diff --git a/1-js/11-async/05-promise-api/2.js b/1-js/11-async/05-promise-api/2.js new file mode 100755 index 0000000000..3a80d37a7f --- /dev/null +++ b/1-js/11-async/05-promise-api/2.js @@ -0,0 +1,15 @@ + +let urls = [ + 'https://api.github.com/users/iliakan', + 'https://api.github.com/users/remy', + 'https://api.github.com/users/jeresig' + ]; + + // 将每个 url 映射(map)到 fetch 的 promise 中 + let requests = urls.map(url => fetch(url)); + + // Promise.all 等待所有任务都 resolved + Promise.all(requests) + .then(responses => responses.forEach( + response => console.log(`${response.url}: ${response.status}`) + )); diff --git a/1-js/11-async/05-promise-api/aggregate-err.js b/1-js/11-async/05-promise-api/aggregate-err.js new file mode 100755 index 0000000000..50a7f019dd --- /dev/null +++ b/1-js/11-async/05-promise-api/aggregate-err.js @@ -0,0 +1,11 @@ + +Promise.any([ + new Promise((resolve, reject) => setTimeout(() => reject(new Error("Ouch!")), 1000)), + new Promise((resolve, reject) => setTimeout(() => reject(new Error("Error!")), 2000)) + ]).catch(error => { + console.log(error.constructor.name); // AggregateError + console.log(error.errors[0]); // Error: Ouch! + console.log(error.errors[1]); // Error: Error! + }); + +// let ae = new AggregateError() ; diff --git a/1-js/11-async/05-promise-api/all-ok.js b/1-js/11-async/05-promise-api/all-ok.js new file mode 100755 index 0000000000..6bfd9e940d --- /dev/null +++ b/1-js/11-async/05-promise-api/all-ok.js @@ -0,0 +1,19 @@ + +let names = ['iliakan', 'remy', 'jeresig']; + +let requests = names.map(name => fetch(`https://api.github.com/users/${name}`)); + +Promise.all(requests) + .then(responses => { + // 所有响应都被成功 resolved + for(let response of responses) { + console.log(`${response.url}: ${response.status}`); // 对应每个 url 都显示 200 + } + + return responses; + }) + // 将响应数组映射(map)到 response.json() 数组中以读取它们的内容 + .then(responses => Promise.all(responses.map(r => r.json()))) + // 所有 JSON 结果都被解析:"users" 是它们的数组 + .then(users => users.forEach(user => console.log(user.name))); + \ No newline at end of file diff --git a/1-js/11-async/05-promise-api/all-some-err.js b/1-js/11-async/05-promise-api/all-some-err.js new file mode 100755 index 0000000000..09e744934d --- /dev/null +++ b/1-js/11-async/05-promise-api/all-some-err.js @@ -0,0 +1,27 @@ + +let names = ['iliakan', 'NO_SUCH_USER', 'jeresig']; + +let requests = names.map(name => fetch(`https://api.github.com/users/${name}`)); + +Promise.all(requests) + .then(responses => { + // 所有响应都被成功 resolved + for(let response of responses) { + console.log(`${response.url}: ${response.status}`); // 对应每个 url 都显示 200 + } + + return responses; + }) + // 将响应数组映射(map)到 response.json() 数组中以读取它们的内容 + .then(responses => Promise.all(responses.map(r => r.json()))) + // 所有 JSON 结果都被解析:"users" 是它们的数组 + .then(users => users.forEach(user => console.log(user.name))); + +/* +https://api.github.com/users/iliakan: 200 +https://api.github.com/users/NO_SUCH_USER: 404 +https://api.github.com/users/jeresig: 200 +Ilya Kantor +undefined +John Resig +*/ diff --git a/1-js/11-async/05-promise-api/all.js b/1-js/11-async/05-promise-api/all.js new file mode 100755 index 0000000000..fd7c81aca2 --- /dev/null +++ b/1-js/11-async/05-promise-api/all.js @@ -0,0 +1,10 @@ + +Promise.all([ + + new Promise((resolve, reject) => { + setTimeout(() => resolve(1), 1000) + }), + + 2, + 3 + ]).then(console.log); // 1, 2, 3 diff --git a/1-js/11-async/05-promise-api/allSettled.js b/1-js/11-async/05-promise-api/allSettled.js new file mode 100755 index 0000000000..741ada0923 --- /dev/null +++ b/1-js/11-async/05-promise-api/allSettled.js @@ -0,0 +1,22 @@ + +let urls = [ + 'https://api.github.com/users/iliakan', + 'https://api.github.com/users/remy', + 'https://no-such-url' + ]; + + Promise.allSettled(urls.map(url => fetch(url))) + .then(results => { // (*) + + results.forEach((result, num) => { + + if (result.status == "fulfilled") { + console.log(`FUL ${urls[num]}: ${result.value.status}`); + } + if (result.status == "rejected") { + console.log(`REJ ${urls[num]}: ${result.reason}`); + } + + }); + + }); diff --git a/1-js/11-async/05-promise-api/any.js b/1-js/11-async/05-promise-api/any.js new file mode 100755 index 0000000000..82b59a1ec3 --- /dev/null +++ b/1-js/11-async/05-promise-api/any.js @@ -0,0 +1,6 @@ + +Promise.any([ + new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 1000)), + new Promise((resolve, reject) => setTimeout(() => resolve(2), 2000)), + new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)) + ]).then(console.log); // 1 diff --git a/1-js/11-async/05-promise-api/msfs-map-test copy.js.txt b/1-js/11-async/05-promise-api/msfs-map-test copy.js.txt new file mode 100755 index 0000000000..f838ada722 --- /dev/null +++ b/1-js/11-async/05-promise-api/msfs-map-test copy.js.txt @@ -0,0 +1,156 @@ + + +async function translate(src){ + const url = 'https://transmart.qq.com/api/imt'; + let body= `{ + "header": { + "fn": "auto_translation_block", + "client_key": "tencent_transmart_crx_TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXQvNTM3Lj" + }, + "source": { + "lang": "en", + "text_block": "${src}" + }, + "target": { + "lang": "zh" + } + }`; + // console.log("body ", body); return; + + let resp = await fetch(url, { + method: 'POST', + body + }); + let json = await resp.json(); + // console.log("json ", json); + let trans = json.auto_translation; + console.log("trans ", trans); + return trans; + } + + + (async function () { + await translate('About'); + })(); + + + +let pages = +{ + "22109205": { + "pageid": 22109205, + "ns": 0, + "title": "IRT Powerhouse", + "index": -1, + "extract": "The IRT Powerhouse, also known as the Interborough Rapid Transit Company Powerhouse...", + "thumbnail": { + "source": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/W58th_St_IRT_power_jeh.JPG/400px-W58th_St_IRT_power_jeh.JPG", + "width": 400, + "height": 338 + }, + "pageimage": "W58th_St_IRT_power_jeh.JPG", + "coordinates": [ + { + "lat": 40.77194444, + "lon": -73.99222222, + "primary": "", + "globe": "earth" + } + ] + }, + + "37321190": { + "pageid": 37321190, + "ns": 0, + "title": "VIA 57 West", + "index": 0, + "extract": "

\n

VIA 57 West (marketed as VIΛ 57WEST) is a residential building at 625 West 57th Street...", + "thumbnail": { + "source": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/VIA_57_West_-_exterior.jpg/400px-VIA_57_West_-_exterior.jpg", + "width": 400, + "height": 335 + }, + "pageimage": "VIA_57_West_-_exterior.jpg", + "coordinates": [ + { + "lat": 40.77138889, + "lon": -73.99305556, + "primary": "", + "globe": "earth" + } + ] + } +} +; + +// console.log(pages); +// console.log(Object.keys(pages)); +// for(let k of Object.keys(pages)){ +// for(let [wid,pg] of Object.entries(pages)){ +// console.log(wid); +// console.log(pg); +// pg.title='ttt'; +// } +let procs = []; +for(let pg of Object.values(pages)){ + console.log(pg.pageid); + // console.log(pg); + + console.log("tt ", pg.title); + console.log("ex ", pg.extract); + + // procs.push(new Promise( resolve => { + + // // (async function () { + // // pg.title = await translate(pg.title); + + // // pg.extract = await translate(pg.extract); + + // // resolve(); + // // // resolve(pg.pageid); // test + // // })(); + // // await translate(pg.title); + + // // resolve(pg.pageid); // test + // })); + + // procs.push(new Promise( resolve => async function() { + // let tt = await translate(pg.title); + // console.log("tt ", tt); + // resolve(); + // })); + + procs.push(new Promise( resolve => { + // (async function () { + // let tt = await translate(pg.title); + // console.log("Tt ", tt); + // resolve(); + // }()); + + translate(pg.title) + .then(trans => console.log("TT ",trans) ) + .then(resolve) + // .then(trans => pg.title = trans) + ; + + // .then(resolve); + })); +} + +Promise.all(procs) +.then(console.log("final ")); +// .then(console.log("final ", pages)); + +// console.log(pages["37321190"]); +// console.log("final ", pages); + + +async function transAll(){ + for (let pg of Object.values(pages)) { + console.log("tt ", pg.title); + console.log("ex ", pg.extract); + await trans + } +} + +transAll(); \ No newline at end of file diff --git a/1-js/11-async/05-promise-api/msfs-map-test lint.js b/1-js/11-async/05-promise-api/msfs-map-test lint.js new file mode 100755 index 0000000000..66c17d5f3d --- /dev/null +++ b/1-js/11-async/05-promise-api/msfs-map-test lint.js @@ -0,0 +1,63 @@ + +let pages = +{ + "22109205": { + "pageid": 22109205, + "ns": 0, + "title": "IRT Powerhouse", + "index": -1, + "extract": "The IRT Powerhouse, also known as the Interborough Rapid Transit Company Powerhouse...", + "thumbnail": { + "source": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/W58th_St_IRT_power_jeh.JPG/400px-W58th_St_IRT_power_jeh.JPG", + "width": 400, + "height": 338 + }, + "pageimage": "W58th_St_IRT_power_jeh.JPG", + "coordinates": [ + { + "lat": 40.77194444, + "lon": -73.99222222, + "primary": "", + "globe": "earth" + } + ] + }, + + "37321190": { + "pageid": 37321190, + "ns": 0, + "title": "VIA 57 West", + "index": 0, + "extract": "

\n

VIA 57 West (marketed as VIΛ 57WEST) is a residential building at 625 West 57th Street...", + "thumbnail": { + "source": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/VIA_57_West_-_exterior.jpg/400px-VIA_57_West_-_exterior.jpg", + "width": 400, + "height": 335 + }, + "pageimage": "VIA_57_West_-_exterior.jpg", + "coordinates": [ + { + "lat": 40.77138889, + "lon": -73.99305556, + "primary": "", + "globe": "earth" + } + ] + } +} +; + + +let ex = pages["37321190"].extract; +console.log(ex.replace(/\n/g, '').replace(/"/g, '\\"')); + +let data = { + xxx:"yyy", + "text_block":ex, +}; +console.log(data); +let json = JSON.stringify(data); +console.log(json); + +let back = JSON.parse(json); +console.log(back); diff --git a/1-js/11-async/05-promise-api/msfs-map-test.js b/1-js/11-async/05-promise-api/msfs-map-test.js new file mode 100755 index 0000000000..438ff2c73e --- /dev/null +++ b/1-js/11-async/05-promise-api/msfs-map-test.js @@ -0,0 +1,106 @@ + + +async function translate(src){ + const url = 'https://transmart.qq.com/api/imt'; + let body= `{ + "header": { + "fn": "auto_translation_block", + "client_key": "tencent_transmart_crx_TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXQvNTM3Lj" + }, + "source": { + "lang": "en", + "text_block": "${src}" + }, + "target": { + "lang": "zh" + } + }`; + // console.log("body ", body); return; + + let resp = await fetch(url, { + method: 'POST', + body + }); + let json = await resp.json(); + // console.log("json ", json); + let trans = json.auto_translation; + console.log("trans ", trans); + return trans; + } + + + (async function () { + await translate('About'); + })(); + + + +let pages = +{ + "22109205": { + "pageid": 22109205, + "ns": 0, + "title": "IRT Powerhouse", + "index": -1, + "extract": "The IRT Powerhouse, also known as the Interborough Rapid Transit Company Powerhouse...", + "thumbnail": { + "source": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/W58th_St_IRT_power_jeh.JPG/400px-W58th_St_IRT_power_jeh.JPG", + "width": 400, + "height": 338 + }, + "pageimage": "W58th_St_IRT_power_jeh.JPG", + "coordinates": [ + { + "lat": 40.77194444, + "lon": -73.99222222, + "primary": "", + "globe": "earth" + } + ] + }, + + "37321190": { + "pageid": 37321190, + "ns": 0, + "title": "VIA 57 West", + "index": 0, + "extract": "

\n

VIA 57 West (marketed as VIΛ 57WEST) is a residential building at 625 West 57th Street...", + "thumbnail": { + "source": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/VIA_57_West_-_exterior.jpg/400px-VIA_57_West_-_exterior.jpg", + "width": 400, + "height": 335 + }, + "pageimage": "VIA_57_West_-_exterior.jpg", + "coordinates": [ + { + "lat": 40.77138889, + "lon": -73.99305556, + "primary": "", + "globe": "earth" + } + ] + } +} +; + + + +async function transAll(){ + for (let pg of Object.values(pages)) { + console.log("tt ", pg.title); + console.log("ex ", pg.extract); + + pg.title = await translate(pg.title); + pg.extract = await translate(pg.extract); + console.log("new pg ", pg); + } +} + +// transAll() +// .then(console.log("final ", pages)) +// ; + +( async function(){ + await transAll(); + console.log("final ", pages); +})(); diff --git a/1-js/11-async/05-promise-api/race.js b/1-js/11-async/05-promise-api/race.js new file mode 100755 index 0000000000..d38dfa8ea1 --- /dev/null +++ b/1-js/11-async/05-promise-api/race.js @@ -0,0 +1,8 @@ + +Promise.race([ + new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)), + new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)), + new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)) + ]).then(console.log); // 1 + + // but still wait for all to finsh diff --git a/1-js/11-async/05-promise-api/reject.js b/1-js/11-async/05-promise-api/reject.js new file mode 100755 index 0000000000..64a8626626 --- /dev/null +++ b/1-js/11-async/05-promise-api/reject.js @@ -0,0 +1,6 @@ + +Promise.all([ + new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)), + new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)), + new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)) + ]).catch(console.log); // Error: Whoops! diff --git a/1-js/11-async/05-promise-api/resolved.js b/1-js/11-async/05-promise-api/resolved.js new file mode 100755 index 0000000000..8664dd8558 --- /dev/null +++ b/1-js/11-async/05-promise-api/resolved.js @@ -0,0 +1,32 @@ + +let cache = new Map(); + +function loadCached(url) { + console.log('cached', cache.size); + + if (cache.has(url)) { + console.log("using cache for ", url); + return Promise.resolve(cache.get(url)); // (*) + } + + console.log("fetch ", url); + return fetch(url) + .then(response => response.text()) + .then(text => { + cache.set(url,text); + return text; + }); +} + +loadCached("https://baidu.com") +.then( ()=> loadCached("https://ir.baidu.com")) +.then( ()=> loadCached("https://baidu.com")) +.then( ()=> {console.log("done");} ); + + +/* + must write: + .then( ()=> loadCached("https://ir.baidu.com")) + instead of + .then(loadCached("https://ir.baidu.com")) +*/ diff --git a/1-js/11-async/07-microtask-queue/aync.js b/1-js/11-async/07-microtask-queue/aync.js new file mode 100755 index 0000000000..ba4ef7b4c5 --- /dev/null +++ b/1-js/11-async/07-microtask-queue/aync.js @@ -0,0 +1,6 @@ + +let promise = Promise.resolve(); + +promise.then(() => console.log("promise done!")); + +console.log("code finished"); // 这个 alert 先显示 diff --git a/1-js/11-async/07-microtask-queue/queued.js b/1-js/11-async/07-microtask-queue/queued.js new file mode 100755 index 0000000000..81fb83a6b7 --- /dev/null +++ b/1-js/11-async/07-microtask-queue/queued.js @@ -0,0 +1,4 @@ + +Promise.resolve() + .then(() => console.log("promise done!")) + .then(() => console.log("code finished")); diff --git a/1-js/11-async/08-async-await/async.js b/1-js/11-async/08-async-await/async.js new file mode 100755 index 0000000000..dbd916298d --- /dev/null +++ b/1-js/11-async/08-async-await/async.js @@ -0,0 +1,14 @@ + +function f0() { + return 1; + } + +async function f() { + return 1; + } + +f0(); +// console.log(f0.prototype); +// console.log(f0.__proto__); + +f().then(console.log); // 1 diff --git a/1-js/11-async/08-async-await/await.js b/1-js/11-async/08-async-await/await.js new file mode 100755 index 0000000000..04212d0714 --- /dev/null +++ b/1-js/11-async/08-async-await/await.js @@ -0,0 +1,13 @@ + +async function f() { + + let promise = new Promise((resolve, reject) => { + setTimeout(() => resolve("done!"), 1000) + }); + + let result = await promise; // 等待,直到 promise resolve (*) + + console.log(result); // "done!" + } + +f(); diff --git a/1-js/11-async/08-async-await/catch.js b/1-js/11-async/08-async-await/catch.js new file mode 100755 index 0000000000..c2fcc5df1d --- /dev/null +++ b/1-js/11-async/08-async-await/catch.js @@ -0,0 +1,11 @@ + +async function f() { + + try { + let response = await fetch('http://no-such-url'); + } catch(err) { + console.log(err); // TypeError: failed to fetch + } + } + + f(); \ No newline at end of file diff --git a/1-js/11-async/08-async-await/catch2.js b/1-js/11-async/08-async-await/catch2.js new file mode 100755 index 0000000000..ebbc8af1b6 --- /dev/null +++ b/1-js/11-async/08-async-await/catch2.js @@ -0,0 +1,13 @@ + +async function f() { + + try { + let response = await fetch('/no-user-here'); + let user = await response.json(); + } catch(err) { + // 捕获到 fetch 和 response.json 中的错误 + console.log(err); + } + } + + f(); \ No newline at end of file diff --git a/1-js/11-async/08-async-await/catch3.js b/1-js/11-async/08-async-await/catch3.js new file mode 100755 index 0000000000..550e5b8d29 --- /dev/null +++ b/1-js/11-async/08-async-await/catch3.js @@ -0,0 +1,7 @@ + +async function f() { + let response = await fetch('http://no-such-url'); + } + + // f() 变成了一个 rejected 的 promise + f().catch(console.log); // TypeError: failed to fetch // (*) diff --git a/1-js/11-async/08-async-await/class.js b/1-js/11-async/08-async-await/class.js new file mode 100755 index 0000000000..c56fa156ee --- /dev/null +++ b/1-js/11-async/08-async-await/class.js @@ -0,0 +1,10 @@ + +class Waiter { + async wait() { + return await Promise.resolve(1); + } + } + + new Waiter() + .wait() + .then(console.log); // 1(alert 等同于 result => alert(result)) diff --git a/1-js/11-async/08-async-await/thenable.js b/1-js/11-async/08-async-await/thenable.js new file mode 100755 index 0000000000..3ea808209e --- /dev/null +++ b/1-js/11-async/08-async-await/thenable.js @@ -0,0 +1,19 @@ + +class Thenable { + constructor(num) { + this.num = num; + } + then(resolve, reject) { + console.log(resolve); + // 1000ms 后使用 this.num*2 进行 resolve + setTimeout(() => resolve(this.num * 2), 1000); // (*) + } + } + + async function f() { + // 等待 1 秒,之后 result 变为 2 + let result = await new Thenable(1); + console.log(result); + } + + f(); diff --git a/1-js/12-generators-iterators/1-generators/1.js b/1-js/12-generators-iterators/1-generators/1.js new file mode 100755 index 0000000000..aff5d9294e --- /dev/null +++ b/1-js/12-generators-iterators/1-generators/1.js @@ -0,0 +1,36 @@ + +function* generateSequence() { + yield 1; + yield 2; + return 3; + } + + let generator = generateSequence(); + + let res; + res = generator.next(); + console.log(JSON.stringify(res)); // {value: 1, done: false} + + res = generator.next(); + console.log(JSON.stringify(res)); + + res = generator.next(); + console.log(JSON.stringify(res)); + +/* +{"value":1,"done":false} +{"value":2,"done":false} +{"value":3,"done":true} +*/ + + res = generator.next(); + console.log(JSON.stringify(res)); + /* + {"done":true} +*/ + + res = generator.next(); + console.log(JSON.stringify(res)); + /* + {"done":true} +*/ diff --git a/1-js/12-generators-iterators/1-generators/2.js b/1-js/12-generators-iterators/1-generators/2.js new file mode 100755 index 0000000000..9e83a82637 --- /dev/null +++ b/1-js/12-generators-iterators/1-generators/2.js @@ -0,0 +1,12 @@ + +function* generateSequence() { + yield 1; + yield 2; + yield 3; + } + + let generator = generateSequence(); + + for(let value of generator) { + console.log(value); // 1,然后是 2,然后是 3 + } \ No newline at end of file diff --git a/1-js/12-generators-iterators/1-generators/3.js b/1-js/12-generators-iterators/1-generators/3.js new file mode 100755 index 0000000000..c7c740e458 --- /dev/null +++ b/1-js/12-generators-iterators/1-generators/3.js @@ -0,0 +1,28 @@ + +let range = { + from: 1, + to: 5, + + // for..of range 在一开始就调用一次这个方法 + [Symbol.iterator]() { + // ...它返回 iterator object: + // 后续的操作中,for..of 将只针对这个对象,并使用 next() 向它请求下一个值 + return { + current: this.from, + last: this.to, + + // for..of 循环在每次迭代时都会调用 next() + next() { + // 它应该以对象 {done:.., value :...} 的形式返回值 + if (this.current <= this.last) { + return { done: false, value: this.current++ }; + } else { + return { done: true }; + } + } + }; + } + }; + + // 迭代整个 range 对象,返回从 `range.from` 到 `range.to` 范围的所有数字 + console.log([...range]); // 1,2,3,4,5 \ No newline at end of file diff --git a/1-js/12-generators-iterators/1-generators/4.js b/1-js/12-generators-iterators/1-generators/4.js new file mode 100755 index 0000000000..fa9ede0bb4 --- /dev/null +++ b/1-js/12-generators-iterators/1-generators/4.js @@ -0,0 +1,13 @@ + +let range = { + from: 1, + to: 5, + + *[Symbol.iterator]() { // [Symbol.iterator]: function*() 的简写形式 + for(let value = this.from; value <= this.to; value++) { + yield value; + } + } + }; + + console.log( [...range] ); // 1,2,3,4,5 \ No newline at end of file diff --git a/1-js/12-generators-iterators/1-generators/5.js b/1-js/12-generators-iterators/1-generators/5.js new file mode 100755 index 0000000000..9b16f1fb65 --- /dev/null +++ b/1-js/12-generators-iterators/1-generators/5.js @@ -0,0 +1,25 @@ + +function* generateSequence(start, end) { + for (let i = start; i <= end; i++) yield i; + } + + function* generatePasswordCodes() { + + // 0..9 + yield* generateSequence(48, 57); + + // A..Z + yield* generateSequence(65, 90); + + // a..z + yield* generateSequence(97, 122); + + } + + let str = ''; + + for(let code of generatePasswordCodes()) { + str += String.fromCharCode(code); + } + + console.log(str); // 0..9A..Za..z diff --git a/1-js/12-generators-iterators/1-generators/6.js b/1-js/12-generators-iterators/1-generators/6.js new file mode 100755 index 0000000000..2dd14fb1b2 --- /dev/null +++ b/1-js/12-generators-iterators/1-generators/6.js @@ -0,0 +1,14 @@ + +function* gen() { + // 向外部代码传递一个问题并等待答案 + let result = yield "2 + 2 = ?"; // (*) + + console.log("G ", result); + } + + let generator = gen(); + + let question = generator.next().value; // <-- yield 返回的 value + console.log(question); + + generator.next(4); // --> 将结果传递到 generator 中 \ No newline at end of file diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/1.js b/1-js/12-generators-iterators/2-async-iterators-generators/1.js new file mode 100755 index 0000000000..3a9d98eff1 --- /dev/null +++ b/1-js/12-generators-iterators/2-async-iterators-generators/1.js @@ -0,0 +1,32 @@ + +let range = { + from: 1, + to: 5, + + [Symbol.asyncIterator]() { // (1) + return { + current: this.from, + last: this.to, + + async next() { // (2) + + // 注意:我们可以在 async next 内部使用 "await" + await new Promise(resolve => setTimeout(resolve, 1000)); // (3) + + if (this.current <= this.last) { + return { done: false, value: this.current++ }; + } else { + return { done: true }; + } + } + }; + } + }; + + (async () => { + + for await (let value of range) { // (4) + console.log(value); // 1,2,3,4,5 + } + + })() \ No newline at end of file diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/2.js b/1-js/12-generators-iterators/2-async-iterators-generators/2.js new file mode 100755 index 0000000000..287820d85a --- /dev/null +++ b/1-js/12-generators-iterators/2-async-iterators-generators/2.js @@ -0,0 +1,21 @@ + +async function* generateSequence(start, end) { + + for (let i = start; i <= end; i++) { + + // 哇,可以使用 await 了! + await new Promise(resolve => setTimeout(resolve, 1000)); + + yield i; + } + + } + + (async () => { + + let generator = generateSequence(1, 5); + for await (let value of generator) { + console.log(value); // 1,然后 2,然后 3,然后 4,然后 5(在每个 console.log 之间有延迟) + } + + })(); \ No newline at end of file diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/fetch-commits.js b/1-js/12-generators-iterators/2-async-iterators-generators/fetch-commits.js new file mode 100755 index 0000000000..2938f5ddff --- /dev/null +++ b/1-js/12-generators-iterators/2-async-iterators-generators/fetch-commits.js @@ -0,0 +1,39 @@ + +async function* fetchCommits(repo) { + let url = `https://api.github.com/repos/${repo}/commits`; + + while (url) { + const response = await fetch(url, { // (1) + headers: {'User-Agent': 'Our script'}, // github 需要任意的 user-agent header + }); + + const body = await response.json(); // (2) 响应的是 JSON(array of commits) + + // (3) 前往下一页的 URL 在 header 中,提取它 + let nextPage = response.headers.get('Link').match(/<(.*?)>; rel="next"/); + nextPage = nextPage?.[1]; + + url = nextPage; + + for(let commit of body) { // (4) 一个接一个地 yield commit,直到最后一页 + yield commit; + } + } + } + +(async () => { + + let count = 0; + + for await (const commit of fetchCommits('javascript-tutorial/en.javascript.info')) { + + console.log(commit.author.login); + + if (++count == 10) { // 让我们在获取了 x 个 commit 时停止 + break; + } + } + + })(); + + // 注意:如果你在外部沙箱中运行它,你需要把上面的 fetchCommits 函数粘贴到这儿。 \ No newline at end of file diff --git a/1-js/13-modules/01-modules-intro/main.js b/1-js/13-modules/01-modules-intro/main.js new file mode 100755 index 0000000000..f60cf8bd40 --- /dev/null +++ b/1-js/13-modules/01-modules-intro/main.js @@ -0,0 +1,7 @@ +// module main; + +// 📁 main.js +import { sayHi } from './sayHi.js'; + +console.log(sayHi); // function... +sayHi('John'); // Hello, John! \ No newline at end of file diff --git a/1-js/13-modules/01-modules-intro/sayHi.js b/1-js/13-modules/01-modules-intro/sayHi.js new file mode 100755 index 0000000000..92559db027 --- /dev/null +++ b/1-js/13-modules/01-modules-intro/sayHi.js @@ -0,0 +1,5 @@ + +// 📁 sayHi.js +export function sayHi(user) { + console.log(`Hello, ${user}!`); + } \ No newline at end of file diff --git a/1-js/99-js-misc/01-proxy/1.js b/1-js/99-js-misc/01-proxy/1.js new file mode 100755 index 0000000000..70cc1b210a --- /dev/null +++ b/1-js/99-js-misc/01-proxy/1.js @@ -0,0 +1,19 @@ + +let target = {}; + +let proxy = new Proxy(target, {}); // 空的 handler 对象 + +console.log(proxy); + +console.log(proxy.__proto__); +// [Object: null prototype] {} + + +proxy.test = 5; // 写入 proxy 对象 (1) +console.log(target.test); // 5,test 属性出现在了 target 中! +console.log(target); + +console.log(proxy.test); // 5,我们也可以从 proxy 对象读取它 (2) +console.log(proxy); + +for(let key in proxy) console.log(key); // test,迭代也正常工作 (3) diff --git a/1-js/99-js-misc/01-proxy/2.js b/1-js/99-js-misc/01-proxy/2.js new file mode 100755 index 0000000000..7a2914af82 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/2.js @@ -0,0 +1,15 @@ + +let numbers = [0, 1, 2]; + +numbers = new Proxy(numbers, { + get(target, prop) { + if (prop in target) { + return target[prop]; + } else { + return 0; // 默认值 + } + } +}); + +console.log( numbers[1] ); // 1 +console.log( numbers[123] ); // 0(没有这个数组项) diff --git a/1-js/99-js-misc/01-proxy/3.js b/1-js/99-js-misc/01-proxy/3.js new file mode 100755 index 0000000000..ae5da0c6ae --- /dev/null +++ b/1-js/99-js-misc/01-proxy/3.js @@ -0,0 +1,21 @@ + +let dictionary = { + 'Hello': 'Hola', + 'Bye': 'Adiós' + }; + + dictionary = new Proxy(dictionary, { + get(target, phrase) { // 拦截读取属性操作 + if (phrase in target) { //如果词典中有该短语 + return target[phrase]; // 返回其翻译 + } else { + // 否则返回未翻译的短语 + return phrase; + } + } + }); + + // 在词典中查找任意短语! + // 最坏的情况也只是它们没有被翻译。 + console.log( dictionary['Hello'] ); // Hola + console.log( dictionary['Welcome to Proxy']); // Welcome to Proxy(没有被翻译) diff --git a/1-js/99-js-misc/01-proxy/4.js b/1-js/99-js-misc/01-proxy/4.js new file mode 100755 index 0000000000..02e684145d --- /dev/null +++ b/1-js/99-js-misc/01-proxy/4.js @@ -0,0 +1,21 @@ + +let numbers = []; + +numbers = new Proxy(numbers, { // (*) + set(target, prop, val) { // 拦截写入属性操作 + if (typeof val == 'number') { + target[prop] = val; + return true; + } else { + return false; + } + } +}); + +numbers.push(1); // 添加成功 +numbers.push(2); // 添加成功 +console.log("Length is: " + numbers.length); // 2 + +numbers.push("test"); // TypeError(proxy 的 'set' 返回 false) + +console.log("This line is never reached (error in the line above)"); \ No newline at end of file diff --git a/1-js/99-js-misc/01-proxy/5.js b/1-js/99-js-misc/01-proxy/5.js new file mode 100755 index 0000000000..a2a2633bfc --- /dev/null +++ b/1-js/99-js-misc/01-proxy/5.js @@ -0,0 +1,25 @@ + +let user = { + name: "John", + age: 30, + _password: "myPassword" + }; + + user = new Proxy(user, { + ownKeys(target) { + return Object.keys(target).filter(key => !key.startsWith('_')); + } + }); + + // "ownKeys" 过滤掉了 _password + for(let key in user) console.log(key); // name,然后是 age + + // 对这些方法的效果相同: + console.log( Object.keys(user) ); // name,age + console.log( Object.values(user) ); // John,30 + + console.log(user); + // { name: 'John', age: 30, _password: 'myPassword' } + + console.log(user._password); + // shows too diff --git a/1-js/99-js-misc/01-proxy/6.js b/1-js/99-js-misc/01-proxy/6.js new file mode 100755 index 0000000000..d4cc975487 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/6.js @@ -0,0 +1,28 @@ + +let user = { }; + +user = new Proxy(user, { + ownKeys(target) { // 一旦要获取属性列表就会被调用 + return ['a', 'b', 'c']; + }, + + getOwnPropertyDescriptor(target, prop) { // 被每个属性调用 + return { + enumerable: true, + configurable: true, + + writable: true, + /* ...其他标志,可能是 "value:..." */ + }; + } + +}); + +console.log( Object.keys(user) ); // a, b, c + +console.log(user); +// {} + +user.a=1; +console.log(user); +// {} !! diff --git a/1-js/99-js-misc/01-proxy/7.js b/1-js/99-js-misc/01-proxy/7.js new file mode 100755 index 0000000000..8f859f5240 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/7.js @@ -0,0 +1,77 @@ + +let user = { + name: "John", + _password: "xxx", + + checkIt(val){ + console.log("check ", val === this._password); + } + + }; + + user = new Proxy(user, { + + get(target, prop) { + if (prop.startsWith('_')) { + throw new Error("Access denied"); + } + let value = target[prop]; + + // return value; + return (typeof value === 'function') ? value.bind(target) : value; // (*) + // required for own funcs to access _xxx vars + // yet still, not best solution. + + }, + + set(target, prop, val) { // 拦截属性写入 + if (prop.startsWith('_')) { + throw new Error("Access denied"); + } else { + target[prop] = val; + return true; + } + }, + + deleteProperty(target, prop) { // 拦截属性删除 + if (prop.startsWith('_')) { + throw new Error("Access denied"); + } else { + delete target[prop]; + return true; + } + }, + + ownKeys(target) { // 拦截读取属性列表 + return Object.keys(target).filter(key => !key.startsWith('_')); + } + + }); + + + + console.log(user); +//{ name: 'John', _password: 'xxx' } + + + // "get" 不允许读取 _password + try { + console.log(user._password); // Error: Access denied + } catch(e) { console.log(e.message); } + + // "set" 不允许写入 _password + try { + user._password = "test"; // Error: Access denied + } catch(e) { console.log(e.message); } + + // "deleteProperty" 不允许删除 _password + try { + delete user._password; // Error: Access denied + } catch(e) { console.log(e.message); } + + // "ownKeys" 将 _password 过滤出去 + for(let key in user) console.log(key); // name + + + user.checkIt("123"); + user.checkIt("xxx"); diff --git a/1-js/99-js-misc/01-proxy/8.js b/1-js/99-js-misc/01-proxy/8.js new file mode 100755 index 0000000000..b94945b721 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/8.js @@ -0,0 +1,14 @@ + +let range = { + start: 1, + end: 10 + }; + + range = new Proxy(range, { + has(target, prop) { + return prop >= target.start && prop <= target.end; + } + }); + + console.log(5 in range); // true + console.log(50 in range); // false diff --git a/1-js/99-js-misc/01-proxy/9.js b/1-js/99-js-misc/01-proxy/9.js new file mode 100755 index 0000000000..b118954c54 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/9.js @@ -0,0 +1,23 @@ + +function delay(f, ms) { + return new Proxy(f, + { + apply(target, thisArg, args) { + setTimeout(() => target.apply(thisArg, args), ms); + } + } + ); + } + + function sayHi(user) { + console.log(`Hello, ${user}!`); + } + + console.log(sayHi.length); + // 1 + + sayHi = delay(sayHi, 1000); + + console.log(sayHi.length); // 1 (*) proxy 将“获取 length”的操作转发给目标对象 + + sayHi("John"); // Hello, John!(3 秒后) diff --git a/1-js/99-js-misc/01-proxy/a.js b/1-js/99-js-misc/01-proxy/a.js new file mode 100755 index 0000000000..7ba8ba4324 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/a.js @@ -0,0 +1,9 @@ + +let user = {}; + +Reflect.set(user, 'name', 'John'); + +console.log(user.name); // John + +console.log(user); +// { name: 'John' } diff --git a/1-js/99-js-misc/01-proxy/b.js b/1-js/99-js-misc/01-proxy/b.js new file mode 100755 index 0000000000..7b5368803a --- /dev/null +++ b/1-js/99-js-misc/01-proxy/b.js @@ -0,0 +1,19 @@ + +let user = { + name: "John", + }; + + user = new Proxy(user, { + get(target, prop, receiver) { + console.log(`GET ${prop}`); + return Reflect.get(target, prop, receiver); // (1) + }, + set(target, prop, val, receiver) { + console.log(`SET ${prop}=${val}`); + return Reflect.set(target, prop, val, receiver); // (2) + } + }); + + let name = user.name; // 显示 "GET name" + user.name = "Pete"; // 显示 "SET name=Pete" + \ No newline at end of file diff --git a/1-js/99-js-misc/01-proxy/c1.js b/1-js/99-js-misc/01-proxy/c1.js new file mode 100755 index 0000000000..dd172b2611 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/c1.js @@ -0,0 +1,31 @@ + +let user = { + _name: "Guest", + get name() { + return this._name; + } + }; + + let userProxy = new Proxy(user, { + get(target, prop, receiver) { + + // console.log("t ", target.__proto__, " rcv ", receiver.__proto__); + // console.log("t ", target.prototype, " rcv ", receiver.__proto__); + // console.log(target); // this one ok + // console.log(receiver.prototype); + //RangeError: Maximum call stack size exceeded + + // return receiver[prop]; + // RangeError: Maximum call stack size exceeded + + return target[prop]; // (*) target = user + } + }); + + let admin = { + __proto__: userProxy, + _name: "Admin" + }; + + // 期望输出:Admin + console.log(admin.name); // 输出:Guest (?!?) \ No newline at end of file diff --git a/1-js/99-js-misc/01-proxy/c2.js b/1-js/99-js-misc/01-proxy/c2.js new file mode 100755 index 0000000000..5560c7c450 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/c2.js @@ -0,0 +1,21 @@ + +let user = { + _name: "Guest", + get name() { + return this._name; + } + }; + + let userProxy = new Proxy(user, { + get(target, prop, receiver) { // receiver = admin + return Reflect.get(target, prop, receiver); // (*) + } + }); + + + let admin = { + __proto__: userProxy, + _name: "Admin" + }; + + console.log(admin.name); // Admin diff --git a/1-js/99-js-misc/01-proxy/prv1.js b/1-js/99-js-misc/01-proxy/prv1.js new file mode 100755 index 0000000000..6f9e2f6740 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/prv1.js @@ -0,0 +1,20 @@ + +class User { + #name = "Guest"; + + getName() { + return this.#name; + } + } + + let user = new User(); + +// console.log(user.#name); +console.log(user.getName()); +// Guest + + + user = new Proxy(user, {}); + + console.log(user.getName()); // Error + // TypeError: Cannot read private member #name from an object whose class did not declare it diff --git a/1-js/99-js-misc/01-proxy/prv2.js b/1-js/99-js-misc/01-proxy/prv2.js new file mode 100755 index 0000000000..6d236d0da3 --- /dev/null +++ b/1-js/99-js-misc/01-proxy/prv2.js @@ -0,0 +1,20 @@ + +class User { + #name = "Guest"; + + getName() { + return this.#name; + } + } + + let user = new User(); + + user = new Proxy(user, { + get(target, prop, receiver) { + let value = Reflect.get(...arguments); + return typeof value == 'function' ? value.bind(target) : value; + } + }); + + console.log(user.getName()); // Guest + \ No newline at end of file diff --git a/1-js/99-js-misc/01-proxy/revoke.js b/1-js/99-js-misc/01-proxy/revoke.js new file mode 100755 index 0000000000..8aa2d9633a --- /dev/null +++ b/1-js/99-js-misc/01-proxy/revoke.js @@ -0,0 +1,18 @@ + +let object = { + data: "Valuable data" + }; + + let {proxy, revoke} = Proxy.revocable(object, {}); + + // 将 proxy 传递到其他某处,而不是对象... + console.log(proxy.data); // Valuable data + + console.log("orig ", object); + + // 稍后,在我们的代码中 + revoke(); + + // proxy 不再工作(revoked) + console.log(proxy.data); // Error +// TypeError: Cannot perform 'get' on a proxy that has been revoked diff --git a/1-js/99-js-misc/02-eval/1.js b/1-js/99-js-misc/02-eval/1.js new file mode 100755 index 0000000000..eab23e5354 --- /dev/null +++ b/1-js/99-js-misc/02-eval/1.js @@ -0,0 +1,4 @@ + +let f = new Function('a', 'console.log(a)'); + +f(5); // 5 diff --git a/2-ui/1-document/07-modifying-document/1.html b/2-ui/1-document/07-modifying-document/1.html new file mode 100755 index 0000000000..fa0bfbb2cc --- /dev/null +++ b/2-ui/1-document/07-modifying-document/1.html @@ -0,0 +1,21 @@ + +

DDD
+ + + + + + diff --git a/2-ui/1-document/08-styles-and-classes/1.html b/2-ui/1-document/08-styles-and-classes/1.html new file mode 100755 index 0000000000..4ebfa3d2a8 --- /dev/null +++ b/2-ui/1-document/08-styles-and-classes/1.html @@ -0,0 +1,16 @@ + + + + diff --git a/2-ui/2-events/01-introduction-browser-events/1.html b/2-ui/2-events/01-introduction-browser-events/1.html new file mode 100755 index 0000000000..14e9ef8949 --- /dev/null +++ b/2-ui/2-events/01-introduction-browser-events/1.html @@ -0,0 +1,3 @@ + + + diff --git a/2-ui/2-events/01-introduction-browser-events/2.html b/2-ui/2-events/01-introduction-browser-events/2.html new file mode 100755 index 0000000000..af63180e31 --- /dev/null +++ b/2-ui/2-events/01-introduction-browser-events/2.html @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/2-ui/2-events/01-introduction-browser-events/3.html b/2-ui/2-events/01-introduction-browser-events/3.html new file mode 100755 index 0000000000..61f0023e54 --- /dev/null +++ b/2-ui/2-events/01-introduction-browser-events/3.html @@ -0,0 +1,3 @@ + + + diff --git a/2-ui/2-events/02-bubbling-and-capturing/both.view/script.js b/2-ui/2-events/02-bubbling-and-capturing/both.view/script.js old mode 100644 new mode 100755 index c3475f5cbb..79195638d7 --- a/2-ui/2-events/02-bubbling-and-capturing/both.view/script.js +++ b/2-ui/2-events/02-bubbling-and-capturing/both.view/script.js @@ -7,6 +7,6 @@ for (let i = 0; i < elems.length; i++) { function highlightThis() { this.style.backgroundColor = 'yellow'; - alert(this.tagName); + console.log(this.tagName); this.style.backgroundColor = ''; } \ No newline at end of file diff --git a/2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/script.js b/2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/script.js old mode 100644 new mode 100755 index b1353712fa..24f586d594 --- a/2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/script.js +++ b/2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/script.js @@ -4,7 +4,7 @@ form.onclick = function(event) { // chrome needs some time to paint yellow setTimeout(() => { - alert("target = " + event.target.tagName + ", this=" + this.tagName); + console.log("target = " + event.target.tagName + ", this=" + this.tagName); event.target.style.backgroundColor = '' }, 0); }; diff --git a/2-ui/2-events/02-bubbling-and-capturing/capture.view/script.js b/2-ui/2-events/02-bubbling-and-capturing/capture.view/script.js old mode 100644 new mode 100755 index d67a496ad7..a82d2b8796 --- a/2-ui/2-events/02-bubbling-and-capturing/capture.view/script.js +++ b/2-ui/2-events/02-bubbling-and-capturing/capture.view/script.js @@ -6,6 +6,6 @@ for (let i = 0; i < elems.length; i++) { function highlightThis() { this.style.backgroundColor = 'yellow'; - alert(this.tagName); + console.log(this.tagName); this.style.backgroundColor = ''; } \ No newline at end of file diff --git a/2-ui/2-events/03-event-delegation/article.md b/2-ui/2-events/03-event-delegation/article.md index 5c015c8884..5f2e53c189 100644 --- a/2-ui/2-events/03-event-delegation/article.md +++ b/2-ui/2-events/03-event-delegation/article.md @@ -199,7 +199,7 @@ One more counter: ``` -如果我们点击按钮 —— 它的值就会增加。但不仅仅是按钮,一般的方法在这里也很重要。 +如果我们点击按钮 —— 它的值就会增加。这里重要的不是按钮,而是这种通用方法。 我们可以根据需要使用 `data-counter` 特性,多少都可以。我们可以随时向 HTML 添加新的特性。使用事件委托,我们属于对 HTML 进行了“扩展”,添加了描述新行为的特性。 diff --git a/2-ui/2-events/03-event-delegation/counter.html b/2-ui/2-events/03-event-delegation/counter.html new file mode 100755 index 0000000000..ae37b6b884 --- /dev/null +++ b/2-ui/2-events/03-event-delegation/counter.html @@ -0,0 +1,15 @@ + +Counter: +One more counter: + + diff --git a/2-ui/2-events/03-event-delegation/menu.html b/2-ui/2-events/03-event-delegation/menu.html new file mode 100755 index 0000000000..875b8c4256 --- /dev/null +++ b/2-ui/2-events/03-event-delegation/menu.html @@ -0,0 +1,39 @@ + + + + diff --git a/2-ui/4-forms-controls/2-focus-blur/article.md b/2-ui/4-forms-controls/2-focus-blur/article.md index ac3a48062b..fdd5675a41 100644 --- a/2-ui/4-forms-controls/2-focus-blur/article.md +++ b/2-ui/4-forms-controls/2-focus-blur/article.md @@ -90,7 +90,7 @@ Your email please: 请注意,我们无法通过在 `onblur` 事件处理程序中调用 `event.preventDefault()` 来“阻止失去焦点”,因为 `onblur` 事件处理程序是在元素失去焦点 **之后** 运行的。 -但在实际中,在实现这样的功能之前应该认真考虑一下,因为我们通常 **应该将报错展示给用户**,但 **不应该阻止用户在填写我们的表单时的进度**。用户可能会想先填写其他表单项。 +但在实际中,在实现这样的功能之前应该认真考虑一下,因为我们通常 **应该将报错展示给用户**,但 **不应该阻止用户填写表单的进程**。用户可能会想先填写其他表单项。 ```warn header="JavaScript 导致的焦点丢失" 很多种原因可以导致焦点丢失。 diff --git a/2-ui/4-forms-controls/3-events-change-input/article.md b/2-ui/4-forms-controls/3-events-change-input/article.md index 42c0518d26..5c3ece09a1 100644 --- a/2-ui/4-forms-controls/3-events-change-input/article.md +++ b/2-ui/4-forms-controls/3-events-change-input/article.md @@ -95,7 +95,7 @@ 因此,大多数浏览器仅允许在某些用户操作范围内(例如复制/粘贴等)对剪切板进行无缝的读/写访问。 -除火狐(Firefox)浏览器外,所有浏览器都禁止使用 `dispatchEvent` 生成“自定义”剪贴板事件,即使我们设法调度此类事件。规范也明确声明了,合成(syntetic)事件不得提供对剪切板的访问权限。 +除火狐(Firefox)浏览器外,所有浏览器都禁止使用 `dispatchEvent` 生成“自定义”剪贴板事件,即使我们设法调度此类事件。规范也明确声明了,合成(synthetic)事件不得提供对剪切板的访问权限。 此外,如果有人想将 `event.clipboardData` 保存在事件处理程序中,然后稍后再访问它 —— 这也不会生效。 diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md index 7e74ce690f..c4d77ced3f 100644 --- a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md +++ b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md @@ -101,7 +101,7 @@ document.addEventListener("DOMContentLoaded", ready); Firefox,Chrome 和 Opera 都会在 `DOMContentLoaded` 中自动填充表单。 -例如,如果页面有一个带有登录名和密码的表单,并且浏览器记住了这些值,那么在 `DOMContentLoaded` 上,浏览器会尝试自动填充它们(如果得到了用户允许)。 +例如,如果页面有一个带有登录名和密码的表单,并且浏览器记住了这些值,那么当 `DOMContentLoaded` 时,浏览器会尝试自动填充它们(如果得到了用户允许)。 因此,如果 `DOMContentLoaded` 被需要加载很长时间的脚本延迟触发,那么自动填充也会等待。你可能在某些网站上看到过(如果你使用浏览器自动填充)—— 登录名/密码字段不会立即自动填充,而是在页面被完全加载前会延迟填充。这实际上是 `DOMContentLoaded` 事件之前的延迟。 diff --git a/4-binary/01-arraybuffer-binary-arrays/1.js b/4-binary/01-arraybuffer-binary-arrays/1.js new file mode 100755 index 0000000000..b26902a5a7 --- /dev/null +++ b/4-binary/01-arraybuffer-binary-arrays/1.js @@ -0,0 +1,20 @@ + +let buffer = new ArrayBuffer(16); // 创建一个长度为 16 的 buffer + +let view = new Uint32Array(buffer); // 将 buffer 视为一个 32 位整数的序列 + +console.log(Uint32Array.BYTES_PER_ELEMENT); // 每个整数 4 个字节 + +console.log(view.length); // 4,它存储了 4 个整数 +console.log(view.byteLength); // 16,字节中的大小 + +// 让我们写入一个值 +view[0] = 123456; + +// 遍历值 +for(let num of view) { + console.log(num); // 123456,然后 0,0,0(一共 4 个值) +} + +console.log(view); +// Uint32Array(4) [ 123456, 0, 0, 0 ] diff --git a/4-binary/01-arraybuffer-binary-arrays/2.js b/4-binary/01-arraybuffer-binary-arrays/2.js new file mode 100755 index 0000000000..773ec6cd53 --- /dev/null +++ b/4-binary/01-arraybuffer-binary-arrays/2.js @@ -0,0 +1,8 @@ + +let arr16 = new Uint16Array([1, 1000]); +let arr8 = new Uint8Array(arr16); +console.log( arr8[0] ); // 1 +console.log( arr8[1] ); // 232,试图复制 1000,但无法将 1000 放进 8 位字节中(详述见下文)。 + +console.log( arr8[2] ); +// undefined diff --git a/4-binary/01-arraybuffer-binary-arrays/3.js b/4-binary/01-arraybuffer-binary-arrays/3.js new file mode 100755 index 0000000000..17c6ba76d8 --- /dev/null +++ b/4-binary/01-arraybuffer-binary-arrays/3.js @@ -0,0 +1,11 @@ + +let uint7array = new Uint8Array(16); + +let num = 255; +console.log(num.toString(2)); // 100000000(二进制表示) + +uint7array[0] = 256; +uint7array[1] = 257; + +console.log(uint7array[0]); // 0 +console.log(uint7array[1]); // 1 diff --git a/4-binary/01-arraybuffer-binary-arrays/4.js b/4-binary/01-arraybuffer-binary-arrays/4.js new file mode 100755 index 0000000000..32e219cb7e --- /dev/null +++ b/4-binary/01-arraybuffer-binary-arrays/4.js @@ -0,0 +1,24 @@ + +// 4 个字节的二进制数组,每个都是最大值 255 +let buffer = new Uint8Array([255, 255, 255, 255]).buffer; + +let dataView = new DataView(buffer); + +// 在偏移量为 0 处获取 8 位数字 +console.log( dataView.getUint8(0) ); // 255 + +console.log( dataView.getUint8(1) ); // 255 +console.log( dataView.getUint8(3) ); // 255 + +// console.log( dataView.getUint8(4) ); +// RangeError: Offset is outside the bounds of the DataView + + + +// 现在在偏移量为 0 处获取 16 位数字,它由 2 个字节组成,一起解析为 65535 +console.log( dataView.getUint16(0) ); // 65535(最大的 16 位无符号整数) + +// 在偏移量为 0 处获取 32 位数字 +console.log( dataView.getUint32(0) ); // 4294967295(最大的 32 位无符号整数) + +dataView.setUint32(0, 0); // 将 4 个字节的数字设为 0,即将所有字节都设为 0 diff --git a/4-binary/01-arraybuffer-binary-arrays/8.js b/4-binary/01-arraybuffer-binary-arrays/8.js new file mode 100755 index 0000000000..138920d825 --- /dev/null +++ b/4-binary/01-arraybuffer-binary-arrays/8.js @@ -0,0 +1,4 @@ + +let arr = new Uint8Array([0, 1, 2, 3]); +console.log( arr.length ); // 4,创建了相同长度的二进制数组 +console.log( arr[1] ); // 1,用给定值填充了 4 个字节(无符号 8 位整数) diff --git a/4-binary/03-blob/1.html b/4-binary/03-blob/1.html new file mode 100755 index 0000000000..9344f17574 --- /dev/null +++ b/4-binary/03-blob/1.html @@ -0,0 +1,14 @@ + + +Download + + diff --git a/4-binary/03-blob/2.html b/4-binary/03-blob/2.html new file mode 100755 index 0000000000..fe4e6f450d --- /dev/null +++ b/4-binary/03-blob/2.html @@ -0,0 +1,3 @@ + + + diff --git a/4-binary/03-blob/3.html b/4-binary/03-blob/3.html new file mode 100755 index 0000000000..685a932660 --- /dev/null +++ b/4-binary/03-blob/3.html @@ -0,0 +1,17 @@ + + diff --git a/4-binary/03-blob/4.html b/4-binary/03-blob/4.html new file mode 100755 index 0000000000..768c9bc088 --- /dev/null +++ b/4-binary/03-blob/4.html @@ -0,0 +1,44 @@ + + + + + + + + diff --git a/4-binary/04-file/1.html b/4-binary/04-file/1.html new file mode 100755 index 0000000000..2822e7cf9f --- /dev/null +++ b/4-binary/04-file/1.html @@ -0,0 +1,26 @@ + + + + diff --git a/5-network/01-fetch/1.js b/5-network/01-fetch/1.js new file mode 100755 index 0000000000..52c2883086 --- /dev/null +++ b/5-network/01-fetch/1.js @@ -0,0 +1,11 @@ + +( async function(){ + +let url = 'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits'; +let response = await fetch(url); + +let commits = await response.json(); // 读取 response body,并将其解析为 JSON 格式 + +console.log(commits[0].author.login); + +} )(); diff --git a/5-network/01-fetch/2.js b/5-network/01-fetch/2.js new file mode 100755 index 0000000000..242c98c6de --- /dev/null +++ b/5-network/01-fetch/2.js @@ -0,0 +1,4 @@ + +fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits') + .then(response => response.json()) + .then(commits => console.log(commits[0].author.login)); diff --git a/5-network/01-fetch/3.js b/5-network/01-fetch/3.js new file mode 100755 index 0000000000..0230822102 --- /dev/null +++ b/5-network/01-fetch/3.js @@ -0,0 +1,15 @@ + + +( async function(){ + +let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits'); + +// 获取一个 header +console.log(response.headers.get('Content-Type')); // application/json; charset=utf-8 + +// 迭代所有 header +for (let [key, value] of response.headers) { + console.log(`${key} = ${value}`); +} + +} )(); \ No newline at end of file diff --git a/5-network/01-fetch/4.js b/5-network/01-fetch/4.js new file mode 100755 index 0000000000..ff03a7ffa6 --- /dev/null +++ b/5-network/01-fetch/4.js @@ -0,0 +1,14 @@ + +// must await, otherwise won't get result + +// ERR + +let response = fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits'); + +// 获取一个 header +console.log(response.headers.get('Content-Type')); // application/json; charset=utf-8 + +// 迭代所有 header +for (let [key, value] of response.headers) { + console.log(`${key} = ${value}`); +} diff --git a/5-network/01-fetch/post.js b/5-network/01-fetch/post.js new file mode 100755 index 0000000000..86a2dcaf78 --- /dev/null +++ b/5-network/01-fetch/post.js @@ -0,0 +1,21 @@ + +( async function(){ + +let user = { + name: 'John', + surname: 'Smith' + }; + + let response = await fetch('https://zh.javascript.info/article/fetch/post/user', { + method: 'POST', + headers: { + 'Content-Type': 'application/json;charset=utf-8' + }, + body: JSON.stringify(user) + }); + + let result = await response.json(); + console.log(result.message); + console.dir(result); + +} )(); \ No newline at end of file diff --git a/5-network/03-fetch-progress/progress.view/index.html b/5-network/03-fetch-progress/progress.view/index.html index ba7f76065e..0da4c184c8 100644 --- a/5-network/03-fetch-progress/progress.view/index.html +++ b/5-network/03-fetch-progress/progress.view/index.html @@ -1,6 +1,6 @@ diff --git a/5-network/11-websocket/article.md b/5-network/11-websocket/article.md index 51a3f6ec4d..ea66ad1f2e 100644 --- a/5-network/11-websocket/article.md +++ b/5-network/11-websocket/article.md @@ -72,7 +72,7 @@ socket.onerror = function(error) { 当 `new WebSocket(url)` 被创建后,它将立即开始连接。 -在连接期间,浏览器(使用 header)问服务器:“你支持 WebSocket 吗?”如果服务器回复说“我支持”,那么通信就以 WebSocket 协议继续进行,该协议根本不是 HTTP。 +在连接期间,浏览器(使用 header)问服务器:“你支持 WebSocket 吗?”如果服务器回复说“我支持”,那么通信就以 WebSocket 协议继续进行,该协议完全不是 HTTP。 ![](websocket-handshake.svg) @@ -109,7 +109,7 @@ Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g= 这里 `Sec-WebSocket-Accept` 是 `Sec-WebSocket-Key`,是使用特殊的算法重新编码的。浏览器使用它来确保响应与请求相对应。 -然后,使用 WebSocket 协议传输数据,我们很快就会看到它的结构("frames")。它根本不是 HTTP。 +然后,使用 WebSocket 协议传输数据,我们很快就会看到它的结构("frames")。它完全不是 HTTP。 ### 扩展和子协议 @@ -119,7 +119,7 @@ WebSocket 可能还有其他 header,`Sec-WebSocket-Extensions` 和 `Sec-WebSoc - `Sec-WebSocket-Extensions: deflate-frame` 表示浏览器支持数据压缩。扩展与传输数据有关,扩展了 WebSocket 协议的功能。`Sec-WebSocket-Extensions` header 由浏览器自动发送,其中包含其支持的所有扩展的列表。 -- `Sec-WebSocket-Protocol: soap, wamp` 表示我们不仅要传输任何数据,还要传输 [SOAP](https://en.wikipedia.org/wiki/SOAP) 或 WAMP("The WebSocket Application Messaging Protocol")协议中的数据。WebSocket 子协议已经在 [IANA catalogue](https://www.iana.org/assignments/websocket/websocket.xml) 中注册。因此,此 header 描述了我们将要使用的数据格式。 +- `Sec-WebSocket-Protocol: soap, wamp` 表示我们要传输的数据不是随意的,而是 [SOAP](https://en.wikipedia.org/wiki/SOAP) 或 WAMP("The WebSocket Application Messaging Protocol")协议数据。WebSocket 子协议已经在 [IANA catalogue](https://www.iana.org/assignments/websocket/websocket.xml) 中注册。因此,此 header 描述了我们将要使用的数据格式。 这个可选的 header 是使用 `new WebSocket` 的第二个参数设置的。它是子协议数组,例如,如果我们想使用 SOAP 或 WAMP: diff --git a/js-notes-me.md b/js-notes-me.md new file mode 100755 index 0000000000..a02a4cb5dd --- /dev/null +++ b/js-notes-me.md @@ -0,0 +1,41 @@ + +# 关于 prototype 原型 + +取 对象的原型: __proto__ (~=父类) +(如果取对象的 prototype,会得到 null) + + 原理是 __proto__ 是在 Object.prototype 中定义的 setter/getter 函数 + + +取 函数的原型: prototype (到具体的父类(父函数)) +如果取某函数的 __proto__ (父类),会拿到 Function.prototype (合理) + + +取 (class)的原型: prototype + 例如 Array.prototype + + +extends 只能从一个父类继承, +如果想有多个父类的能力,用 mixin + + +# proxy +类似 java 里的 proxy +也有点像 C++ 里的操作符重载 + + +# curry 化 +有点像偏导数 + + +html element -> attribute +DOM -> property + + +某个element.append/prepend, before/after, replaceWith 这些都是以纯文本形式插入,不会识别为 html +要想插入 html 的话,用 elm.insertAdjacentHTML/Text/Element + + +想读尺寸数值的话,不要读 css,而是那些几何属性 clientXXX, xxxHeight 等 + +