JavaScript 知识点

发布于 2021-01-07 15:04:46 字数 45029 浏览 1396 评论 0

一、什么是变量

从字面上看,变量是可变的量;从编程角度讲,变量是用于存储某种/某些数值的存储器。我们可以把变量看做一个盒子,为了区分盒子,可以用BOX1,BOX2等名称代表不同盒子,BOX1就是盒子的名字(也就是变量的名字)。

定义变量使用关键字var  var 变量名

变量名可以任意取名,但要遵循命名规则:

  • 1.变量必须使用字母、下划线(_)或者美元符($)开始。
  • 2.然后可以使用任意多个英文字母、数字、下划线(_)或者美元符($)组成。
  • 3.不能使用JavaScript关键词与JavaScript保留字。

变量要先声明再赋值(用 var 或 let 语句声明的变量,如果没有赋初始值,则其值为 undefined。)

var mychar; mychar="javascript"; var mynum = 6;

你可以使用 undefined 来判断变量是否已赋值.( 以下的代码中,变量input未被赋值,因而if条件语句的求值结果是true。)

var input; if(input === undefined){   doThis(); } else {   doThat();
}

undefined 值在布尔类型环境中会被当作 false。例如,下面的代码将会执行函数 myFunction,因为数组myArray中的元素未被赋值:

var myArray = [];
if (!myArray[0]) { myFunction();  }

数值类型环境中 undefined 值会被转换为 NaN。

 var a; // 计算为 NaN a + 2;

当你对一个 null 变量求值时,空值 null 在数值类型环境中会被当作0来对待,而布尔类型环境中会被当作 false。例如:

var n = null; typeof(n); // "object"
// The Null type has exactly one value, called null. console.log(n * 32);
// 0

变量可以重复赋值

var mychar; mychar="javascript"; mychar="hello";

注意:

  • 在JS中区分大小写,如变量mychar与myChar是不一样的,表示是两个变量。
  • 变量虽然也可以不声明,直接使用,但不规范,需要先声明,后使用。

变量的作用域

在所有函数之外声明的变量,叫做全局变量,因为它可被当前文档中的任何其他代码所访问。在函数内部声明的变量,叫做局部变量,因为它只能在该函数内部访问。

ECMAScript 6 之前的JavaScript没有 语句块 作用域;相反,语句块中声明的变量将成为语句块所在代码段的局部变量。例如,如下的代码将在控制台输出 5,因为 x 的作用域是声明了 x 的那个函数(或全局范围),而不是 if 语句块。

if (true) { var x = 5; }
console.log(x); // 5

如果使用 ECMAScript 6 中的 let 声明,上述行为将发生变化。

if (true) { let y = 5; } console.log(y);
// ReferenceError: y is not defined

变量的数据类型

  • 1、String: 字符串(文字序列)。 要表示变量的值是字符串,你必须将它们用引号包裹起来。
  • 2、Number: 数字。不用引号包围。
  • 3、Boolean: 布尔(逻辑)值。一个 True/False (真 / 假)值。 true/false 是 JS 里的特殊关键字,不需要引号。
  • 4、Object: 对象,基本上 JavaScript 里的任何东西都是对象,而且都可以被储存在变量里。将这个牢记于心。
  • Function (函数)
  • Array (数组)一种允许你存储多个值在一个引用里的结构。
  • Date (日期)
  • RegExp (正则表达式)
  • 5、Null (空)
  • 6、Undefined (未定义)
  • 7、Symbol (符合)(第六版新增)
  • 8、Error(错误)

二、什么是函数

函数是完成某个特定功能的一组语句。如没有函数,完成任务可能需要五行、十行、甚至更多的代码。这时我们就可以把完成特定功能的代码块放到一个函数里,直接调用这个函数,就省重复输入大量代码的麻烦。

基本语法

function定义函数的关键字。

函数调用:只需直接在需要的位置写函数就ok了

function add2(){   var sum = 3 + 2;   alert(sum); } add2();   // 函数调用

三、输出内容(document.write): 可用于直接向 HTML 输出流写内容。简单的说就是直接在网页中输出内容。

第一种:输出内容用""括起,直接输出""号内的内容。

<script type="text/javascript"> document.write("I love JavaScript!");
//内容用""括起来,""里的内容直接输出。 </script>

第二种:通过变量,输出内容

<script type="text/javascript"> var mystr="hello world!"; document.write(mystr);
//直接写变量名,输出变量存储的内容。
</script>

第三种:输出多项内容,内容之间用+号连接。

<script type="text/javascript"> var mystr="hello";
document.write(mystr+"I love JavaScript");
//多项内容之间用+号连接
</script>

第四种:输出HTML标签,并起作用,标签使用""括起来。

<script type="text/javascript"> var mystr="hello";
document.write(mystr+"<br>");
//输出hello后,输出一个换行符 document.write("JavaScript"); </script>

alert 输出内容,可以是字符串或变量,与 document.write 相似。

四、确认(confirm 消息对话框)

常用于允许用户做选择的动作,如:“你对吗?”等。弹出对话框(包括一个确定按钮和一个取消按钮)。

confirm(str);

  • str:在消息对话框中要显示的文本
  • 返回值: Boolean值:当用户点击"确定"按钮时,返回true;当用户点击"取消"按钮时,返回false

通过返回值可以判断用户点击了什么按钮

<script type="text/javascript"> var mymessage=confirm("你喜欢JavaScript吗?"); if(mymessage==true) {
  document.write("很好,加油!");
} else {
  document.write("JS功能强大,要学习噢!");
}
</script>

消息对话框是排它的,即用户在点击对话框按钮前,不能进行任何其它操作

五、提问(prompt 消息对话框)

prompt 弹出消息对话框,通常用于询问一些需要与用户交互的信息。弹出消息对话框(包含一个确定按钮、取消按钮与一个文本输入框)。

prompt(str1, str2);
  • str1: 要显示在消息对话框中的文本,不可修改
  • str2:文本框中的内容,可以修改

返回值:

  • 点击确定按钮,文本框中的内容将作为函数返回值
  • 点击取消按钮,将返回null
var myname=prompt("请输入你的姓名:"); if(myname!=null) {
  alert("你好"+myname);
} else {
  alert("你好 my friend.");
}

注:在用户点击对话框的按钮前,不能进行任何其它操作。

六、打开新窗口(window.open)

open() 方法可以查找一个已经存在或者新建的浏览器窗口。

window.open([URL], [窗口名称], [参数字符串])

  • URL:可选参数,在窗口中要显示网页的网址或路径。如果省略这个参数,或者它的值是空字符串,那么窗口就不显示任何文档。
  • 窗口名称:可选参数,被打开窗口的名称。
    • 1.该名称由字母、数字和下划线字符组成。
    • 2."_top"、"_blank"、"_self"具有特殊意义的名称。_blank:在新窗口显示目标网页。 _self:在当前窗口显示目标网页。 _top:框架网页中在上部窗口中显示目标网页。
    • 3.相同 name 的窗口只能创建一个,要想创建多个窗口则 name 不能相同。
    • 4.name 不能包含有空格。
  • 参数字符串:可选参数,设置窗口参数,各参数用逗号隔开。(top,left,width,height,menubar,toolbar,scrollbars,status)

例如:打开 http://www.imooc.com网站,大小为300px * 200px,无菜单,无工具栏,无状态栏,有滚动条窗口:

<script type="text/javascript">
window.open('http://www.imooc.com','_blank','width=300,height=200,menubar=no,toolbar=no,
status=no,scrollbars=yes')
</script>

七、关闭窗口(window.close)

  • window.close(); //关闭本窗口
  • <窗口对象>.close(); //关闭指定的窗口
  • 例如:关闭新建的窗口。

<script type="text/javascript"> var mywin=window.open('http://www.imooc.com'); //将新打的窗口对象,存储在变量mywin中 mywin.close(); </script>

  • 注意:上面代码在打开新窗口的同时,关闭该窗口,看不到被打开的窗口。

八、DOM

  • 文档对象模型DOM(Document Object Model)定义访问和处理HTML文档的标准方法。DOM 将HTML文档呈现为带有元素、属性和文本的树结构(节点树)。
  • HTML文档可以说由节点构成的集合,三种常见的DOM节点:
      1. 元素节点:上图中<html>、<body>、<p>等都是元素节点,即标签。
      1. 文本节点:向用户展示的内容,如<li>...</li>中的JavaScript、DOM、CSS等文本.
      1. 属性节点:元素属性,如标签的链接属性href="http://www.imooc.com"。

1、通过ID获取元素

  • document.getElementById(“id”)
  • 注:获取的元素是一个对象,如想对元素进行操作,我们要通过它的属性或方法。

<p id="con">JavaScript</p> <script type="text/javascript"> var mychar=document.getElementById("con"); document.write("结果:"+mychar); //输出获取的P标签。 </script>

  • 结果:null或[object HTMLParagraphElement]

2、innerHTML 属性

  • innerHTML 属性用于获取或替换 HTML 元素的内容。
  • Object.innerHTML
    • 1.Object是获取的元素对象,如通过document.getElementById("ID")获取的元素。
    • 2.注意书写,innerHTML区分大小写。

<script type="text/javascript"> var mychar=document.getElementById("con") ; document.write("原标题:"+mychar.innerHTML+"<br>"); //输出原h2标签内容 mychar.innerHTML = 'Hello World!' document.write("修改后的标题:"+mychar.innerHTML); //输出修改后h2标签内容 </script>

3、改变 HTML 样式

  • Object.style.property=new style;
  • 注意:Object是获取的元素对象,如通过document.getElementById("id")获取的元素。
  • <h2 id="con">I love JavaScript</H2> <p> JavaScript使网页显示动态效果并实现与用户交互功能。</p> <script type="text/javascript"> var mychar= document.getElementById("con"); mychar.style.color = "red"; mychar.style.backgroundColor = "#ccc"; mychar.style.width = "300px"; </script>

4、显示和隐藏(display属性)

  • Object.style.display = value
  • 注意:Object是获取的元素对象,如通过document.getElementById("id")获取的元素。

<script type="text/javascript"> function hidetext() { var mychar = document.getElementById("con"); mychar.style.display="none"; } function showtext() { var mychar = document.getElementById("con"); mychar.style.display="block"; } </script>

5、控制类名(className 属性)

  • className 属性设置或返回元素的class 属性。
  • object.className = classname
    • 1.获取元素的class 属性
      1. 为网页内的某个元素指定一个css样式来更改该元素的外观

<p id="p1" > JavaScript使网页显示动态效果并实现与用户交互功能。</p> <input type="button" value="添加样式" onclick="add()"/> <p id="p2" class="one">JavaScript使网页显示动态效果并实现与用户交互功能。</p> <input type="button" value="更改外观" onclick="modify()"/>

`<script type="text/javascript">`
   `function add(){`
      `var p1 = document.getElementById("p1");`
      `p1.className = 'one';`
   `}`
   `function modify(){`
      `var p2 = document.getElementById("p2");`
      `p2.className = 'two';`
   `}`
`</script>`

九、运算符

相等: ===

  • 它将测试两个值是否相等,而且会返回一个 true/false (布尔型)值。

非,不等:! 、 !=

  • 经常与相等运算一起使用,非运算符在JS中表示逻辑非——它也返回一个布尔值。
  • 原本的值是 true ,但是返回了 false 因为之后我们做了非运算:var myVariable = 3;!myVariable === 3; // false
  • 这里我们测试了" myVariable 是否等于 3"。这里返回了 false ,因为它等于 3。var myVariable = 3; myVariable !== 3; // false

十、字符串

1、检索特定字符串字符

  • 可以使用方括号符号返回字符串中的任何字符:如: var browserType = 'mozilla'; browserType[0]; // m
  • 检索任何字符串的最后一个字符: browserType[browserType.length-1];

2、在字符串中查找子字符串并提取它

  • browserType.indexOf('zilla'); // 2
  • browserType.indexOf('vanilla'); // -1(在主字符串中找不到子字符串)
  • 使用它来查找不包含子串“mozilla”的所有字符串实例,或者如果使用否定运算符,请执行以下操作if(browserType.indexOf('mozilla') !== -1) { // do stuff with the string }
  • 当你知道字符串中的子字符串开始的位置,以及想要结束的字符时,slice()可以用来提取它。第一个参数是开始提取的字符位置,第二个参数是提取的最后一个字符后一位置browserType.slice(0,3); // moz
  • 在某个字符之后提取字符串中的所有剩余字符,则不必包含第二个参数,而只需要包含要从中提取的字符位置 字符串中的其余字符browserType.slice(2); // zilla

3、转换大小写

var radData = 'My NaMe Is MuD'; radData.toLowerCase(); // 转换成小写 radData.toUpperCase(); // 转换成大写

4、替换字符串的某部分

  • 使用replace()方法将字符串中的一个子字符串替换为另一个子字符串
  • 需要两个参数 - 要被替换下的字符串和要被替换上的字符串
  • 注意,想要真正更新browserType变量的值反应在真实程序里,您需要设置变量的值等于刚才的操作结果;它不会自动更新子串的值。所以事实上你需要这样写:browserType = browserType.replace('moz','van');

十一、数组

  • 可以将数组中的任何项目存储在数组中 - 字符串,数字,对象,另一个变量,甚至另一个数组,也可以混合和匹配项目类型。
  • var random = ['tree', 795, [0, 1, 2]];

1、访问和修改数组项

  • 使用括号表示法访问数组中的各个项目,方式与访问字符串中的字母相同

var shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles']; shopping; shopping[0]; // returns "bread"

  • 还可以通过简单地向单个数组项提供新值来修改数组中的项目。

shopping[0] = 'tahini'; shopping; // shopping will now return [ "tahini", "milk", "cheese", "hummus", "noodles" ]

  • 请注意,数组中的数组称为多维数组。 您可以通过将两组方括号链接在一起来访问数组内的另一个数组。
    • 例如,要访问数组中的一个作为随机数组内的第三个项目的内容.
    • var random = ['tree', 795, [0, 1, 2]]; random[2][2]; // return 2(访问数组中的第三个项目,然后再访问第三个项目中的第三个项目)

2、字符串和数组之间的转换

  • split():会看到一个包含在一个长长的字符串中的原始数据,您可能希望将有用的项目分成更有用的表单,然后对它们进行处理,例如将它们显示在数据表中。在其最简单的形式中,这需要一个参数,您要将字符串分隔的字符,并返回分隔符之间的子串,作为数组中的项 var myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle'; var myArray = myData.split(','); // 用每个逗号分隔它 return: Manchester,London,Liverpool,Birmingham,Leeds,Carlisle myArray; myArray[0]; // the first item in the array myArray[myArray.length-1]; // the last item in the array
  • 也可以使用join()方法进行相反的操作

var myNewString = myArray.join(','); return: Manchester,London,Liverpool,Birmingham,Leeds,Carlisle myNewString;

  • 数组转换为字符串:toString()
    • toString()可以比join()更简单,因为它不需要一个参数,但更有限制。 使用join()可以指定不同的分隔符

3、添加和删除数组项

  • push() :需要添加一个或多个要添加到数组末尾的项目

myArray.push('Cardiff'); myArray; myArray.push('Bradford', 'Brighton'); myArray; var newLength = myArray.push('Bristol');

  • 数组中删除最后一个项目就像在其上运行pop()一样简单 myArray.pop(); var removedItem = myArray.pop();
  • unshift()shift()以完全相同的方式工作,只是它们分别作用于数组的开始处,而不是结尾处。
  • unshift(): 在数组的开始增加一个元素
  • shift(): 删除数组的第一个元素

myArray.unshift('Edinburgh'); myArray;

var removedItem = myArray.shift(); myArray; removedItem;

十二、条件语句

1、if ... else 语句

if (condition) { code to run if condition is true } else { run some other code instead }

  • 要测试的条件,放到括号里(通常是“这个值大于另一个值吗”或者“这个值存在吗”)。这个条件会利用比较运算符进行比较,并且返回true或者 false。
  • 如果(if)条件(condition)返回true,运行代码A,否则(else)运行代码B
  • 注意:你不一定需要else和第二个花括号——下面的代码也是符合语法规则的: if (condition) { code to run if condition is true }

run some other code

  • 不过,这里你需要注意——在这种情况下,第二段代码不被条件语句控制,所以它总会运行,不管条件返回的是true还是false。这不一定是一件坏事,但这可能不是你想要的——你经常只想要运行一段代码或者另一段,而不是两个都运行。

2、比较运算符

  • === and !== — 判断一个值是否严格等于,或不等于另一个。
  • < and > — 判断一个值是否小于,或大于另一个。
  • <= and >= — 判断一个值是否小于或等于,或者大于或等于另一个。
  • 我们想特别提到测试布尔值(true / false),和一个通用模式,你会频繁遇到它,任何不是 false, undefined, null, 0, NaN 的值,或一个空字符串('')在作为条件语句进行测试时实际返回true,因此您可以简单地使用变量名称来测试它是否为真,甚至是否存在(即它不是未定义的)。例如:
  • var cheese = 'Cheddar'; if (cheese) { console.log('Yay! Cheese available for making cheese on toast.'); } else { console.log('No cheese on toast for you today.'); }
  • var shoppingDone = false; if (shoppingDone) { // don't need to explicitly specify '=== true' var childsAllowance = 10; } else { var childsAllowance = 5; }

3、嵌套if ... else

  • if (choice === 'sunny') { if (temperature < 86) { para.textContent = 'It is ' + temperature + ' degrees outside —
    nice and sunny. Let\'s go out to the beach, or the park, and get an ice
    cream.';
    } else if (temperature >= 86) { para.textContent = 'It is ' + temperature + ' degrees outside —
    REALLY HOT! If you want to go outside, make sure to put some suncream
    on.';
    } }

4、逻辑运算符:AND,OR和NOT

  • 如果要测试多个条件,而不需要编写嵌套if ... else语句,逻辑运算符可以帮助您。当在条件下使用时,前两个执行以下操作:
  • && — 逻辑与; 使得并列两个或者更多的表达式成为可能,只有当这些表达式每一个都返回true时,整个表达式才会返回true.
  • || — 逻辑或; 当两个或者更多表达式当中的任何一个返回 true 则整个表达式将会返回 true.
  • if (choice === 'sunny' && temperature < 86) { para.textContent = 'It is ' + temperature + ' degrees outside —
    nice and sunny. Let\'s go out to the beach, or the park, and get an ice
    cream.';
    } else if (choice === 'sunny' && temperature >= 86) { para.textContent = 'It is ' + temperature + ' degrees outside —
    REALLY HOT! If you want to go outside, make sure to put some suncream
    on.';
    }
  • 让我们快速看一个OR的例子: if (iceCreamVanOutside || houseStatus === 'on fire') { console.log('You should leave the house quickly.'); } else { console.log('Probably should just stay in then.'); }
  • 逻辑运算符的最后一个, NOT, 用 ! 运算符表示, 可以用于对一个表达式取否. 让我们把NOT结合上一个例子里的OR看看: if (!(iceCreamVanOutside || houseStatus === 'on fire')) { console.log('Probably should just stay in then.'); } else { console.log('You should leave the house quickly.'); }
    • 在这一段代码中,如果OR所在的语句返回 true,则NOT运算符将会将其取否,于是整个表达式的返回值将会是false。
  • 您可以在任何结构中随意合并很多个逻辑表达式。接下来的例子将会只在OR两边的语句同时返回true时才会执行代码,这也就意味着整个AND语句将会返回true: if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === 'Steve')) { // run the code }
  • 在条件语句中运用OR逻辑运算符最常见的错误是尝试声明变量后,仅检查该变量一次的情况下赋予很多个都会返回true的值,不同的值之间用 || (OR)运算符分隔。比如:
    • 错误演示: if (x === 5 || 7 || 10 || 20) { // run my code }
    • 在这个例子里 if(...) 里的条件总为真,因为 7 (或者其它非零的数) 的值总是为真. 这个条件实际意思是 "如果x等于5, 或者7为真 — 它总是成立的". 这不是我们想要的逻辑,为了 让它正常工作你必须指定每个OR表达式两边都是完整的检查:

if (x === 5 || x === 7 || x === 10 ||x === 20) { // run my code }

5、switch语句

switch (expression) { case choice1: run this code break;

case choice2: run this code instead break;

// include as many cases as you like

default: actually, just run this code }

6、三元运算符

  • 用于测试一个条件,并返回一个值/表达,如果它是true,另一个是false-这种情况下是有用的,并且可以占用比if...else块较少的代码块。如果你只有两个通过true/ false条件选择。 ( condition ) ? run this code : run this code instead var greeting = ( isBirthday ) ? 'Happy birthday Mrs. Smith — we hope you have a great day!' : 'Good morning Mrs. Smith.';
  • 在这里我们有一个变量叫做isBirthday- 如果它是true,我们给客人一个生日快乐的消息; 如果不是,我们给她标准的每日问候。
  • 你不需要用三元运算符设置变量值; 你也可以运行任何你喜欢的函数或代码行。以下实例显示了一个简单的主题选择器,其中该站点的样式应用了三元运算符。 <label for="theme">Select theme: </label> <select id="theme"> <option value="white">White</option> <option value="black">Black</option> </select>

<h1>This is my website</h1> var select = document.querySelector('select'); var html = document.querySelector('html'); document.body.style.padding = '10px';

function update(bgColor, textColor) { html.style.backgroundColor = bgColor; html.style.color = textColor; }

select.onchange = function() { ( select.value === 'black' ) ? update('black','white') : update('white','black'); }

  • 如果这返回true,我们运行update()带有黑色和白色参数的函数,这意味着我们最终得到黑色的背景颜色和白色的文字颜色。如果返回false,我们运行update()带有白色和黑色参数的函数,这意味着站点颜色被反转。

7、 一个简单的日历

  `<div class="output" style="height: 500px;overflow: auto;">`
        `<label for="month">Select month: </label>`
        `<select id="month">`
            `<option value="January">January</option>`
            `<option value="February">February</option>`
            `<option value="March">March</option>`
            `<option value="April">April</option>`
            `<option value="May">May</option>`
            `<option value="June">June</option>`
            `<option value="July">July</option>`
            `<option value="August">August</option>`
            `<option value="September">September</option>`
            `<option value="October">October</option>`
            `<option value="November">November</option>`
            `<option value="December">December</option>`
        `</select>`

        `<h1></h1>`

        `<ul></ul>`
    `</div>`
    
    `<script type="text/javascript">`
        `var select = document.querySelector('select');`
        `var list = document.querySelector('ul');`
        `var h1 = document.querySelector('h1');`

        `select.onchange = function(){`
            `var choice = select.value;`
            `var days = 31;`
            `if(choice === 'February'){`
                `days = 28;`
            `} else if(choice === 'April' ||  choice === 'June' || choice === 'September'|| choice === 'November'){`
                `days = 30;`
            `}`
            `createCalendar(days, choice);`
        `}`

        `function createCalendar(days, choice){`
            `list.innerHTML = '';`
            `h1.textContent = choice;`
            `for(var i = 1; i <= days; i++){`
                `var listItem = document.createElement('li');`
                `listItem.textContent = i;`
                `list.appendChild(listItem);`
            `}`
        `};`
        `createCalendar(31,'January');`
    `</script>`

十三、循环

1、for (initializer; exit-condition; final-expression) {

// code to run }

var cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin']; var info = 'My cats are called '; var para = document.querySelector('p');

for (var i = 0; i < cats.length; i++) { info += cats[i] + ', '; }

para.textContent = info;

  • 输出:My cats are called Bill, Jeff, Pete, Biggles, Jasmin,
  • 理想情况下,我们想改变最后循环迭代中的连接,以便在句子末尾没有逗号。 for (var i = 0; i < cats.length; i++) { if (i === cats.length - 1) { info += 'and ' + cats[i] + '.'; } else { info += cats[i] + ', '; } }

2、使用break退出循环

  • 如果要在所有迭代完成之前退出循环,可以使用break语句。 <label for="search">Search by contact name: </label> <input id="search" type="text"> <button>Search</button>

<p></p> var contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975']; var para = document.querySelector('p'); var input = document.querySelector('input'); var btn = document.querySelector('button');

`btn.addEventListener('click',function(){`
    `// 我们将输入的值输入到一个名为searchName的变量中,然后清空文本输入并重新对准它,准备进行下一个搜索`
    `var searchName = input.value;`
    `input.value = '';`
    `input.focus();`

    `for( var i = 0; i < contacts.length; i++){`
        `// 将当前联系人(contacts [i])拆分为冒号字符,并将生成的两个值存储在名为splitContact的数组中`
        `var splitContact = contacts[i].split(':');`
        `// 使用条件语句来测试splitContact [0](联系人姓名)是否等于输入的searchName。 如果是,我们在段落中输入一个字符串来报告联系人的号码,并使用break来结束循环`
        `// 在(contacts.length-1) 迭代后,如果联系人姓名与输入的搜索不符,则段落文本设置为“未找到联系人”,循环继续迭代。`
        `if(splitContact[0] === searchName){`
            `para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.';`
            `break;`
        `} else {`
            `para.textContent = 'Contact not found.';`
        `}`
    `}`

`}) `

3、使用continue跳过迭代

var para = document.querySelector('p'); var input = document.querySelector('input'); var btn = document.querySelector('button');

`var num  = input.value;`

`for(var i = 1; i <= num; i++){`
    `var sqRoot = Math.sqrt(i); `
    `// 用Math.sqrt(i)找到每个数字的平方根,然后通过测试平方根是否是一个整数,当它被四舍五入到最接近的整数时,它是否与自身相同(这是Math.floor(...)对传递的数字是什么)`
    `if( Math.floor(sqRoot) !== sqRoot){`
        `continue;`
    `}`
`// 如果平方根和四舍五入的平方根不相等(!==),则表示平方根不是整数,因此我们对此不感兴趣。 在这种情况下,我们使用continue语句跳过下一个循环迭代,而不在任何地方记录该数字。`
     `para.textContent += i + ' ';`
    `// 如果平方根是一个整数,我们完全跳过if块,所以continue语句不被执行; 相反,我们将当前i值加上一个空格连接到段落内容的末尾`
`}`

4、while语句和do ... while语句

  • while循环 -initializer while (exit-condition) { // code to runfinal-expression }

-var i = 0;

while (i < cats.length) { if (i === cats.length - 1) { info += 'and ' + cats[i] + '.'; } else { info += cats[i] + ', '; }

i++; }

  • do...while循环非常类似但在while后提供了终止条件: -initializer do { // code to runfinal-expression } while (exit-condition)

-var i = 0;

do { if (i === cats.length - 1) { info += 'and ' + cats[i] + '.'; } else { info += cats[i] + ', '; }

i++; } while (i < cats.length);

5、启动倒计时

// 方法一: // var i = 10; // 初始化 // while ( i >= 0){ // 退出条件 // var para = document.createElement('p');

        `//     if( i === 10 ){`
        `//        para.textContent = 'Countdown' + i;`

        `//     } else if( i === 0 ){`
        `//         para.textContent = 'Blast off!';`
        `//     } else{`
        `//         para.textContent = i;`
        `//     }`
        `//     output.appendChild(para);`
        `//     i--;  `
        `//     // 在循环中的代码运行(迭代已经完成)之后,运行最后的条件,这只有在尚未达到退出条件时才会发生`
        `// }`
       
       `// 方法二:`
        `// for(var i = 10; i >= 0; i--){`
        `//     var para = document.createElement('p');  `
        `//     if( i === 10){`
        `//         para.textContent = 'Countdown' + i;`
        `//     }else if( i === 0 ){`
        `//         para.textContent = 'Blast off!';`
        `//     } else{`
        `//         para.textContent = i;`
        `//     }`
        `//     output.appendChild(para);`
        `// }`
        

        `// 方法三:`
        `var i = 10;`
        `do {  `
        `// 花括号中的代码总是在检查之前运行一次,以查看是否应该再次执行(在while和for中,检查首先出现,因此代码可能永远不会执行)。`
            `var para = document.createElement('p');  `
            `if( i === 10){`
                `para.textContent = 'Countdown' + i;`
            `}else if( i === 0 ){`
                `para.textContent = 'Blast off!';`
            `} else{`
                `para.textContent = i;`
            `}`
            `output.appendChild(para);`
            `i--;`
        `} while( i >= 0 );`

6、填写来宾列表

var people = ['Chris', 'Anne', 'Colin', 'Terri', 'Phil', 'Lola', 'Sam', 'Kay', 'Bruce']; var admitted = document.querySelector('.admitted'); var refused = document.querySelector('.refused'); admitted.textContent = 'Admit: '; refused.textContent = 'Refused: ';

        `var i = 0;`
        `while( i < people.length){`
            `if( people[i] === 'Phil' || people[i] === 'Lola'){`
                `refused.textContent += people[i] + ', ';`
            `} else {`
                `admitted.textContent += people[i] + ', ';`
            `}`
            `i++;`
        `}`

        `refused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + '.';`
        `admitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + '.';`

十四、函数

1、浏览器内置函数

  • JavaScript有许多内置的函数,可以让您做很多有用的事情,而无需自己编写所有的代码。事实上, 许多你调用(运行或者执行的专业词语)浏览器内置函数时调用的代码并不是使用JavaScript来编写——大多数调用浏览器后台的函数的代码,是使用像C++这样更低级的系统语言编写的,而不是像JavaScript这样的web编程语言。

2、函数与方法

  • 严格说来,内置浏览器函数并不是函数——它们是方法。函数和方法在很大程度上是可互换的.
  • 二者区别在于方法是在对象内定义的函数。内置浏览器功能(方法)和变量(称为属性)存储在结构化对象内,以使代码更加高效,易于处理。

3、自定义函数

  • 自定义名称后面都带有括号,那么您使用的是自定义函数.

function draw() { ctx.clearRect(0,0,WIDTH,HEIGHT); for (var i = 0; i < 100; i++) { ctx.beginPath(); ctx.fillStyle = 'rgba(255,0,0,0.5)'; ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); ctx.fill(); } }

  • 该函数在元素中绘制100个随机圆。每次我们想要这样做,我们可以使用这个函数来调用这个功能 draw();
  • 函数可以从内部函数调用其他函数。
    • 以上函数例如调用random()函数三次,由以下代码定义:
    • function random(number) { return Math.floor(Math.random()*number); }
    • 我们需要这个函数,因为浏览器的内置Math.random()函数只生成一个0到1之间的随机十进制数。我们想要一个0到一个指定数字之间的随机整数。

4、调用函数

  • 通过将函数名包含在代码的某个地方,后跟圆括号来完成的 function myFunction() { alert('hello'); }

myFunction() // calls the function once

5、匿名函数

  • 没有函数名,不会自己做任何事情,通常使用匿名函数以及事件处理程序。
  • 例如,如果单击相关按钮,以下操作将在函数内运行代码: var myButton = document.querySelector('button');myButton.onclick = function() { alert('hello'); }
  • 还可以将匿名函数分配为变量的值。 var myGreeting = function() { alert('hello'); } myGreeting();
  • 有效地给变量一个名字;还可以将该函数分配为多个变量的值,例如: var anotherGreeting = function() { alert('hello'); } anotherGreeting();
    • 但这只会令人费解,所以不要这样做!创建功能时,最好只要坚持下列形式: function myGreeting() { alert('hello'); }
  • 您将主要使用匿名函数来运行负载的代码以响应事件触发(如点击按钮) - 使用事件处理程序。再次,这看起来像这样: myButton.onclick = function() { alert('hello'); // I can put as much code // inside here as I want }
  • 匿名函数也称为函数表达式。函数表达式与函数声明有一些区别。函数声明会进行声明提升(declaration hoisting),而函数表达式不会。

6、函数参数

  • 一些函数需要在调用它们时指定参数 - 这些值需要包含在函数括号内,它需要正确地完成其工作。
  • 参数有时称为参数,属性(properties)或甚至属性(attributes)
    • 例如,浏览器的内置Math.random()函数不需要任何参数。当被调用时,它总是返回0到1之间的随机数: var myNumber = Math.random();
    • 浏览器的内置字符串replace()函数需要两个参数:在主字符串中查找的子字符串,以及用以下替换该字符串的子字符串: var myText = 'I am a string'; var newString = myText.replace('string', 'sausage');
  • 当您需要指定多个参数时,它们以逗号分隔。
  • 还应该注意,有时参数是可选的 - 您不必指定它们。如果没有,该功能一般会采用某种默认行为。作为示例,数组join()函数的参数是可选的:

var myArray = ['I', 'love', 'chocolate', 'frogs']; var madeAString = myArray.join(' '); // returns 'I love chocolate frogs' var madeAString = myArray.join(); // returns 'I,love,chocolate,frogs'

  • 如果没有包含参数来指定加入/分隔符,默认情况下会使用逗号

7、函数作用域(scope)和冲突

  • 创建一个函数时,函数内定义的变量和其他东西都在它们自己的单独的范围内, 意味着它们被锁在自己独立的隔间中, 不能从函数外代码其它函数内访问。
  • 所有函数的最外层被称为全局作用域。 在全局作用域内定义的值可以在任意地方访问。

8、函数内部的函数

function myBigFunction() { var myValue;

subFunction1(); subFunction2(); subFunction3(); }

function subFunction1() { console.log(myValue); }

function subFunction2() { console.log(myValue); }

function subFunction3() { console.log(myValue); }

  • 只需确保在函数内使用的值正确的范围. 上面的例子会抛出一个错误ReferenceError:MyValue没有被定义,因为myValue变量与函数调用的范围相同, 函数定义内没有定义 - 调用函数时运行的实际代码。为了使这个工作,你必须将值作为参数传递给函数,如下所示: function myBigFunction() { var myValue = 1;subFunction1(myValue); subFunction2(myValue); subFunction3(myValue); }

function subFunction1(value) { console.log(value); }

function subFunction2(value) { console.log(value); }

function subFunction3(value) { console.log(value); }

十五、事件

  • 在编程时系统内的发生的动作或者发生的事情— 系统会在事件出现的时候触发某种信号并且会提供一个自动加载某种动作(列如:运行一些代码)的机制,比如在一个机场,当一架将起飞的飞机的跑道清理完成后,飞行员会收到一个信号,结果是他们开始起飞。
  • 在Web中, 事件在浏览器窗口中被触发并且通常被绑定到窗口内部的特定部分 — 可能是一个元素、一系列元素、被加载到这个窗口的 HTML 代码或者是整个浏览器窗口。
  • 每个可用的事件都会有一个事件处理器(事件监听器),也就是事件触发时会运行的代码块。
  • 当我们定义了一个用来回应事件被激发的代码块的时候,我们说我们注册了一个事件处理器
  • 网络事件不是 JavaScript 语言的核心——它们被定义成内置于浏览器的JavaScript APIs。

1、使用网页事件的方式

  • 事件处理器属性(存在于事件处理程序过程的属性中) var btn = document.querySelector('button');

btn.onclick = function() { var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; document.body.style.backgroundColor = rndCol; }

  • 这个 onclick 是被用在这个情景下的事件处理器的属性,它就像 button 其他的属性(如 btn.textContent, or btn.style), 但是有一个特别的地方——当您将一些代码赋值给它的时候,只要事件触发代码就会运行。
  • 也可以将一个有名字的函数赋值给事件处理参数 var btn = document.querySelector('button');

function bgChange() { var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; document.body.style.backgroundColor = rndCol; }

btn.onclick = bgChange;

  • 行内事件处理器 - 请勿使用(注释: 将您的编程逻辑与内容分离也会使您的站点对搜索引擎更加友好。) <button onclick="bgChange()">Press me</button> function bgChange() { var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; document.body.style.backgroundColor = rndCol; }

2、addEventListener()和removeEventListener()

  • 这个函数和事件处理属性是类似的,但是语法略有不同 var btn = document.querySelector('button');

function bgChange() { var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; document.body.style.backgroundColor = rndCol; }

btn.addEventListener('click', bgChange);

  • 在addEventListener() 函数中, 我们具体化了两个参数——我们想要将处理器应用上去的事件名称,和包含我们用来回应事件的函数的代码。注意将这些代码全部放到一个匿名函数中是可行的: btn.addEventListener('click', function() { var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; document.body.style.backgroundColor = rndCol; });
  • 这个机制带来了一些相较于旧方式的优点。有一个相对应的方法,removeEventListener(),这个方法移除事件监听器。例如,下面的代码将会移除上个代码块中的事件监听器: btn.removeEventListener('click', bgChange);
    • 这在简单个的、小型的项目中可能不是很有用,但是在大型的、复杂的项目中就非常有用了,可以非常高效地清除不用的事件处理器,另外在其他的一些场景中也非常有效——比如您需要在不同环境下运行不同的事件处理器,您只需要恰当地删除或者添加事件处理器即可
  • 您也可以给同一个监听器注册多个处理器,下面这种方式不能实现这一点:

myElement.onclick = functionA; myElement.onclick = functionB;

  • 第二行会覆盖第一行,但是下面这种方式就会正常工作了:

myElement.addEventListener('click', functionA); myElement.addEventListener('click', functionB);

  • 当元素被点击时两个函数都会工作:

3、 我该使用哪种机制?

  • 第三种机制(DOM Level 2 Events (addEventListener(), etc.))的主要优点是,如果需要的话,可以使用removeEventListener()删除事件处理程序代码,而且如果有需要,您可以向同一类型的元素添加多个监听器。例如,您可以在一个元素上多次调用,addEventListener('click', function() { ... }),并可在第二个参数中指定不同的函数。对于事件处理程序属性来说,这是不可能的,因为后面任何设置的属性都会尝试覆盖较早的属性。

4、其他事件概念

事件对象:有时候在事件处理函数内部,您可能会看到一个固定指定名称的参数,例如event,evt或简单的e。 这被称为事件对象,它被自动传递给事件处理函数,以提供额外的功能和信息。

function bgChange(e) {
    var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
    e.target.style.backgroundColor = rndCol;
    console.log(e);
}
btn.addEventListener('click', bgChange);

在这里,您可以看到我们在函数中包括一个事件对象,e,并在函数中设置背景颜色样式在e.target上 - 它指的是按钮本身。 事件对象 e 的target属性始终是事件刚刚发生的元素的引用。 所以在这个例子中,我们在按钮上设置一个随机的背景颜色,而不是页面。

当您要在多个元素上设置相同的事件处理程序时,e.target非常有用,并且在发生事件时对所有元素执行某些操作.

例如,你可能有一组16块方格,当它们被点击时就会消失。用e.target总是能准确选择当前操作的东西(方格)并执行操作让它消失,而不是必须以更困难的方式选择它。

    • 我们使用JavaScript创建了16个元素。接着我们使用 document.querySelectorAll()选择全部的元素,然后遍历每一个,为每一个元素都添加一个onclick单击事件,每当它们点击时就会为背景添加一个随机颜色。
    • var divs = document.querySelectorAll('div');
      for (var i = 0; i < divs.length; i++) {
          divs[i].onclick = function(e) {
              e.target.style.backgroundColor = bgChange();
          }
      }
    • 完整代码
<script>
for (var i = 1; i <= 16; i++) {
    var myDiv = document.createElement('div');
    document.body.appendChild(myDiv);
  }
  function random(number) {
    return Math.floor(Math.random() * number);
  }
  function bgChange() {
    var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
    return rndCol;
  }
  var divs = document.querySelectorAll('div');
  for (var i = 0; i < divs.length; i++) {
    divs[i].onclick = function(e) {
      e.target.style.backgroundColor = bgChange();
    }
  }
</script>

阻止默认行为

    • 最常见的例子是Web表单,例如自定义注册表单。 当你填写详细信息并按提交按钮时,自然行为是将数据提交到服务器上的指定页面进行处理,并将浏览器重定向到某种“成功消息”页面(或 相同的页面,如果另一个没有指定。)
    • 当用户没有正确提交数据时,麻烦就来了 - 作为开发人员,你希望停止提交信息给服务器,并给他们一个错误提示,告诉他们什么做错了,以及需要做些什么来修正错误。 一些浏览器支持自动的表单数据验证功能,但由于许多浏览器不支持,因此建议你不要依赖这些功能,并实现自己的验证检查。 我们来看一个简单的例子。

<form> <div> <label for="fname">First name: </label> <input id="fname" type="text"> </div> <div> <label for="lname">Last name: </label> <input id="lname" type="text"> </div> <div> <input id="submit" type="submit"> </div> </form> <p></p>

  • 这里我们用一个onsubmit事件处理程序(在提交的时候,在一个表单上发起submit事件)来实现一个非常简单的检查,用于测试文本字段是否为空。 如果是,我们在事件对象上调用preventDefault()函数,这样就停止了表单提交,然后在我们表单下面的段落中显示一条错误消息,告诉用户什么是错误的:

var form = document.querySelector('form'); var fname = document.getElementById('fname'); var lname = document.getElementById('lname'); var submit = document.getElementById('submit'); var para = document.querySelector('p');

form.onsubmit = function(e) { if (fname.value === '' || lname.value === '') { e.preventDefault(); para.textContent = 'You need to fill in both names!'; } }

  • 显然,这是一种非常弱的表单验证——例如,用户输入空格或数字提交表单,表单验证并不会阻止用户提交——这不是我们例子想要达到的目的。
  • 事件冒泡及捕获

5、事件冒泡及捕获

事件冒泡和捕捉是两种机制,主要描述当在一个元素上有两个相同类型的事件处理器被激活会发生什么。

比如有个父元素的事件(比如点击隐藏),然后 子元素是(点击播放), 当点击播放的时候,也会触发了隐藏事件。要解决的话 可以在子元素的事件里加上 stopPropagation()来解决。

在现代浏览器中,默认情况下,所有事件处理程序都在冒泡阶段进行注册。因此,在我们当前的示例中,当您单击视频时,这个单击事件从 元素向外冒泡直到元素。沿着这个事件冒泡线路:

  • 它发现了video.onclick...事件处理器并且运行它,因此这个视频第一次开始播放。
  • 接着它发现了(往外冒泡找到的) videoBox.onclick...事件处理器并且运行它,因此这个视频也隐藏起来了。

1、对事件冒泡和捕捉的解释

当一个事件发生在具有父元素的元素上(例如,在我们的例子中是元素)时,现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。 在捕获阶段:

  • 浏览器检查元素的最外层祖先,是否在捕获阶段中注册了一个onclick事件处理程序,如果是,则运行它。
  • 然后,它移动到中的下一个元素,并执行相同的操作,然后是下一个元素,依此类推,直到到达实际点击的元素。

在冒泡阶段,恰恰相反:

  • 浏览器检查实际点击的元素是否在冒泡阶段中注册了一个onclick事件处理程序,如果是,则运行它。
  • 然后它移动到下一个直接的祖先元素,并做同样的事情,然后是下一个,等等,直到它到达元素。

2、用 stopPropagation() 修复问题

  • 标准事件对象具有可用的名为 stopPropagation()的函数, 当在事件对象上调用该函数时,它只会让当前事件处理程序运行,但事件不会在冒泡链上进一步扩大,因此将不会有更多事件处理器被运行(不会向上冒泡)。
  • 所以,我们可以通过改变前面代码块中的第二个处理函数来解决当前的问题: video.onclick = function(e) { e.stopPropagation(); video.play(); };
  • 注解: 为什么我们要弄清楚捕捉和冒泡呢?那是因为,在过去糟糕的日子里,浏览器的兼容性比现在要小得多,Netscape(网景)只使用事件捕获,而Internet Explorer只使用事件冒泡。当W3C决定尝试规范这些行为并达成共识时,他们最终得到了包括这两种情况(捕捉和冒泡)的系统,最终被应用在现在浏览器里。
  • 注解: 如上所述,默认情况下,所有事件处理程序都是在冒泡阶段注册的,这在大多数情况下更有意义。如果您真的想在捕获阶段注册一个事件,那么您可以通过使用addEventListener()注册您的处理程序,并将可选的第三个属性设置为true。
  • 参考例子1 参考例子2

3、事件委托 参考例子

冒泡还允许我们利用事件委托——这个概念依赖于这样一个事实,如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并将事件监听器气泡的影响设置为每个子节点,而不是每个子节点单独设置事件监听器。

一个很好的例子是一系列列表项,如果你想让每个列表点击时弹出一条信息,您可以将click单击事件监听器设置在父元素上,它将会冒泡到列表项上。

十六、对象

在 JavaScript 中,大多数事物都是对象, 从作为核心功能的字符串和数组,到建立在 JavaScript 之上的浏览器 API。你甚至可以自己创建对象,将相关的函数和变量封装打包成便捷的数据容器。理解这种面向对象 (object-oriented, OO) 的特性对于进一步学习 JavaScript 语言知识是必不可少的。

1、对象基础

对象是一个包含相关数据和方法的集合(通常由一些变量和函数组成,我们称之为对象里面的属性和方法)

一个对象由许多的成员组成,每一个成员都拥有一个名字(像上面的name、age),和一个值(如['Bob', 'Smith']、32)。每一个名字/值(name/value)对被逗号分隔开,并且名字和值之间由冒号(:)分隔,语法规则如下所示:

var objectName = { member1Name : member1Value, member2Name : member2Value, member3Name : member3Value }

var person = { name : ['Bob', 'Smith'], age : 32, gender : 'male', interests : ['music', 'skiing'], bio : function() { alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + '
years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] +
'.');
}, greeting: function() { alert('Hi! I\'m ' + this.name[0] + '.'); } };

对象成员的值可以是任意的,在我们的person对象里有字符串(string),数字(number),两个数组(array),两个函数(function)。前4个成员是资料项目,被称为对象的属性(property),后两个成员是函数,允许对象对资料做一些操作,被称为对象的方法(method)

一个如上所示的对象被称之为对象的字面量(literal)——手动的写出对象的内容来创建一个对象。不同于从类实例化一个对象,

当你想要传输一些有结构和关联的资料时常见的方式是使用字面量来创建一个对象,举例来说,发起一个请求到服务器以存储一些数据到数据库,发送一个对象要比分别发送这些数据更有效率,而且比起数组更为易用,因为你使用名字(name)来标识这些资料。

2、点表示法

  • 访问对象的属性和方法,当你想访问对象内部的属性或方法时,然后是一个点(.),紧接着是你想要访问的项目,标识可以是简单属性的名字(name),或者是数组属性的一个子元素,又或者是对象的方法调用。 person.age person.interests[1] person.bio()
  • 子命名空间:可以用一个对象来做另一个对象成员的值 name : ['Bob', 'Smith'], 改成 name : { first : 'Bob', last : 'Smith' },
  • 访问:链式的再使用一次点表示法 person.name.first person.name.last

3、括号表示法

另外一种访问属性的方式是使用括号表示法(bracket notation) person.age person.name.first

  • 换成: person['age'] person['name']['first']

这看起来很像访问一个数组的元素,从根本上来说是一回事儿,你使用了关联了值的名字,而不是索引去选择元素。难怪对象有时被称之为关联数组(associative array)了——对象做了字符串到值的映射,而数组做的是数字到值的映射。

4、设置对象成员

person.age = 45 person['name']['last'] = 'Cratchit'

设置成员并不意味着你只能更新已经存在的属性的值,你完全可以创建新的成员,尝试以下代码: person['eyes'] = 'hazel' person.farewell = function() { alert("Bye everybody!") }

括号表示法一个有用的地方是它不仅可以动态的去设置对象成员的值,还可以动态的去设置成员的名字。(这是使用点表示法无法做到的,点表示法只能接受字面量的成员的名字,不接受变量作为名字。)

  • 比如说,我们想让用户能够在他们的数据里存储自己定义的值类型,通过两个input框来输入成员的名字和值,通过以下代码获取用户输入的值:

var myDataName = nameInput.value var myDataValue = nameValue.value

  • 我们可以这样把这个新的成员的名字和值加到person对象里:

person[myDataName] = myDataValue

5、"this"的含义

this 指向了代码所在的对象(其实代码运行时所在的对象)。在字面量的对象里this看起来不是很有用,但是当你动态创建一个对象(例如使用构造器)时它是非常有用的,之后你会更清楚它的用途。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文