ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[toc] # 每日英语 1. `clipboard` 剪切板 2. `declaration` 声明 3. `hoisting` 提升 4. `factorial` 阶乘 5. `Range` 范围 6. `Maximum` 最大值 7. `call` 调用 8. `stack` 栈(内存) 9. `queue` 队列 10. `heap` 堆 11. `exceeded` 超越,超限 12. `overflow` 溢出 # 日历功能 ## 为 div 添加文字 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> <style> #div1 { width: 200px; height: 150px; border: 1px #000 solid; word-wrap: break-word; overflow-y: auto; } </style> <script> window.onload = function() { var oDiv = document.getElementById("div1"); var oBtn = document.getElementById("btn1"); var oTxt = document.getElementById("txt1"); oBtn.onclick = function() { oDiv.innerHTML = oTxt.value; }; }; </script> </head> <body> <input type="text" id="txt1" /> <input type="button" id="btn1" value="设置文字" /> <div id="div1"></div> </body> </html> ``` ## 注意 innerHTML 和 innerText 的区别 > innerHTML 会解析 html 代码 > innerText 会原样输出 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> <style> #div1 { width: 200px; height: 150px; border: 1px #000 solid; word-wrap: break-word; overflow-y: auto; } </style> <script> window.onload = function() { var oDiv = document.getElementById("div1"); var oBtn = document.getElementById("btn1"); var oTxt = document.getElementById("txt1"); oBtn.onclick = function() { oDiv.innerText = oTxt.value; // oDiv.innerHTML = oTxt.value; }; }; </script> </head> <body> <input type="text" id="txt1" /> <input type="button" id="btn1" value="设置文字" /> <div id="div1"></div> </body> </html> ``` ## 先做`onmouseover`的效果 ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <link href="calendar.css" rel="stylesheet" type="text/css" /> <script> window.onload = function() { var oDiv = document.getElementById("tab"); var aLi = oDiv.getElementsByTagName("li"); var oTxt = oDiv.getElementsByTagName("div")[0]; for (var i = 0; i < aLi.length; i++) { aLi[i].onmouseover = function() { for (var i = 0; i < aLi.length; i++) { aLi[i].className = ""; } this.className = "active"; }; } }; </script> </head> <body> <div id="tab" class="calendar"> <ul> <li class="active"> <h2>1</h2> <p>JAN</p> </li> <li> <h2>2</h2> <p>FER</p> </li> <li> <h2>3</h2> <p>MAR</p> </li> <li> <h2>4</h2> <p>APR</p> </li> <li> <h2>5</h2> <p>MAY</p> </li> <li> <h2>6</h2> <p>JUN</p> </li> <li> <h2>7</h2> <p>JUL</p> </li> <li> <h2>8</h2> <p>AUG</p> </li> <li> <h2>9</h2> <p>SEP</p> </li> <li> <h2>10</h2> <p>OCT</p> </li> <li> <h2>11</h2> <p>NOV</p> </li> <li> <h2>12</h2> <p>DEC</p> </li> </ul> <div class="text"> <h2>1月活动</h2> <p>快过年了,大家可以商量着去哪玩吧~</p> </div> </div> </body> </html> ``` ## 再改标题(注意, 有个小问题) ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <link href="calendar.css" rel="stylesheet" type="text/css" /> <script> window.onload = function() { var oDiv = document.getElementById("tab"); var aLi = oDiv.getElementsByTagName("li"); var oTxt = oDiv.getElementsByTagName("div")[0]; for (var i = 0; i < aLi.length; i++) { aLi[i].index = i; aLi[i].onmouseover = function() { for (var i = 0; i < aLi.length; i++) { aLi[i].className = ""; } this.className = "active"; console.log(i); oTxt.innerHTML = "<h2>" + this.index + 1 + "月活动</h2> <p>快过年了,大家可以商量着去哪玩吧~</p>"; // oTxt.innerHTML = "<h2>" + (this.index + 1) + "月活动</h2> <p>快过年了,大家可以商量着去哪玩吧~</p>"; }; } }; </script> </head> <body> <div id="tab" class="calendar"> <ul> <li class="active"> <h2>1</h2> <p>JAN</p> </li> <li> <h2>2</h2> <p>FER</p> </li> <li> <h2>3</h2> <p>MAR</p> </li> <li> <h2>4</h2> <p>APR</p> </li> <li> <h2>5</h2> <p>MAY</p> </li> <li> <h2>6</h2> <p>JUN</p> </li> <li> <h2>7</h2> <p>JUL</p> </li> <li> <h2>8</h2> <p>AUG</p> </li> <li> <h2>9</h2> <p>SEP</p> </li> <li> <h2>10</h2> <p>OCT</p> </li> <li> <h2>11</h2> <p>NOV</p> </li> <li> <h2>12</h2> <p>DEC</p> </li> </ul> <div class="text"> <h2>1月活动</h2> <p>快过年了,大家可以商量着去哪玩吧~</p> </div> </div> </body> </html> ``` ## 最后改内容 > 最后的`+=`代表字符串拼接 > 注意修改默认的 div 文字为数组的第一项 ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <link href="calendar.css" rel="stylesheet" type="text/css" /> <script> window.onload = function() { var aDatas = [ "一月首阳,犹有寒霜,唯有梅花独自香", "早春二月, 春意渐浓, 往事随风...", "春天来了,万物复苏, 又到了交配的季节...", "人间四月天, 承载着岁月的沧桑, 承载着如诗的心语", "除了诱惑, 我还有什么不能抗拒? 五月, 情窦初开...", "六月的风, 缠绵, 六月的雨, 热情...", "七月的风和八月的雨,卑微的喜欢和遥远的你", "七月的风和八月的雨,满满的功课和无聊的假期...", "九月江南花事休, 芙蓉宛转在中洲. 美人笑隔盈盈水, 落日还生渺渺愁", "十月了, 小伙伴们已经迫不及待的要给祖国庆生了!", "十一月来了, 丹桂飘香、秋风萧瑟、黄叶遍地", "冰雪林中著此身,不同桃李混芳尘。" ]; var oDiv = document.getElementById("tab"); var aLi = oDiv.getElementsByTagName("li"); var oTxt = oDiv.getElementsByClassName("text")[0]; for (var i = 0; i < aLi.length; i++) { aLi[i].aaa = i; // aLi[i].aaa1 = i + 1; aLi[i].onmouseover = function() { for (var i = 0; i < aLi.length; i++) { aLi[i].className = ""; } this.className = "active"; oTxt.innerHTML = ""; oTxt.innerHTML += "<h2>" + (this.aaa + 1) + "月活动</h2>"; oTxt.innerHTML += "<p>" + aDatas[this.aaa] + "</p>"; }; } }; </script> </head> <body> <div id="tab" class="calendar"> <ul> <li class="active"> <h2>1</h2> <p>JAN</p> </li> <li> <h2>2</h2> <p>FER</p> </li> <li> <h2>3</h2> <p>MAR</p> </li> <li> <h2>4</h2> <p>APR</p> </li> <li> <h2>5</h2> <p>MAY</p> </li> <li> <h2>6</h2> <p>JUN</p> </li> <li> <h2>7</h2> <p>JUL</p> </li> <li> <h2>8</h2> <p>AUG</p> </li> <li> <h2>9</h2> <p>SEP</p> </li> <li> <h2>10</h2> <p>OCT</p> </li> <li> <h2>11</h2> <p>NOV</p> </li> <li> <h2>12</h2> <p>DEC</p> </li> </ul> <div class="text"> <h2>1月活动</h2> <p>一月首阳,犹有寒霜,唯有梅花独自香</p> </div> </div> </body> </html> ``` # 什么是函数 - 函数实际上是对象。每个函数都是 Function 类型的实例,而且都与其他引用类型一样具有属性和方法。 - 由于函数是对象,因此函数名实际上也是一个指向函数对象的指针 - 函数通常是使用函数声明语法定义的,如下面的例子所示。 ## 定义函数的三种方式 ```javascript function sum(num1, num2) { return num1 + num2; } ``` - 这与下面使用函数表达式定义函数的方式一样。 ```javascript var sum = function(num1, num2) { return num1 + num2; }; ``` - `function` 关键字后面没有函数名。(匿名函数) - 这是因为在使用函数表达式定义函数时,没有必要使用函数名——通过变量 sum 即可以引用函数。 - 另外,还要注意函数末尾有一个分号,就像声明其他变量时一样。 * 最后一种定义函数的方式是使用 Function 构造函数。 Function 构造函数可以接收任意数量的参数 * 最后一个参数始终都被看成是函数体,而前面的参数则枚举出了新函数的参数。 ```javascript var sum = new Function("num1", "num2", "return num1 + num2"); // 不推荐 ``` - 从技术角度讲,这是一个函数表达式 - 不推荐读者使用这种方法定义函数,因为这种语法会导致解析两次代码(影响性能) - 第一次是解析常规 ECMAScript 代码 - 第二次是解析传入构造函数中的字符串 - 这种语法对于理解“函数是对象,函数名是指针”的概念倒是非常直观的。 - 由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同。 - 换句话说,一个函数可能会有多个名字 ```javascript function sum(num1, num2) { return num1 + num2; } console.log(sum(10, 10)); var anotherSum = sum; console.log(anotherSum(10, 10)); ``` ## 请大家思考一个问题 ```javascript function sum(num1, num2) { return num1 + num2; } console.log(sum(10, 10)); var anotherSum = sum; console.log(anotherSum(10, 10)); sum = null; console.log(anotherSum(10, 10)); ``` ```javascript function sum(a, b) { return a + b; } console.log(sum()); // undefined+undefined = NaN var anotherSum = sum(); console.log(anotherSum); // NaN ``` ```javascript function sum(a, b) { return a + b; } console.log(sum()); // undefined+undefined = NaN var anotherSum = sum(); console.log(anotherSum(10, 10)); // error, NaN不是一个函数 ``` - 使用不带圆括号的函数名是访问函数指针,而非调用函数 # 函数没有重载 ## 什么是重载? > 方法名相同, 但是参数类型或参数个数不同的两个或者多个方法, 形成重载的关系 > 同一个函数, 参数不同, 干不同的事情 ```javascript function addParams(param1, param2) { console.log("字符串相加!"); console.log(param1 + param2); } function addParams(param1, param2) { console.log("数字相加"); console.log(param1 + param2); } addParams("123", "1"); addParams(123, 1); ``` **相当于这样...** ```javascript var addParams = function(param1, param2) { console.log("字符串相加!"); console.log(param1 + param2); }; var addParams = function(param1, param2) { console.log("数字相加"); console.log(param1 + param2); }; addParams("123", "1"); addParams(123, 1); ``` ```javascript function addStrParams(param1, param2) { console.log("字符串相加!"); console.log(param1 + param2); } function addNumParams(param1, param2) { console.log("数字相加"); console.log(param1 + param2); } addStrParams("123", "1"); addNumParams(123, 1); ``` ### javascript 模拟重载 ```javascript function addParams(param1, param2) { if (typeof param1 === "string" && typeof param2 === "string") { console.log("字符串相加!"); } if (typeof param1 === "number" && typeof param2 === "number") { console.log("数字相加!"); } console.log(param1 + param2); } addParams("123", "1"); addParams(123, 1); ``` # 函数声明与函数表达式(为什么函数可以先调用后声明) 什么是函数声明, 什么是函数表达式? 先看一个小栗子 ```javascript function hello() { console.log("hello world"); } hello(); // "hello world" ``` ```javascript hello(); // "hello world" function hello() { console.log("hello world"); } ``` **顺便插一句, 代码压缩的注释问题** ```javascript hello(); /* "hello world" */ function hello() { console.log("hello world"); } ``` ```javascript var hello = function() { console.log("hello world"); }; hello(); // "hello world" ``` ```javascript hello(); var hello = function() { console.log("hello world"); }; ``` ```javascript console.log(a); var a = 123; ``` ```javascript var a; console.log(a); a = 123; ``` ```javascript var hello; // undefined hello(); hello = function() { console.log("hello world"); }; ``` - 解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。 - 解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问) > 函数声明提升 (`function declaration hoisting`) - 函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行 # 函数的内部属性 ## arguments - 在函数内部,有两个特殊的对象: arguments 和 this 。 - arguments 它是一个类数组对象,包含着传入函数中的所有参数(所有数字求和)。 - 虽然 arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。 - `arguments.callee`代表函数本身, 代表当前函数, 或者代表`这个`函数 > 来一个阶乘(`factorial`) ```javascript function factorial(num) { if (num <= 1) { return 1; } else { return num * factorial(num - 1); } } console.log(factorial(5)); ``` 如果改名字了呢? ```javascript function factorial(num) { if (num <= 1) { return 1; } else { return num * factorial(num - 1); } } console.log(factorial(5)); var trueFactorial = factorial; factorial = function() { return 0; }; console.log(trueFactorial(5)); console.log(factorial(5)); ``` 解决方案(解耦) > 解除函数体代码和函数名的耦合状态 ```javascript function factorial(num) { if (num <= 1) { return 1; } else { return num * arguments.callee(num - 1); } } console.log(factorial(5)); ``` ```javascript function factorial(num) { if (num <= 1) { return 1; } else { return num * arguments.callee(num - 1); } } console.log(factorial(5)); var trueFactorial = factorial; factorial = function() { return 0; }; console.log(trueFactorial(5)); console.log(factorial(5)); ``` ## this ### 到底什么是 this > this 引用的是函数据以执行的环境对象 ——(当在网页的全局作用域中调用函数时, this 对象引用的就是 window ) > 当前发生事件的元素 > 调用函数之前, this 的值并不确定,因此 this 可能会在代码执行过程中引用不同的对象 ```javascript window.color = "red"; var obj = { color: "blue" }; function sayColor() { console.log(this.color); } sayColor(); window.sayColor(); window.alert("hello world"); obj.sayColor = sayColor; obj.sayColor(); ``` ### 函数的调用者(this)和函数的引用者(caller) ```javascript function outer() { inner(); } function inner() { console.log(inner.caller); } outer(); ``` 当然也可以使用`arguments.callee` ```javascript function outer() { inner(); } function inner() { console.log(arguments.callee.caller); } outer(); ``` > 注意`循环引用`会导致栈溢出 ```javascript function outer() { inner(); } function inner() { console.log(arguments.callee.caller()); } outer(); ``` # 函数的属性和方法 ## length > length 属性表示函数希望接收的命名参数的个数 > string.length > array.length ```javascript function sayName(name) { console.log(name); } function sum(num1, num2) { return num1 + num2; } function sayHi() { console.log("hi"); } console.log(sayName.length); console.log(sum.length); console.log(sayHi.length); ``` # 模拟块级作用域 什么是块级作用域? js 没有块级作用域会有什么结果? ```javascript var arr = [ "The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog" ]; for (var index = 0; index < arr.length; index++) { console.log(arr[index]); } console.log(index); ``` 不只是 js, php 和 python 都没有块级作用域 ## 解决方案 1. 函数是私有空间 ```javascript var arr = [ "The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog" ]; (function() { for (var i = 0; i < arr.length; i++) { console.log(arr[i]); } })(); console.log(i); ``` 2. let ```javascript var arr = [ "The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog" ]; for (let i = 0; i < arr.length; i++) { console.log(arr[i]); } console.log(i); ```