diff --git a/learn_demo/chapter1.js b/learn_demo/chapter1.js
new file mode 100644
index 0000000..59bfa2c
--- /dev/null
+++ b/learn_demo/chapter1.js
@@ -0,0 +1,10 @@
+let msg = `hello \n
+world`;
+console.log(msg)
+
+
+let a
+let b = null
+let c = 10;
+console.log(a + c)
+console.log(b + c)
\ No newline at end of file
diff --git a/learn_demo/chapter10.js b/learn_demo/chapter10.js
new file mode 100644
index 0000000..1e58bec
--- /dev/null
+++ b/learn_demo/chapter10.js
@@ -0,0 +1,22 @@
+//事件
+//js可以监听到用户对html做的各种事件,并基于这些事件做出事件处理
+
+//常见的事件如下:
+//1. 鼠标事件:
+//onclick 一旦点击元素,触发事件
+//onmouseover 鼠标悬浮到元素上 触发事件
+//onmouseout 鼠标移出元素 触发事件
+//onmousedown 鼠标按钮对元素长按 触发事件
+//onmouseup 鼠标按钮对元素取消长按 触发事件
+//onmousemove 鼠标移动 触发事件
+
+//2. form表单
+//onfocus 用户聚焦某个元素时 触发事件
+//onSubmit 用户提交表单时 触发事件
+//onblur 焦点原理表单时 触发事件
+//onchange 当用户修改或更改表单元素的值时 触发事件
+
+//window/Document 事件
+//onload 当浏览器完成页面加载时触发事件
+//onunload 当访问者离开网页,浏览器将其卸载时,触发事件
+//onresize 当浏览器窗口被调整时 触发事件
\ No newline at end of file
diff --git a/learn_demo/chapter10_1.html b/learn_demo/chapter10_1.html
new file mode 100644
index 0000000..2aeb261
--- /dev/null
+++ b/learn_demo/chapter10_1.html
@@ -0,0 +1,25 @@
+
+
+
+
+ 事件处理测试
+
+
+
+ click example
+
+
+
+
+
+
\ No newline at end of file
diff --git a/learn_demo/chapter10_2.html b/learn_demo/chapter10_2.html
new file mode 100644
index 0000000..398329f
--- /dev/null
+++ b/learn_demo/chapter10_2.html
@@ -0,0 +1,30 @@
+
+
+
+
+ 事件委托
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/learn_demo/chapter10_3.html b/learn_demo/chapter10_3.html
new file mode 100644
index 0000000..a90b83c
--- /dev/null
+++ b/learn_demo/chapter10_3.html
@@ -0,0 +1,52 @@
+
+
+
+
+ 事件捕获与事件冒泡
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/learn_demo/chapter10_4.html b/learn_demo/chapter10_4.html
new file mode 100644
index 0000000..02f4fa2
--- /dev/null
+++ b/learn_demo/chapter10_4.html
@@ -0,0 +1,27 @@
+
+
+
+
+ form submi事件
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/learn_demo/chapter11_1.js b/learn_demo/chapter11_1.js
new file mode 100644
index 0000000..202c9f3
--- /dev/null
+++ b/learn_demo/chapter11_1.js
@@ -0,0 +1,122 @@
+//ES6中新增class 且在class中新增constructor构造方法
+
+class Person {
+ constructor(name, age) {
+ this.name = name
+ this.age = age
+ }
+}
+let tom = new Person("Tom", 12)
+console.log(JSON.stringify(tom))
+
+let { name, age } = tom;
+console.log(name, age)
+
+//clone对象
+//浅clone
+//1. 扩展运算符
+let address = {
+ city: "LA",
+ country: "USA"
+}
+tom.address = address;
+let marry = { ...tom }
+marry.name = "Marry"
+marry.age = 16
+marry.address.city = "NewYork"
+console.log(JSON.stringify(marry))
+console.log(JSON.stringify(tom))
+//2. Object.assign()
+let perter = Object.assign({}, tom)
+perter.name = "Peter"
+perter.address.city = "WT"
+console.log(JSON.stringify(tom))
+console.log(JSON.stringify(perter))
+
+//其中Object.assign功能更强大 Object.assign(target, ...sources)
+
+const target = { a: 1, b: 2 };
+const source = { b: 3, c: 4 };
+
+const returnedTarget = Object.assign(target, source);
+
+console.log(target); // { a: 1, b: 3, c: 5 }
+console.log(returnedTarget); // { a: 1, b: 3, c: 5 }
+
+//深拷贝
+let john = JSON.parse(JSON.stringify(tom))
+john.name = "John"
+john.address.city = "BeiJing"
+john.address.country = "China"
+console.log(JSON.stringify(tom))
+console.log(JSON.stringify(john))
+
+//深拷贝的实现
+
+function deepClone(obj) {
+ let cloneObj = {}
+ for (const property in obj) {
+ //深层对象,递归拷贝
+ if (typeof obj[property] === "object" && obj[property] != null) {
+ cloneObj[property] = deepClone(obj[property])
+ } else {
+ cloneObj[property] = obj[property]
+ }
+ }
+ return cloneObj
+}
+let jeffy = deepClone(tom)
+jeffy.name = "jeffy"
+jeffy.address.country = "France"
+console.log(JSON.stringify(tom))
+console.log(JSON.stringify(jeffy))
+
+
+//map与object
+let myPerson = {
+ name: "javascript",
+ age: 20
+}
+
+//对象遍历
+console.log("============")
+for (const property in myPerson) {
+ if (myPerson.hasOwnProperty(property)) {
+ console.log(property, myPerson[property])
+ }
+}
+for (const [key, value] of Object.entries(myPerson)) {
+ console.log(`${key}:${value}`)
+}
+
+for (const value of Object.values(myPerson)) {
+ console.log(value)
+}
+for (const key of Object.keys(myPerson)) {
+ console.log(key)
+}
+
+console.log("xxxxxxxxxxxxxxxxxxxxx")
+let myMap = new Map()
+//js中map通过get和set
+myMap.set("name", "javascript")
+myMap.set("age", 20)
+
+//这里用了解构来遍历key value
+for (const [key, value] of myMap) {
+ console.log(key, value)
+}
+//只遍历key
+for (const key of myMap.keys()) {
+ console.log(key)
+}
+//只遍历value
+for (const value of myMap.values()) {
+ console.log(value)
+}
+
+
+
+
+
+
diff --git a/learn_demo/chapter11_2.js b/learn_demo/chapter11_2.js
new file mode 100644
index 0000000..0395ec5
--- /dev/null
+++ b/learn_demo/chapter11_2.js
@@ -0,0 +1,26 @@
+//对象代理 有些类似于aop或者继承对象 然后重写父类方法 总之就是对原对象的代理增强
+class Person {
+ constructor(name, age) {
+ this.name = name
+ this.age = age
+ }
+}
+let tom = new Person("tom", 12)
+
+let proxyHandler = {
+ //重写原来的get
+ get(target, property) {
+ console.log("this is proxy obj get")
+ return target[property]
+ }
+}
+
+let proxyTom = new Proxy(tom, proxyHandler)
+console.log(proxyTom.name)
+
+//js中反射
+Person.prototype.sayHello = function (arg) {
+ console.log("hello i am ", this.name, arg)
+}
+tom.sayHello("nice to meet you")
+Reflect.apply(tom.sayHello, tom, ["nice to meet you too"])
\ No newline at end of file
diff --git a/learn_demo/chapter12_1.html b/learn_demo/chapter12_1.html
new file mode 100644
index 0000000..cc93af4
--- /dev/null
+++ b/learn_demo/chapter12_1.html
@@ -0,0 +1,67 @@
+
+
+
+
+ ducoment测试
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/learn_demo/chapter12_1.js b/learn_demo/chapter12_1.js
new file mode 100644
index 0000000..9bb4d9f
--- /dev/null
+++ b/learn_demo/chapter12_1.js
@@ -0,0 +1,2 @@
+//js中的window与document对象
+//详见https://github.com/coderZoe/javascript-basics 12.1节
diff --git a/learn_demo/chapter12_2.html b/learn_demo/chapter12_2.html
new file mode 100644
index 0000000..4b8521b
--- /dev/null
+++ b/learn_demo/chapter12_2.html
@@ -0,0 +1,12 @@
+
+
+
+
+ 浏览记录测试
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/learn_demo/chapter6.js b/learn_demo/chapter6.js
new file mode 100644
index 0000000..5c4c6b5
--- /dev/null
+++ b/learn_demo/chapter6.js
@@ -0,0 +1,53 @@
+//字符串数组操作
+
+//============= 1. slice与splice ===============//
+
+//slice与splice的区别 用于字符串处理
+//首先slice与splice最大的区别是slice不改变源数组,操作后会返回一个新的数组 splice是直接修改源数组
+
+let languages = ["JavaScript","Python","Java","PHP","Golang"]
+let slice1 = languages.slice(1,3) //Python Java
+console.log(slice1)
+
+//splice用于插入/删除/替换元素 比较复杂
+//首先函数接收1-n个参数,splice(index,count,item1,....,itemn)
+//第一个参数index是从何除开始操作(删除/添加)
+//第二个参数是要删除几个元素,从index开始从后数,要删除几个参数,count可以为0,此时代表删除0个元素
+//后面的第3-n个元素代表要插入的元素,从index开始向后插入
+//举几个常见案例
+//1. 删除
+let languages2 = ["JavaScript","Python","Java","PHP","Golang"]
+languages2.splice(1,1)
+console.log(languages2) //JavaScript Java PHP Golang
+
+//2. 替换
+let languages3 = ["JavaScript","Python","Java","PHP","Golang"]
+languages3.splice(1,1,"Rust")
+console.log(languages3) //JavaScript Rust Java PHP Golang
+
+//3. 插入
+let languages4 = ["JavaScript","Python","Java","PHP","Golang"]
+languages4.splice(1,0,"Rust")
+console.log(languages4) //JavaScript Rust Python Java PHP Golang
+
+
+//================2. 字串包含 ==============//
+//1. 使用正则匹配,这里不再演示
+
+//2. 使用indexOf
+let str1 = "hello world"
+let subStr1 = "world"
+let isSub = str1.indexOf(subStr1) != -1
+console.log(isSub)
+
+//3. 使用includes
+let str2 = "hello world"
+let subStr2 = "wor";
+console.log(str2.includes(subStr2))
+
+//=========3. 检测是否以XX开头或者结尾 =========
+let str3 = "hello world"
+let startStr = "hello"
+let endStr = "world"
+console.log(str3.startsWith(startStr))
+console.log(str3.endsWith(endStr))
\ No newline at end of file
diff --git a/learn_demo/chapter7.js b/learn_demo/chapter7.js
new file mode 100644
index 0000000..74c8bb5
--- /dev/null
+++ b/learn_demo/chapter7.js
@@ -0,0 +1,205 @@
+//数组
+
+//=======1. 数组添加删除元素=====//
+
+
+//1. slice与splice 见chapter6
+
+//2. pop和push
+let fruits = ["Apple", "Orange", "Banana"]
+fruits.push("Pear")
+console.log(fruits)
+fruits.pop()
+console.log(fruits)
+
+//3. shift和unshift
+//shift删除头元素
+fruits.shift()
+console.log(fruits)
+//unshift插入头元素
+fruits.unshift("Apple", "Cherry")
+console.log(fruits)
+//4. concat 连接两个数组 不会修改原数组,而是会返回一个新数组
+let doc = [".docs", ".xlsx", ".md"]
+let array1 = doc.concat(fruits)
+console.log(array1)
+
+
+//5. map传入一个方法,方法会返回元素,源数组里的每个元素执行方法,然后返回的元素收集起来创建一个新数组 类似于Java流中的map
+let sfruits = fruits.map(element => "s" + element)
+console.log(sfruits)
+
+//6. filter 与Java流中的filter功能类似
+let filterFruits = fruits.filter(element => element.startsWith("A"))
+console.log(filterFruits)
+
+//7. reduce reduce每个元素迭代执行,然后返回一个最终结果
+let reduceResult = fruits.reduce((result, element) => result + element) //AppleCherryOrangeBanana
+console.log(reduceResult)
+
+//8. reduceRight 与reduce基本一样,但是倒着 从右向左使用
+let reduceRightResult = fruits.reduceRight((result, element) => result + element) //BananaOrangeCherryApple
+console.log(reduceRightResult)
+
+//9. every 测试方法中的每个元素是否都通过了测试,返回bool,通过filter也可以实现,filter过滤结果与原数组一样就是every通过
+let everyResult = fruits.every(element => element.length > 2) //true
+console.log(everyResult)
+//与下面等效果
+let everyFilterResult = fruits.filter(element => element.length > 2).length == fruits.length
+console.log(everyFilterResult)
+
+//10. some 有一个通过就行
+let someResult = fruits.some(element => element.startsWith("App"))
+console.log(someResult)
+//与下面等效
+let someFilterResult = fruits.filter(element => element.startsWith("App")).length > 0
+console.log(someFilterResult)
+
+//11. find 找到第一个满足条件的元素并返回
+let findResult = fruits.find(element => element.length > 5)
+console.log(findResult)
+
+
+//12. 排序 sort
+let unsortArray = [1, 4, 2, 7, 3, 8, 5]
+let sortArray = unsortArray.sort((a, b) => a - b)
+console.log(sortArray) //[1, 2, 3, 4, 5, 7, 8]
+
+//===========2. 数组遍历 ===============//
+for (let i = 0; i < fruits.length; i++) {
+ console.log(fruits[i])
+}
+
+//for of用于遍历数组 for of迭代的是值 for in迭代的是key
+for (let i of fruits) {
+ console.log(i)
+}
+//或者直接调用for-each方法,这应该是数组原型链支持的方法,方法支持多个参数
+fruits.forEach((element, index) => {
+ console.log(element, index)
+});
+
+
+
+//3. ============ rest与spread ================= //
+//rest与spread的语法都是剩余运算符... 但rest用于将多个参数合并为一个数组,而spread用于将一个数组/对象展开为单个元素,举例如下:
+
+//rest用于将多个元素合成一个数组,下例中就是将1,2,3,4,5元素合成数组element
+function sum(start, ...element) {
+ return start + element.reduce((result, item) => result + item)
+}
+
+console.log(sum(0, 1, 2, 3, 4, 5)) //15
+
+
+//spread用于将数组/对象拆为单个元素,比如下例中将数组sumItem自动拆为x,y,z
+function sum2(x, y, z) {
+ return x + y + z
+}
+let sumItem = [1, 2, 3]
+console.log(sum(...sumItem))
+
+let spreadArray1 = [3, 4, 5]
+let spreadArray2 = [1, 2, ...spreadArray1, 6, 7]
+console.log(spreadArray2)
+
+let stu1 = {
+ age: 1,
+ name: "Tom",
+ sex: "Man"
+}
+let stu2 = {
+ ...stu1
+}
+console.log(JSON.stringify(stu2))
+
+
+//=============4. 解构 ============//
+//js中的解构主要用于从数组或对象中解析出元素
+//数组解构如下:
+let animals = ["mouse", "cat", "dog"]
+let [a, b, c] = animals;
+console.log(a, b, c) //mouse cat dog
+let [d, , e] = animals;
+console.log(d, e) //mouse dog
+
+//对象解构如下:
+let person = {
+ name: "Tom",
+ age: 18,
+ sex: "Man"
+}
+let { name, age, sex } = person;
+console.log(name, age, sex) //Tom 18 Man
+
+//指定属性映射
+let { name: personName, age: PersonAge } = person
+console.log(personName, PersonAge) //Tom 18
+
+//方法参数是解构
+function consolePerson({ name, age }) {
+ console.log(name, age)
+}
+consolePerson(person) //Tom 18
+
+function consoleAnimal([a, b]) {
+ console.log(a, b)
+}
+consoleAnimal(animals) //mouse cat
+
+//替换
+let num1 = 10;
+let num2 = 20;
+[num1, num2] = [num2, num1]
+console.log(num1, num2) //20 10
+
+//默认值
+let animals2 = ["Lion", "Tigger"]
+let [a2 = "a2", b2 = "b2", c2 = "c2"] = animals2
+console.log(a2, b2, c2) //Lion Tigger c2
+
+let person2 = {
+ name: "Marry",
+ sex: "Woman"
+}
+let { name: Person2Name = "Test", age: Person2Age = -1, sex: Person2Sex = "Test" } = person2
+console.log(Person2Name, Person2Age, Person2Sex) //Marry -1 Woman
+
+function consolePerson2({ name, age = 10 }) {
+ console.log(name, age)
+}
+consolePerson2(person) //Tom 18
+consolePerson2(person2) //Marry 10
+
+
+
+//================== 5.JSON ==================//
+const personData = {
+ "personsJsonArray": [
+ { "name": "Tom", "age": 18 },
+ { "name": "Marry", "age": 16 },
+ { "name": "John", "age": 28 },
+ { "name": "Peter", "age": 38 }
+ ]
+}
+console.log(personData.personsJsonArray[0].name)
+
+//parse与stringify
+const personObj = [
+ {
+ name: "Tom",
+ age: 18
+ },
+ {
+ name: "Marry",
+ age: 28
+ },
+ {
+ name: "John",
+ age: 38
+ }
+]
+console.log(JSON.stringify(personObj)) //[{"name":"Tom","age":18},{"name":"Marry","age":28},{"name":"John","age":38}]
+
+let personJson = '[{"name":"Tom","age":18},{"name":"Marry","age":28},{"name":"John","age":38}]';
+console.log(JSON.parse(personJson)[1].name) //Marry
diff --git a/learn_demo/chapter9_1.js b/learn_demo/chapter9_1.js
new file mode 100644
index 0000000..9d126d6
--- /dev/null
+++ b/learn_demo/chapter9_1.js
@@ -0,0 +1,121 @@
+// 箭头函数
+let consoleHello = () => {
+ console.log("Hello")
+}
+consoleHello()
+
+//其等价于
+function consoleHello2() {
+ console.log("Hello")
+}
+consoleHello2()
+//或者
+let consoleHello3 = function () {
+ console.log("Hello")
+}
+consoleHello3()
+
+//单参数
+let consoleNum = x => console.log(x)
+consoleNum(1)
+
+//多参数
+let consoleNumSum = (x, y) => console.log(x + y)
+consoleNumSum(1, 2) //3
+
+//箭头方法使用的注意场景:
+//=======1. 应该使用的场景==========//
+//1. 无需this的 箭头函数与普通函数最大的区别是箭头函数没有this上下文,而普通函数有this,其中普通函数的this指向调用时的环境 举例如下:
+
+const person = {
+ name: "Tom",
+ say: function () {
+ console.log(this.name)
+ }
+}
+//由于say方法是普通函数,且调用它的环境是person,因此这里的this.name就是person.name
+person.say() //Tom
+//但如果要是
+const person2 = {
+ name: "Tom",
+ say: () => {
+ console.log(this.name)
+ }
+}
+//此时say是箭头函数,没有上下文,那它的上下文就是全局对象,因此不存在name属性
+person2.say() //undefined
+
+//2. 回调函数中
+const unsortedArray = [4, 7, 2, 6]
+const sortedArray = unsortedArray.sort((a, b) => a - b)
+console.log(sortedArray) //[2,4,6,7]
+//或者
+const person3 = {
+ name: "Tom",
+ say: function () {
+ setTimeout(() => {
+ console.log(this.name)
+ }, 0)
+ }
+}
+//say本身是普通函数,因此具有this是person3,say里的回调函数() =>{console.log(this.name)} 本身无this,因此继承say的this,也是person3,因此可以找到name
+person3.say() //Tom
+//但如果是下面这样就有问题:因为person4CallBack是普通方法,他有this,它的this其实是全局对象
+function person4CallBack() {
+ console.log(this.name)
+}
+
+const person4 = {
+ name: "Tom",
+ say: function () {
+ setTimeout(person4CallBack, 0)
+ }
+}
+person4.say() //undefined
+
+//3.构造方法不能用箭头函数,因为无法继承this
+const Person5 = (name) => {
+ this.name = name
+}
+// const john = new Person5("John") //会报错
+
+const Person6 = function (name) {
+ this.name = name
+}
+const marry = new Person6("Marry")
+console.log(marry.name) //Marry
+
+//4. arguments js中的arguments代表所有入参,是个数组,但箭头函数没有argumenst
+function argumentsTest1(a,b){
+ console.log(arguments[0])
+}
+argumentsTest1(1,2) //1
+
+let argumentsTest2 = (a,b) =>{
+ console.log(arguments[0])
+}
+argumentsTest2(1,2) //undefined 这里是由于运行环境是nodejs环境,全局变量有arguments,但不是入参参数上那个,如果是浏览器环境则报错
+
+//5. 添加原型链方法也不应该使用箭头函数,如:
+function PersonPrototype(name ,age){
+ this.name = name
+ this.age = age
+}
+PersonPrototype.prototype.say = () =>{
+ console.log("say",this.name)
+}
+new PersonPrototype("Tom",18).say() //say undefined
+
+PersonPrototype.prototype.say2 = function(){
+ console.log("say2",this.name)
+}
+new PersonPrototype("Tom",18).say2() //say2 Tom
+
+//6. 事件处理器
+document.getElementById('myButton').addEventListener('click', function() {
+ console.log(this); // 这里的 `this` 指向触发事件的元素,即 'myButton'
+ })
+document.getElementById('myButton').addEventListener('click', () => {
+ console.log(this); // 这里的 `this` 不再指向触发事件的元素,而是指向定义事件处理器时的上下文 例如,如果在全局作用域中定义,则this可能是全局对象,如window)
+ })
+
diff --git a/learn_demo/chapter9_2.js b/learn_demo/chapter9_2.js
new file mode 100644
index 0000000..927dfcc
--- /dev/null
+++ b/learn_demo/chapter9_2.js
@@ -0,0 +1,80 @@
+//函数的属性
+
+//1. arguments 函数的所有参数
+function sum(...elements){
+ let count = 0;
+ //arguments不是严格意义上的数组,因此不能使用数组的reduce map filter等方法
+ for(arg of arguments){
+ count+=arg
+ }
+ return count;
+}
+console.log(sum(1,2,3)) //6
+//2. arguments.callee 返回正在执行的函数
+function fa(){
+ console.log("fa")
+ return arguments.callee;
+}
+function fb(){
+ console.log("fb")
+ return arguments.callee;
+}
+//返回方法本身,再使用()调用方法
+fa()()()
+fb()()()
+
+//3. arguments.length 参数长度
+//4. constructor 构造函数
+//5. prototype 原型
+
+//我们需要回顾一下构造方法:
+function Person(name,age){
+ this.name = name;
+ this.age = age;
+}
+let tom = new Person("tom",18)
+console.log(JSON.stringify(tom))
+//上面我们使用了new关键字,但new的实现其实如下:
+//其核心思想其实就是原型链,Object.create()方法需要传入一个原型,而每个方法都是有原型属性的
+function _new(constructor,...params){
+ let obj = Object.create(constructor.prototype)
+ let result = constructor.apply(obj,params)
+ return (typeof result === 'object' && result != null) ? result : obj;
+}
+
+let marry = _new(Person,"Marry",20)
+console.log(JSON.stringify(marry))
+
+//关于原型链,这里解释一下 在js中每个函数都有个原型属性
+//当这个函数是构造函数的时候,实际上new的时候就如上,let obj = Object.create(constructor.prototype)
+//造出来的对象的原型就是构造函数的原型,所以函数原型其实往往只有函数是构造函数时有意义
+
+//最后这里再补充下call apply和bind的区别
+//首先call和apply功能基本相似,它们都是允许你指令函数运行时的上下文(this),区别是call是正常传入参数,但apply的参数用数组组合起来,举例如下:
+
+function sayHello(address,sex){
+ console.log(this.name,this.age,address,sex)
+}
+let peter = {
+ name: "Peter",
+ age: 12
+}
+let zoe = {
+ name: "Zoe",
+ age: 16
+}
+sayHello.call(peter,"翻斗花园","男")
+sayHello.call(zoe,"青青草原","女")
+//apply是将参数放在了数组里 相对来说我还是更喜欢call
+sayHello.apply(peter,["翻斗花园","男"])
+sayHello.apply(zoe,["青青草原","女"])
+
+//bind其实是对上面的两步拆解,先绑定一个上下文this,返回返回一个新的函数,再可以调用这个函数,举例如下:
+let peterSayHello = sayHello.bind(peter)
+peterSayHello("翻斗花园","男")
+let zoeSayHelllo = sayHello.bind(zoe)
+zoeSayHelllo("青青草原","女")
+
+
+//可以看到无论是bind还是call或者apply 它们的核心思想都是从别的对象上借一个方法用在自己的对象上
+//bind的好处是返回一个借过后的方法,方便后续利用,而不像call和apply是一次性的
diff --git a/learn_demo/chapter9_3.js b/learn_demo/chapter9_3.js
new file mode 100644
index 0000000..035aa85
--- /dev/null
+++ b/learn_demo/chapter9_3.js
@@ -0,0 +1,27 @@
+//柯里化函数
+function sum(a,b,c){
+ return a+b+c
+}
+console.log(sum(1,2,3))
+
+//柯里化函数其实就是将上面的多个参数函数改为一个参数的函数,并返回一个新函数继续调用
+function curryingSum(a){
+ return (b) =>{
+ return (c) =>{
+ return a+b+c
+ }
+ }
+}
+console.log(curryingSum(1)(2)(3))
+
+//柯里化函数主要是针对 一些代码复用场景,比如:
+let base3Sum = curryingSum(1)(2)
+console.log(base3Sum(4))
+console.log(base3Sum(7))
+
+//自执行函数 一般都是匿名函数,主要是就用这一次的函数 但js的自执行函数坑挺多的,比如需要()括住整体表达式,还要加;
+;(function (a,b){
+ console.log(a+b)
+})(1,2)
+
+
diff --git a/learn_demo/chapter9_4.js b/learn_demo/chapter9_4.js
new file mode 100644
index 0000000..a70e71e
--- /dev/null
+++ b/learn_demo/chapter9_4.js
@@ -0,0 +1,112 @@
+//聊一下JS中比较关键的promise
+
+function getPromsie(delay){
+ return new Promise((resolve,reject) =>{
+ setTimeout(() => {
+ resolve("ok")
+ }, delay);
+ })
+}
+
+getPromsie(5000).then((result) => console.log(result)) //5秒后打印ok
+
+//上面就是一个很典型的js中promise demo 由于笔者很熟悉netty中的future-promise源码,而js得实现与此基本类似,所以类比说下理解:
+//首先netty中的promise是通过setSuccess或者setFail来设置结果的,我们知道结果一旦设置就代表promise的完成
+//而一旦promise完成,就需要做两件事:1. 唤醒由于promise阻塞的线程 2. 执行注册的监听器
+//其中netty promise中的setSuccess其实就是js中的resolve,一旦执行resolve就代表设置正常结果,而resolve得参数就是结果值
+//netty promise中得setFail 其实就是js中得reject,一旦执行reject就代表设置异常结果
+//netty中注册监听器是通过addListener,而js中通过.then注册正常返回时候得监听器,而通过.catch注册异常执行时得监听器
+//netty中通过get来同步阻塞等待获取promise得结果,而js中是通过await 其中js中的await要和async函数一起使用,这是一种异步阻塞
+async function promiseHandle(){
+ try {
+ const result = await getPromsie(10000) //10s后返回ok
+ console.log(result)
+ } catch (error) {
+ //promise执行异常会到这里
+ console.error(error)
+ }
+}
+promiseHandle()
+console.log("hello")
+
+
+//js中的生成器
+function* gen(){
+ yield 1;
+ yield 2;
+ yield 3;
+}
+const generator = gen()
+console.log(generator.next().value)
+console.log(generator.next().value)
+console.log(generator.next().value)
+
+//生成器其实具备一个功能:暂停和继续执行代码,可以看到yield会自动暂停代码的执行,当再次调用next的时候又会继续从之前暂停处执行代码
+//这有些类似于线程的挂起和唤醒 通过这个功能,其实我们可以实现上面说的async与await(其实js底层的async和await其实就是通过生成器实现的)
+function* asyncGen(){
+ const result = yield new Promise(resolve =>{
+ setTimeout(() => {
+ resolve("asyncGen Promise Finish")
+ }, 3000);
+ });
+ console.log(result)
+}
+
+const asyncGenerator = asyncGen()
+
+function run(generator){
+ let iteration = generator.next()
+ if(!iteration.done){
+ let promise = iteration.value
+ promise.then(result =>{
+ generator.next(result)
+ })
+ }
+}
+
+run(asyncGenerator)
+//如上例所示:
+//核心其实是如下几处: const result = yield new Promise(...)
+//这里其实会先将yield右侧处的代码返回,也即如果调用asyncGen().next()会得到一个promise
+//但注意的是,只会执行yield右侧的代码,左侧的const result = yield其实不会执行,下面的console.log(result)也不会执行
+//那什么时候执行呢?下一次再调asyncGen().next()的时候。
+//所以我们可以认为生成器其实具备暂停和恢复执行的能力,有些类似于其他编程语言中线程的挂起和唤醒
+//既然具备这个能力,那只需要在promise没执行完的时候挂起,promise执行完后再恢复执行即可
+//因此下一处核心其实是
+// let iteration = generator.next()
+// if(!iteration.done){
+// let promise = iteration.value
+// promise.then(result =>{
+// generator.next(result)
+// })
+// }
+//这里先拿到promise,如果promise没完成,就注册一个监听器,监听器执行的时间必然是promise完成的时间,
+//此时在这个监听器里执行generator.next(result),由于生成器被调用next会继续执行代码,也即执行下面的
+//const result = yield... 和console.log(result) 需要注意的是,我们给next方法传入了一个参数
+//而这个参数其实就可以作为上一次yield的返回结果,我们知道这个result就是promise的结果,将promise的结果作为yield的返回
+//因此const result = yield ...其实result赋值的就是promise的结果 这就很像 const result = await promise
+
+//最后我们总结下:
+//T1时刻,通过调用生成器.next()返回一个Promise,这个promise没完成,我们给这个Promise注册一个.then监听器,
+//监听器的内容是:一旦Promise完成,拿到Promise的结果,并将结果赋值给生成器的返回,并触发生成器继续执行代码对应的是.next(result)
+//T2 时刻 Promise完成,此时执行监听器代码,将Promise结果返回,并将结果设置为生成器yield的返回结果 此时const result = yield...被执行
+//然后result的结果就是Promise的结果,,再然后打印result
+
+
+
+
+
+//js中的闭包
+function closures(){
+ let count = 0
+ return function(){
+ return ++count
+ }
+}
+
+let adder = closures()
+console.log("count ",adder())
+console.log("count ",adder())
+console.log("count ",adder())
+console.log("count ",adder())
+