前端——JavaScript
Posted 学霸初养成
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端——JavaScript相关的知识,希望对你有一定的参考价值。
何谓javascript?它与Java有什么关系?
JavaScript与html、CSS组合使用应用于前端开发,JavaScript是一门独立的语言,浏览器内置了JS的解释器。它除了和Java名字长得相似,没有半毛线关系。
JavaScript组成
一个完整的JavaScript实现是由以下几个部分组成:
- 核心(ECMAScript) 包括:语法、类型、语句、关键字、保留字、运算符、对象(封装 继承 多态)
- 文档对象模型(DOM) Document object model (整合js,css,html)
- 浏览器对象模型(BOM) Broswer object model(整合js和浏览器)
JavaScript的存在形式
1.JavaScript代码的存在形式
代码写在JS文件中,在html文件头部引入<script type="text/javascript" src="JS文件"></script>
- 代码写在html文件头部的<scrpit></script>标签中
2.JavaScript代码存放位置
-
HTML的head中
-
HTML的body代码块底部(推荐)
由于Html代码是从上到下执行,如果Head中的js代码耗时严重,就会导致用户长时间无法看到页面,如果放置在body代码块底部,那么即使js代码耗时严重,也不会影响用户看到页面效果,只是js实现特效慢而已。
标识符
1.由字母、数字、下划线、美元符号组成
2.不以数字开头
3.常用于函数、变量等的名称
4.JavaScript中代表特定含义的词称为关键字,不允许程序再定义为标识符。
变量
JavaScript中变量的声明是一个非常容易出错的点,局部变量必须一个 var 开头,如果未使用var,则默认表示声明的是全局变量。
<script type="text/javascript"> name = \'seven\',age = 20,job = "teacher"; // 全局变量 function func(){ var age = 18; // 局部变量 gender = "男" // 全局变量 } </script>
JavaScript中代码注释:
- 单行 //
- 多行 /* */
注意:此注释仅在Script块中生效。
数据类型
JavaScript 中的数据类型分为基本数据类型和对象类型:
- 基本数据类型
- 数字
- 字符串
- 布尔型
- Null
- Undefined
- 对象类型
- 数组
- “字典”
- ...
特别的,数字、布尔值、null、undefined、字符串是不可变。
null是JavaScript语言的关键字,它表示一个特殊值,常用来描述“空值”。undefined是一个特殊值,表示变量未定义。
1.数字(Number)
JavaScript中不区分整数值和浮点数值,JavaScript中所有数字均用浮点数值表示。
转换:
- parseInt(..) 将某值转换成数字,不成功则NaN
- parseFloat(..) 将某值转换成浮点数,不成功则NaN
特殊值:
- NaN,非数字。可使用 isNaN(num) 来判断。
- Infinity,无穷大。可使用 isFinite(num) 来判断。
2.字符串(String)
字符串是由字符组成的数组,但在JavaScript中字符串是不可变的:可以访问字符串任意位置的文本,但是JavaScript并未提供修改已知字符串内容的方法。
obj.length 长度 obj.trim() 移除空白 obj.trimLeft() obj.trimRight) obj.charAt(n) 返回字符串中的第n个字符 obj.concat(value, ...) 拼接 obj.indexOf(substring,start) 子序列位置 obj.lastIndexOf(substring,start) 子序列位置 obj.substring(from, to) 根据索引获取子序列 obj.slice(start, end) 切片 obj.toLowerCase() 大写 obj.toUpperCase() 小写 obj.split(delimiter, limit) 分割 obj.search(regexp) 从头开始匹配,返回匹配成功的第一个位置(g无效) obj.match(regexp) 全局搜索,如果正则中有g表示找到全部,否则只找到第一个。 obj.replace(regexp, replacement) 替换,正则中有g则替换所有,否则只替换第一个匹配项,
3.布尔类型(Boolean)
布尔类型仅包含真假(true 和 false),与Python不同的是其首字母小写。
- == 比较值相等
- != 不等于
- === 比较值和类型相等
- !=== 不等于
- || 或
- && 且
4.Null类型 和 Undefined类型
Undefined类型只有一个值:undefined。当声明的变量未初始化时,该变量的默认值是undefined。
当函数无返回值时,返回值也是"undefined"
Null类型也只有一个值:null。值 undefined 实际上是从 null 派生而来的,因此 ECMAScript 把它们定义为相等的。
尽管这两个值相等,但它们含义却不同。undefined 是声明了变量但未对其初始化时赋予该变量的值,null 则用于表示尚未存在的对象(在讨论 typeof 运算符时,简单地介绍过这一点)。如果函数或方法要返回的是对象,那么找不到该对象时,返回的通常是 null。
5.数组(列表)
JavaScript中的数组类似于Python中的列表
obj.length 数组的大小 obj.push(ele) 尾部追加元素 obj.pop() 尾部获取一个元素 obj.unshift(ele) 头部插入元素 obj.shift() 头部移除元素 obj.splice(start, deleteCount, value, ...) 插入、删除或替换数组的元素 obj.splice(n,0,val) 指定位置插入元素 obj.splice(n,1,val) 指定位置替换元素 obj.splice(n,1) 指定位置删除元素 obj.slice( ) 切片 obj.reverse( ) 反转 obj.join(sep) 将数组元素连接起来以构建一个字符串 obj.concat(val,..) 连接数组 obj.sort( ) 对数组元素进行排序
6.类型查询函数(typeof)
ECMAScript 提供了 typeof 运算符来判断一个值是否在某种类型的范围内。可以用这种运算符判断一个值是否表示一种原始类型:如果它是原始类型,还可以判断它表示哪种原始类型。
函数typeof :查询数值当前类型(string / number / boolean / object ) 例如typeof("test"+3) "string" 例如typeof(null) "object " 例如typeof(true+1) "number" 例如typeof(true-false) "number"
其他
1.序列化
- JSON.string(obj) 序列化:将对象转化为字符串
- JSON.parss(str) 反序列化:将字符串转化为对象类型
2.转义
很多时候需要将数据转义后,保存在cookie中。
- decodeURI( ) URl中未转义的字符
- decodeURIComponent( ) URI组件中的未转义字符
- encodeURI( ) URI中的转义字符
- encodeURIComponent( ) 转义URI组件中的字符
- escape( ) 对字符串转义
- unescape( ) 给转义字符串解码
- URIError 由URl的编码和解码方法抛出
3、eval()
JavaScript中的eval是Python中eval()和exec()的合集,既可以编译代码也可以获取返回值。
- eval()
- EvalError 执行字符串中的JavaScript代码
4、正则表达式
1、定义正则表达式
- /.../ 用于定义正则表达式
- /.../g 表示全局匹配
- /.../i 表示不区分大小写
- /.../m 表示多行匹配
JS正则匹配时本身就是支持多行,此处多行匹配只是影响正则表达式^和$,m模式也会使用^$来匹配换行的内容)
var pattern = /^Java\\w*/gm; var text = "JavaScript is more fun than \\nJavaEE or JavaBeans!"; result = pattern.exec(text) result = pattern.exec(text) result = pattern.exec(text)
注:定义正则表达式也可以 reg= new RegExp()
2、匹配
JavaScript中支持正则表达式,其主要提供了两个功能:
- test(string) 检查字符串中是否和正则匹配
n = \'uui99sdf\' reg = /\\d+/ reg.test(n) ---> true # 只要正则在字符串中存在就匹配,如果想要开头和结尾匹配的话,就需要在正则前后加 ^和$
- exec(string) 获取正则表达式匹配的内容,如果未匹配,值为null,否则,获取匹配成功的数组。
获取正则表达式匹配的内容,如果未匹配,值为null,否则,获取匹配成功的数组。 非全局模式 获取匹配结果数组,注意:第一个元素是第一个匹配的结果,后面元素是正则子匹配(正则内容分组匹配) var pattern = /\\bJava\\w*\\b/; var text = "JavaScript is more fun than Java or JavaBeans!"; result = pattern.exec(text) var pattern = /\\b(Java)\\w*\\b/; var text = "JavaScript is more fun than Java or JavaBeans!"; result = pattern.exec(text) 全局模式 需要反复调用exec方法,来一个一个获取结果,直到匹配获取结果为null表示获取完毕 var pattern = /\\bJava\\w*\\b/g; var text = "JavaScript is more fun than Java or JavaBeans!"; result = pattern.exec(text) var pattern = /\\b(Java)\\w*\\b/g; var text = "JavaScript is more fun than Java or JavaBeans!"; result = pattern.exec(text)
3、字符串中相关方法
obj.search(regexp) 获取索引位置,搜索整个字符串,返回匹配成功的第一个位置(g模式无效) obj.match(regexp) 获取匹配内容,搜索整个字符串,获取找到第一个匹配内容,如果正则是g模式找到全部 obj.replace(regexp, replacement) 替换匹配替换,正则中有g则替换所有,否则只替换第一个匹配项, $数字:匹配的第n个组内容; $&:当前匹配的内容; $`:位于匹配子串左侧的文本; $\':位于匹配子串右侧的文本 $$:直接量$符号
5、时间操作
JavaScript中提供了时间相关的操作,时间操作中分为两种时间:
- 时间统一时间
- 本地时间(东8区)
首先生成Date对象 var d = new Date();
get 系列:获取时间
set 系列:设置时间
设置分钟:
设置日期:
设置小时:
等等.....
6.定时器
1.setInterval("执行函数",间隔时间) 功能:每隔固定时间,执行指定函数,无限循环下去。(时间单位:毫秒)
setInterval(function(){ console.log(); },5000),
2.setTimeout(函数,时间) 定时执行。在等待指定时间后,执行一次指定函数。(时间单位:毫秒)
setTimeout(function(){ console.log(1); },5000)
基本语法
1.条件语句
1. if...else... 语句
if(条件){ }else if(条件){ }else{ }
2. switch...case... 语句
switch(name){ case \'1\': age = 123; break; case \'2\': age = 456; break; default : age = 777; }
JS的if语句和switch语句和C语言的完全一样。
2.循环语句
JavaScript中支持若干种循环,其中最为常用的有三种循环
1. for循环(方式一)
var names = ["alex", "tony", "rain"]; for(var i=0;i<names.length;i++){ console.log(i); console.log(names[i]); }
上面代码在每次循环的时候都要获取数组长度,这会降低代码性能,好的办法是缓存数组的长度。
for(var i=0,len=names.length;i<len;i++){ console.log(i); console.log(names[i]); }
2. for循环(方式二)
var names = ["alex", "tony", "rain"]; for(var index in names){ console.log(index); console.log(names[index]); }
此种for循环看起来与Python非常相似。但使用它的时候需要小心,它不仅会遍历对象中的元素,还会将对象原型中的属性与方法遍历出来,所以可能会导致代码中出现意外的错误。
// 给Array的原型添加一个sex属性 Array.prototype.sex = "man"; for(var i in name){ console.log(name[i]); } // 输出结果: alex tony rain man
如何避免呢?可以使用对象的 hasOwnProperty()方法。如果对象的属性或方法是非继承的,那么 hasOwnProperty() 方法返回true。即这里的检查不涉及从其他对象继承的属性和方法,只会检查在特定对象自身中直接创建的属性。
// 给Array的原型添加一个sex属性 Array.prototype.sex = "man"; for(var i in name){ if( !name.hasOwnProperty(i) ) { continue; }else { console.log(name[i]); } } // 输出结果: alex tony rain
3. while循环
while(条件){ // break; // continue; }
3. 异常处理
try { //这段代码从上往下运行,其中任何一个语句抛出异常该代码块就结束运行 } catch (e) { // 如果try代码块中抛出了异常,catch代码块中的代码就会被执行。 //e是一个局部变量,用来指向Error对象或者其他抛出的对象 } finally { //无论try中代码是否有异常抛出(甚至是try代码块中有return语句),finally代码块中始终会被执行。 }
函数
JavaScript中的函数分三类:普通函数、匿名函数、自执行函数。
1.普通函数
function func(){ ...... }
2.匿名函数
匿名函数的存在形式多种多样
// 定义函数时并给函数取名,将匿名函数赋值给变量func var func = function(arg){ return "tony"; } // 定时器中的执行函数,可以以匿名函数形式存在 setInterval(function(){ console.log(); },5000),
3.自执行函数
由两个括号组成,第一个括号内是执行函数,第二个括号内是传入参数。
(function(arg){ console.log(arg); })(\'123\') // 立即自动执行函数,
作用域(重点)
作用域在许多程序设计语言中非常重要。通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。
1.以函数作为作用域
其他语言(如C,Java,C#):以代码块作为作用域(代码块即为大括号抱起来的部分)
public static void main () { if(1==1){ String name = "seven"; } System.out.println(name); } // 报错
Python中:以函数作为作用域
情况一: def func(): if 1==1: name = \'alex\' print(name) func() // 成功 情况二: def func(): if 1==1: name = \'alex\' print(name) func() print(name) // 报错
JavaScript中:以函数作为作用域
var name=\'cc\'; function func(){ if(1==1){ var name = \'dd\'; } console.log(name); } func()
2.函数的作用域在被调用之前就已经创建
3.函数的作用域存在作用域链,也是在被调用之前创建
如果出现嵌套函数,则会出现作用域链;作用域在被执行之前就已经被创建,执行时只需要按照作用域链寻找即可。
同名变量的值,取决于离自己自己最近的作用域的值。(根据作用域链从内到外的优先级寻找,如果内层没有就逐步向上找,直到没找到抛出异常。)
示例1:
xo = \'alex\'; function Func(){ var xo = "seven"; function inner(){ var xo = \'alvin\'; console.log(xo); } inner(); } Func();
// 输出结果:alvin
示例2:
xo = \'alex\'; function Func(){ var xo = "seven"; function inner(){ console.log(xo); } return inner; } var ret = Func(); ret(); // 输出结果: seven
示例三:
xo = \'alex\'; function Func(){ var xo = "eirc"; function inner(){ console.log(xo); } xo = \'seven\'; return inner; } var ret = Func(); ret(); // 输出结果: seven
上述代码和示例一的目的相同,也是强调在函数被调用之前作用域链已经存在:
- 全局作用域 -> Func函数作用域 -> inner函数作用域
不同的时,在执行【var ret = Func();】时,Func作用域中的xo变量的值已经由 “eric” 被重置为 “seven”,所以之后再执行【ret();】时,就只能找到“seven”。
示例四:
xo = \'alex\'; function Bar(){ console.log(xo); } function Func(){ var xo = "seven"; return Bar; } var ret = Func(); ret(); // 输出结果: alex
上述代码,在函数被执行之前已经创建了两条作用域链:
- 全局作用域 -> Bar函数作用域
- 全局作用域 -> Func函数作用域
当执行【ret();】时,ret代指的Bar函数,而Bar函数的作用域链已经存在:全局作用域 -> Bar函数作用域,所以,执行时会根据已经存在的作用域链去寻找。
4.函数内局部变量提前声明
编译阶段生成作用域链,同时找到所有局部变量,执行var声明操作,但并没有赋值。
在JavaScript中如果不创建变量,直接去使用,则报错:
console.log(xxoo); // 报错:Uncaught ReferenceError: xxoo is not defined
JavaScript中如果创建值而不赋值,则该值为 undefined,如:
var xxoo; console.log(xxoo); // 输出:undefined
在函数内如果这么写:
function Foo(){ console.log(xo); var xo = \'seven\'; } // 解释过程中: var xo; Foo(); // 输出:undefined
上述代码,不报错而是输出 undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于上述实例中,函数在“预编译”时,已经执行了var xo;所以上述代码中输出的是undefined
JavaScript面向对象
定义类和实例化示例:
function Foo(n){ this.name = n; this.sayName = function(){ console.log(this.name); } } var obj = new Foo("we");
- Foo是类名
- this代指对象,相当于Python中的self
- 创建对象需要用new关键字,区别于函数调用
以上代码可以发现,从外壳来看,类与函数长得很像,它与函数的形式区别在于:1.this的使用2.实例化时的new关键字
在Python中,类实例化若干个对象后,每个对象内存中包含变量,但不包含方法,方法在类中,我们认为这是合理的。然而JavaScript不一样,每个对象中都存在相同的方法,这样浪费内存,不合理。
解决办法是:将方法写在prototype原型中
Foo的原型: Foo.prototype = { "sayName":function(){ console.log(this.name); } }
当创建对象并调用方法时,如果在类中没有找到就会去原型中去寻找。将所有方法写在原型中,就达到了节省内存的目的。
JavaScript词法分析
JS代码执行前有一个类似编译的过程即词法分析(AO分析:active object),词法分析主要有三个步骤:
-
分析形式参数;
-
分析局部变量;
-
分析函数声明表达式;
在这里你可能会有问题:已经明白了作用域为什么还要看词法分析呢?词法分析和作用域在JS代码执行过程中各分担什么作用?带着这些疑问先往下看:
分析过程:
1.首先分析形式参数,赋给AO对象
先看函数的形式参数,添加到AO的属性,并且这个时候值为undefined
再看接收的实参,如果有,负载之前的undefined
2.局部变量
检查局部变量,如果遇到不同名变量,添加属性并赋值为undefined
如果有遇到同名变量,不做任何修改
3.函数声明表达式(优先级最高)
遇到函数,添加属性,并把函数赋值给这个属性。
如果该函数和前面的变量同名,则将变量覆盖,因为函数的优先级更高。
先来看示例一:
function t1(age) { console.log(age); var age = 27; console.log(age); function age() {} console.log(age); } t1(3);
首先词法分析:
1.生成AO对象
2.分析形参,AO.age = undefined;
发现实参,赋值AO.age = 3;
3.分析局部变量发现同名变量age,不做任何修改
4.分析函数age,因为优先级高,所以覆盖,即AO.age = function age(){}
整个过程只有一个变量名,所以词法分析的结果是:AO.age = function age(){}
执行阶段:
1.第一行输出age,即词法分析的结果function age(){};
2.遇到 var age = 27 ,给age赋值为27;
3.输出age为27
4.输出age为27
执行完毕,感觉懵逼?多此一举? 要记住,词法分析和执行是两个不同的阶段,词法分析在前,执行在后
继续看示例二:
function t1(age) { var age; console.log(age); var age = 23; console.log(age); function age() {} console.log(age); } t1(22) // 与示例一代码不同之处:在第一次输出之前定义了同名变量,但没有赋值
词法分析阶段:
1.生成AO对象
2.分析形参,AO.age = undefined;
分析实参,赋值,AO.age = 22;
3.分析局部变量age,与前面同名,不做任何修改
4.分析局部变量age,虽然赋值23,但因为同名,不做任何修改
5.分析函数age,覆盖AO.age = function age(){}
分析结果:AO.age = function age(){}
执行阶段:
1.第一次输出时,没有做赋值,所以输出词法分析结果function age(){}
2.var age = 23;值被修改
3.第二次输出:23
4.第三次输出:23
示例三:
function t1(age) { var age; console.log(age); function age() {} console.log(age); var age = 23; console.log(age); } t1(22) // 与实例二代码区别:将函数位置提前
词法分析阶段:
1.生成AO对象
2.分析形参,AO.age = undefined;
分析实参,AO.age = 22;
3.分析函数age,覆盖:AO.age = function age(){};
4.分析局部变量age,虽然被赋值,但在词法分析阶段函数优先级高,故age属性仍然为上一步的值
分析结果:AO.age = function age(){}
执行阶段:
1.第一次输出,为词法分析结果 function age(){}
2.第二次输出,为词法分析结果 function age(){}
3.age被重新赋值,age = 23
4.第三次输出,为23
示例四:
function t1(age) { var age; console.log(age); age = 23; console.log(age); function age() { console.log(age); } age(); console.log(age) } t1(22)
词法分析阶段:
1.生成AO对象
2.分析形式参数AO.age = undefined;
分析实参AO.age = 23;
3.分析局部变量var age,不做改变
4.分析局部变量var age = 23,不做改变
5.分析函数,AO.age = function age(){console.log(age)}
分析结果:AO.age = function age(){console.log(age)}
执行阶段:
1.第一次输出:function age(){console.log(age)}
2.age被重新赋值,age=23
3.第二次输出:23
4.执行 "age()" 代码,但是此时age是普通变量而非函数,因此语法错误,会报错
JavaScript的词法分析介绍到这里,现在对词法分析和作用域的作用做一下梳理:
- 作用域 是程序执行过程所遵守的规则
- 词法分析 可以理解为程序执行前的初始化过程,在程序执行的最开始提供变量的初值
BOM对象
BOM(浏览器对象模型),可以对浏览器窗口进行访问和操作。使用 BOM,开发者可以移动窗口、改变状态栏中的文本以及执行其他与页面内容不直接相关的动作。使 JavaScript 有能力与浏览器“对话”。
window对象
所有浏览器都支持 window 对象。
概念上讲,一个html文档对应一个window对象;
功能上讲:控制浏览器窗口的;
使用上讲:window对象不需要创建对象,直接使用即可。
1.window对象方法
alert() 显示带有一段消息和一个确认按钮的警告框。 confirm() 显示带有一段消息以及确认按钮和取消按钮的对话框。 prompt() 显示可提示用户输入的对话框。 open() 打开一个新的浏览器窗口或查找一个已命名的窗口。 close() 关闭浏览器窗口。 setInterval() 按照指定的周期(以毫秒计)来调用函数或计算表达式。 clearInterval() 取消由 setInterval() 设置的 timeout。 setTimeout() 在指定的毫秒数后调用函数或计算表达式。 clearTimeout() 取消由 setTimeout() 方法设置的 timeout。 scrollTo() 把内容滚动到指定的坐标。
2.交互方法
方法讲解: alert() confirm() prompt() 三种弹窗方式: alert(); 括号中的内容为字符串或数字类型。点击确认即可关闭,无返回值。 confirm(); 括号中的内容为字符串或数字类型。点击确认返回 true,点击取消返回 false prompt(text,defaultText); 参数:text 可选。要在对话框中显示的文本 defaultText 可选。输入框中显示的默认文本,点击确定返回此值。 返回值是用户输入的内容。 open()方法: 用于打开一个新的浏览器窗口或查找一个已命名的窗口。 window.open(URL,name,features,replace) 使用1: 打开和一个新的窗口 并 进入指定网址.参数1 : 网址. open("http://www.baidu.com"); 如果参数1 什么都不填 就是打开一个新窗口. 参数2.填入新窗口的名字(一般可以不填). 参数3: 新打开窗口的参数. open(\'\',\'\',\'width=200,resizable=no,height=100\'); // 新打开一个宽为200 高为100的窗口 close方法:将当前文档窗口关闭. //close();
示例:
var num = Math.round(Math.random()*100); function acceptInput(){ //2.让用户输入(prompt) 并接受 用户输入结果 var userNum = prompt("请输入一个0~100之间的数字!","0"); //3.将用户输入的值与 随机数进行比较 if(isNaN(+userNum)){ //用户输入的无效(重复2,3步骤) alert("请输入有效数字!"); acceptInput(); } else if(userNum > num){ //大了==> 提示用户大了,让用户重新输入(重复2,3步骤) alert("您输入的大了!"); acceptInput(); }else if(userNum < num){ //小了==> 提示用户小了,让用户重新输入(重复2,3步骤) alert("您输入的小了!"); acceptInput(); }else{ //答对了==>提示用户答对了 , 询问用户是否继续游戏(confirm). var result = confirm("恭喜您!答对了,是否继续游戏?"); if(result){ //是 ==> 重复123步骤. num = Math.round(Math.random()*100); acceptInput(); }else{ //否==> 关闭窗口(close方法). close(); } }
History对象
History 对象包含用户(在浏览器窗口中)访问过的 URL。
History 对象是 window 对象的一部分,可通过 window.history 属性对其进行访问。
history对象属性
length 返回浏览器历史列表中的 URL 数量。
history对象方法
back() 加载 history 列表中的前一个 URL。 forward() 加载 history 列表中的下一个 URL。 go() 加载 history 列表中的某个具体页面。
<a href="rrr.html">click</a> <button onclick=" history.forward()">>>></button> <button onclick="history.back()">back</button> <button onclick="history.go()">back</button>
Location对象
Location 对象包含有关当前 URL 的信息。
Location 对象是 Window 对象的一个部分,可通过 window.location 属性来访问。
Location 对象方法
location.assign(URL) location.reload() 强制浏览器刷新页面,参数默认为false,从缓存中取文档。设置为true重新发送get请求 location.replace(newURL)//注意与assign的区别
以上是关于前端——JavaScript的主要内容,如果未能解决你的问题,请参考以下文章
markdown Snippets.md是我最常用的HTML,CSS和JavaScript代码片段,用于前端Web开发