<script>
/*
JS中的数据类型
String 字符串
Number 数值
Boolean 布尔值
Null 空值
Undefined 未定义
以上这五种类型属于基本数据类型,以后我们看到的值
只要不是上边的5种,全都是对象
Object 对象
基本数据都是单一的值"hello" 123 true,
值和值之间没有任何的联系,
在JS中来表示一个人的信息(name gender age),
var name="孙悟空";
var gender="男";
var age=18;
如果使用基本数据类型的数据,我们所创建的变量都是独立,不能成为一个整体。
对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。
对象的分类:
1.内建对象
由ES标准中定义的对象,在任何的ES的实现中都可以使用
比如:Math String Number Boolean Function Object....
2.宿主对象
由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
比如BOM DOM
3.自定义对象
由开发人员自己创建的对象
*/
//创建对象
/*
使用new关键字调用的函数,是构造函数constructor
构造函数是专门用来创建对象的函数
使用typeof检查一个对象时,会返回object
*/
var obj=new Object();
/*
在对象中保存的值称为属性
向对象添加属性
语法:对象.属性名=属性值;
*/
//向obj中添加一个name值
obj.name="孙悟空";
//向obj中添加一个gender属性
obj.gender="男";
//向obj中添加一个age属性
obj.age=18;
/*
读取对象中的属性
语法:对象.属性名
如果读取对象中没有的属性,不会报错而是会返回undefined
*/
//console.log(obj.gender);
//console.log(obj.hello);
/*
修改对象的属性值
语法:对象.属性名=新值
*/
obj.name="tom";
/*
删除对象的属性
语法:delete 对象.属性名
*/
delete obj.name;
console.log(obj.name);
script>
<script>
var obj=new Object();
/*
向对象中添加属性
属性名:
对象的属性名不强制要求遵守标识符的规范
什么乱七八糟的名字都可以使用
但是尽量使用时还是尽量按照标识符的规范去做
*/
obj.name="孙悟空";
//obj.var="hello";
/*
如果要使用特殊的属性名,不能采用.的方式来操作
需要使用另一种方式:
语法:对象["属性名"]=属性值
读取时也需要采用这种方式
使用[]这种形式去操作属性,更加的灵活,
在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性
*/
//obj["123"]=789;
//obj["nihao"]="你好";
var n="nihao";
//console.log(obj[n]);
/*
属性值
JS对象的属性值,可以是任意的数据类型
甚至也可以是一个对象
*/
obj.test=true;
obj.test=null;
obj.test=undefined;
//创建一个对象
var obj2=new Object();
obj2.name="猪八戒";
//将obj2设置为obj的属性
obj.test=obj2;
//console.log(obj.test.name);
/*
in 运算符
通过该运算可以检查一个对象中是否含有指定的属性
如果有则返回true,没有则返回false
语法:
"属性名" in 对象
*/
//console.log(obj.test2);
//检查obj中是否含有test2属性
//console.log("test2" in obj);
//console.log("test" in obj);
console.log("name" in obj);
script>
<script>
/*
基本数据类型
String Number Boolean Null Undefined
引用数据类型
Object
JS中的变量都是保存到栈内存中的,
基本数据类型的值直接在栈内存中存储,
值与值之间是独立存在,修改一个变量不会影响其他的变量
对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,
而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,
当一个通过一个变量修改属性时,另一个也会受到影响
*/
var a=123;
var b=a;
a++;
/* console.log("a="+a);
console.log("b="+b); */
var obj=new Object();
obj.name="孙悟空";
var obj2=obj;
//修改obj的name属性
obj.name="猪八戒";
/* console.log(obj.name);
console.log(obj2.name); */
//设置obj2为null
obj2=null;
console.log(obj);
console.log(obj2);
var c=10;
var d=10;
//console.log(c==d);
var obj3=new Object();
var obj4=new Object();
obj3.name="沙和尚";
obj4.name="沙和尚";
/* console.log(obj3);
console.log(obj4); */
/*
当比较两个基本数据类型的值时,就是比较值。
而比较两个引用数据类型时,它是比较的对象的内存地址。
如果两个对象是一模一样的,但是地址不同,它也会返回false
*/
console.log(obj3==obj4);
script>
<script>
//创建一个对象
//var obj=new Object();
/*
使用对象字面量来创建一个对象
*/
var obj={};
//console.log(typeof obj);
obj.name="孙悟空";
//console.log(obj.name);
/*
使用对象字面量,可以在创建对象时,直接指定对象中的属性
语法:{属性名:属性值,属性名:属性值....}
对象字面量的属性名可以加引号也可以不加,建议不加,
如果要使用一些特殊的名字,则必须加引号
属性名和属性值是一组一组的名值对结构,
名和值之间使用:连接,多个名值对之间使用,隔开
如果一个属性之后没有其他的属性了,就不要写,
*/
var obj2={
name:"猪八戒",
age:28,
gender:"男",
test:{name:"沙和尚"}
};
console.log(obj2.test);
script>
<script>
/*
函数function
函数也是一个对象
函数中可以封装一些功能(代码),在需要时可以执行这些功能(代码)
函数中可以保存一些代码在需要的时候调用
使用typeof检查一个函数对象时,会返回function
*/
//我们在实际开发中很少使用构造函数来创建一个函数对象
//创建一个函数对象
//可以将要封装的代码以字符串的形式传递给构造函数
//var fun=new Function("console.log('Hello 这是我的第一个函数');");
//封装到函数中的代码不会立即执行
//函数中的代码会在函数调用的时候执行
//调用函数 语法:函数对象()
//当调用函数时,函数中封装的代码会按照顺序执行
//fun();
/*
使用函数声明来创建一个函数
语法:
function 函数名([形参1,形参2...形参N]){
语句...
}
*/
function fun2(){
console.log("这是我的第二个函数~~~");
alert("哈哈哈哈哈");
document.write("~~~~(>_<)~~~~");
}
//console.log(fun2);
//调用fun2
//fun2();
/*
使用 函数表达式来创建一个函数
var 函数名=function([形参1,形参2...形参N]){
语句....
}
*/
var fun3=function(){
console.log("我是匿名函数中封装的代码");
};
fun3();
script>
<script>
/*
定义一个用来求两个数和的函数
可以在函数的()中来指定一个或多个形参(形式参数)
多个形参之间使用,隔开,声明形参就相当于在函数内部声明了对应的变量
但是并不赋值
*/
function sum(a,b){
console.log("a="+a);
console.log("b="+b);
console.log(a+b);
}
/*
在调用函数时,可以在()中指定实参(实际参数)
实参将会赋值给函数中对应的形参
*/
/* sum(1,2);
sum(123,456); */
/*
调用函数时解析器不会检查实参的类型
所以要注意,是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查
函数的实参可以是任意的数据类型
*/
//sum(123,"hello");
//sum(true,false);
/*
调用函数时,解析器也不会检查实参的数量,
多余的实参不会被赋值
如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined
*/
//sum(123,456,"hello",true,null);
sum(123);
script>
<script>
/*
创建一个函数,用来计算三个数的和
可以使用return来设置函数的返回值
语法:
return 值
return后的值将会作为函数的执行结果返回,
可以定义一个变量,来接收该结果
在函数中return后的语句都不会执行
如果return语句后不跟任何值就相当于返回一个undefined,
如果函数中不写return,则也会返回undefined
return后可以跟任意类型的值
*/
function sum(a,b,c){
//alert(a+b+c);
var d=a+b+c;
return d;
//return undefined;
}
//调用函数
//变量result的值就是函数的执行结果
//函数返回什么result的值就是什么
var result=sum(4,7,8);
//var result=alert("hello");
console.log("result="+result);
script>
<script>
/*
定义一个函数,判断一个数字是否是偶数,如果是返回true,否则返回false
*/
function isOu(num){
return num%2==0;
}
var result=isOu(15);
//console.log("result="+result);
/*
定义一个函数,可以根据半径计算一个圆的面积,并返回计算结果
3.14*r*r
*/
function mianji(r){
return 3.14*r*r;
}
result=mianji(5);
//console.log("result="+result);
/*
创建一个函数,可以在控制台中输出一个人的信息
可以输出人的name age gender address
实参可以是任意的数据类型,也可以是一个对象
当我们的参数过多时,可以将参数封装到一个对象中,然后通过对象传递
*/
function sayHello(o){
//console.log("o="+o);
console.log("我是"+o.name+",今年我"+o.age+"岁了,"+"我是一个"+o.gender+"人"+",我住在"+o.address);
}
//sayHello("猪八戒",28,"高老庄","男");
//创建一个对象
var obj={
name:"孙悟空",
age:18,
address:"花果山",
gender:"男"
};
//sayHello(obj);
/*
实参可以是一个对象,也可以是一个函数
*/
function fun(a){
console.log("a="+a);
//a(obj);
}
//fun(sayHello);
//fun(function(){alert("hello")});
fun(mianji(10));
/*
mianji()
调用函数
相当于使用的函数的返回值
mianji
函数对象
相当于直接使用函数对象
*/
script>
<script>
function fun(){
alert("函数要执行了~~~~");
for(var i=0;i<5;i++){
if(i==2){
//使用break可以退出当前的循环
//break;
//continue用于跳过当次循环
//continue;
//使用return可以结束整个函数
//return;
}
console.log(i);
}
alert("函数执行完了~~~~");
}
//fun();
/*
返回值可以是任意的数据类型
也可以是一个对象,也可以是一个函数
*/
function fun2(){
//返回一个对象
return {name:"沙和尚"};
}
var a=fun2();
//console.log("a="+a);
function fun3(){
//在函数内部再声明一个函数
function fun4(){
alert("我是fun4");
}
//将fun4函数对象作为返回值返回
return fun4;
}
a=fun3();
//console.log(a);
//a();
fun3()();
script>
<script>
//函数对象()
/*
立即执行函数
函数定义完,立即被调用,这种函数叫做立即执行函数
立即执行函数往往只会执行一次
*/
/* (function(){
alert("我是一个匿名函数");
})(); */
(function(a,b){
console.log("a="+a);
console.log("b="+b);
})(123,456);
script>
<script>
/*
创建一个对象
*/
var obj=new Object();
//向对象中添加属性
obj.name="孙悟空";
obj.age=18;
//对象的属性值可以是任何的数据类型,也可以是个函数
obj.sayName=function(){
console.log(obj.name);
};
function fun(){
consoel.log(obj.name);
}
//console.log(obj.sayName);
//调方法
obj.sayName();
//调函数
//fun();
/*
函数也可以称为对象的属性
如果一个函数作为一个对象的属性保存,
那么我们称这个函数是这个对象的方法
调用这个函数就说调用对象的方法(method)
但是它只是名称上的区别没有其他的区别
*/
var obj2={
name:"猪八戒",
age:18,
sayName:function(){
console.log(obj2.name);
}
};
obj2.sayName();
script>
<script>
var obj={
name:"孙悟空",
age:18,
gender:"男",
address:"花果山"
};
//枚举对象中的属性
//使用for...in语句
/*
语法:
for(var 变量 in 对象){
}
for...in语句 对象中有几个属性,循环体就会执行几次
每次执行时,会将对象中的一个属性的名字赋值给变量
*/
for(var n in obj){
console.log("属性名:"+n);
console.log("属性值:"+obj[n]);
}
script>
<script>
/*
作用域
作用域指一个变量作用的范围
在JS中一共有两种作用域:
1.全局作用域
直接编写在script标签中的JS代码,都在全局作用域
全局作用域在页面打开时创建,在页面关闭时销毁
在全局作用域中有一个全局对象window,
它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用
在全局作用域中:
创建的变量都会作为window对象的属性保存
创建的函数都会作为window对象的方法保存
全局作用域中的变量都是全局变量,
在页面的任意部分都可以访问的到
2.函数作用域
*/
var a=10;
var b=20;
//var c="hello";
//console.log(window.c);
function fun(){
console.log("我是fun函数");
}
//window.fun();
//window.alert("hello");
script>
<script>
/*
变量的声明提前
使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值)
但是如果声明变量时不使用var关键字,则变量不会被声明提前
函数的声明提前
使用函数声明形式创建的函数function 函数(){}
它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数
使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
*/
/* console.log("a=")+a;
var a=123; */
//fun();
//函数声明,会被提前创建
function fun(){
console.log("我是一个fun函数");
}
//函数表达式,不会被提前创建
var fun2=function(){
console.log("我是fun2函数");
};
fun2();
script>
<script>
/*
函数作用域
调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
在函数作用域中可以访问到全局作用域的变量
在全局作用域中无法访问到函数作用域的变量
当在函数作用域操作一个变量时,它会现在自身作用域中寻找,如果有就直接使用
如果没有则向上一级作用域中寻找,知道找到全局作用域,
如果全局作用域中依然没有找到,则会报错ReferenceError
在函数中要访问全局变量可以使用window对象
*/
//创建一个变量
var a=10;
function fun(){
var a="我是函数中的变量a";
var b=20;
//console.log("a="+a);
function fun2(){
console.log("a="+window.a);
}
fun2();
}
//fun();
//console.log("b="+b);
/*
在函数作用域也有声明提前的特性,
使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
函数声明也会在函数中所有的代码执行之前执行
*/
function fun3(){
fun4();
//console.log(a);
var a=35;
function fun4(){
alert("I'm fun4");
}
}
//fun3();
var c=33;
/*
在函数中,不使用var声明的变量都会成为全局变量
*/
function fun5(){
//console.log("c="+c);
//c=10;
//d没有使用var关键字,则会设置为全局变量
d=100;
}
fun5();
//在全局输出c
//console.log("d="+d);
var e=23;
/*
定义形参就相当于在函数作用域中声明了变量
*/
function fun6(e){
alert(e);
}
fun6();
script>
<script>
/*
解析器在调用函数每次都会向函数内部传递进一个隐含的参数,
这个隐含的参数就是this,this指向的是一个对象
这个对象我们称为函数执行的上下文对象,
根据汉书的调用方式不同,this会指向不同的对象
1.以函数的形式调用时,this永远都是window
2.以方法的形式调用时,this就是调用方法的那个对象
*/
function fun(a,b){
//console.log("a="+a+",b="+b);
cosnole.log(this.name);
}
//fun();
//创建一个对象
var obj={
name:"孙悟空",
sayName:fun
};
var obj2={
name:"沙和尚",
sayName:fun
};
//console.log(obj.sayName==fun);
var name="全局的name属性";
//obj.sayName();
//以函数形式调用,this时window
//fun();
//以方法的形式调用,this是调用方法的对象
//obj.sayName();
obj2.sayName();
script>
<script>
//创建一个name变量
var name="全局";
//创建一个fun()函数
function fun(){
console.log(this.name);
}
//创建两个对象
var obj={
name:"孙悟空",
sayName:fun
};
var obj2={
name:"沙和尚",
sayName:fun
};
//我们希望调用obj.sayName()时可以输出obj的名字
//obj.sayName();
obj.sayName();
script>
<script>
/*
创建一个对象
*/
var obj={
name:"孙悟空",
age:"18",
gender:"男",
sayName:function(){
alert(this.name);
}
};
/*
使用工厂方法创建对象
通过该方法可以大批量的创建对象
*/
function createPerson(name,age,gender){
var obj=new Object();
//向对象中添加属性
obj.name=name;
obj.age=age;
obj.gender=gender;
obj.sayName=function(){
alert(this.name);
};
//将新的对象返回
return obj;
}
/*
用来创建狗的对象
*/
function createDog(name,age){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.sayHello=function(){
alert("汪汪~~");
}
return obj;
}
var obj2=createPerson("猪八戒",28,"男");
var obj3=createPerson("白骨精",16,"女");
var obj4=createPerson("蜘蛛精",18,"女");
/*
使用工厂方法创建的对象,使用的构造函数都是Object
所以创建的对象都是Object这个类型,
就导致我们无法区分出多种不同类型的对象
*/
//创建一个狗的对象
var dog=createDog("旺财",3);
console.log(dog);
console.log(obj4);
script>
<script>
/*
创建一个Person构造函数
在Person构造函数中,为每一个对象都添加了一个sayName方法
目前我们的方法是在构造函数内部创建的,
也就是构造函数每执行一次后就会创建一个新的sayName方法
也是所有实例的都是唯一的。
这样就导致了构造函数执行一次就会创建一个新的方法,
执行10000次就会创建10000个新的方法,而10000个方法都是一模一样的
这是完全没有必要,完全可以是所有的对象共享同一个方法
*/
function Person(name,age,gender){
this.name=name;
this.age=age;
this.gender=gender;
//向对象中添加一个方法
//this.sayName=fun;
}
//将sayName方法在全局作用域中定义
/*
将函数定义在全局作用域,污染了全局作用域的命名空间
而且定义在全局作用域中也很不安全
*/
/* function fun(){
alert("Hello大家好,我是:"+this.name);
}; */
//向原型中添加sayName方法
Person.prototype.sayName=function(){
alert("Hello大家好,我是:"+this.name);
};
//创建一个Person的实例
var per=new Person("孙悟空",18,"男");
var per2=new Person("猪八戒",28,"男");
per.sayName();
per2.sayName();
//console.log(per.sayName()==per2.sayName());
script>
<script>
/*
原型prototype
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype
这个属性对应着一个对象,这个对象就是我们所谓的原型对象
如果函数作为普通函数调用prototype没有任何作用
当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,
指向该构造函数的原型对象,我们可以通过__proto__来访问该属性
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,
我们可以将对象中共有的内容,统一设置到原型对象中,
当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,
如果没有则会去原型对象中寻找,如果找到则直接使用
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,
这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
*/
function MyClass(){
}
//向MyClass的原型中添加属性a
MyClass.prototype.a=123;
//向MyClass的原型中添加一个方法
Myclass.prototype.sayHello=function(){
alert("hello");
};
var mc=new MyClass();
var mc2=new MyClass();
//console.log(MyClass.prototype);
//console.log(mc2.__proto__==MyClass.prototype);
//向mc中添加a属性
mc.a="我是mc中的a";
//console.log(mc2.a);
mc.sayHello();
script>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script>
/*
创建一个构造函数
*/
function MyClass(){
}
//向MyClass的原型中添加一个name属性
MyClass.prototype.name="我是原型中的名字";
var mc=new MyClass();
mc.age=18;
//console.log(mc.name);
//使用in检查对象中是否含有某个属性时,如果都对象中没有但是原型中有,也会返回true
//console.log("name" in mc);
//可以使用对象的hasOwnProperty()来检查自身中是否含有该属性
//使用该方法只有当对象自身中含有属性时,才会返回true
//console.log(mc.hasOwnProperty("age"));
//console.log(mc.hasOwnProperty("hasOwnProperty"));
/*
原型对象也是对象,所以它也有原型,
当我们使用一个对象的属性或方法时,会先在自身中寻找,
自身中如果有,则直接使用
如果没有则去原型对象中寻找,如果原型对象中与有,则使用,
如果没有则取原型的原型中寻找,直到找到Object对象的原型,
Object对象的原型没有原型,如果在Object中依然没有找到,则返回undefined
*/
//console.log(mc.__proto__.hasOwnProperty("hasOwnProperty"));
//console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));
//console.log(mc.__proto__.__proto__.__proto__);
//console.log(mc.hello);
//console.log(mc.__proto__.__proto__.__proto__);
script>
head>
<body>
body>
html>
<script>
function Person(name,age,gender){
this.name=name;
this.age=age;
this.gender=gender;
}
//修改原型的toString
Person.prototype.toString=function(){
return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
};
//创建一个Person实例
var per=new Person("孙悟空",18,"男");
var per2=new Person("猪八戒",28,"男");
//当我们直接在页面中打印一个对象时,实际上是输出的对象的toString()方法的返回值
//如果我们希望在输出对象时不输出[object Object],可以为对象添加一个toString()方法
//Person[name=孙悟空,age=18,gender=男]
/* per.toString=function(){
return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
}; */
var result=per.toString();
//console.log("result="+result);
//console.log(per.__proto__.__proto__.hasOwnProperty("toString"));
console.log(per2);
script>
<script>
/*
垃圾回收(GC)
就像人生活的时间长了会产生垃圾一样,程序运行中也会产生垃圾
这些垃圾积攒过多以后,会导致程序运行的速度过慢,
所以我们需要一个垃圾回收的机制,来处理程序运行过程中产生垃圾
当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,
此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序变慢,
所以这种垃圾必须进行清理。
在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,
我们不需要也不能进行垃圾回收的操作
我们需要做的只是要将不再使用的对象设置null即可
*/
var obj=new Object();
//对对象进行各种操作。。。。
obj=null;
script>
<script>
/*
内建对象
宿主对象
自定义对象
数组(Array)
数组也是一个对象
它和我们普通对象功能类似,也是用来存储一些值的
不同的是普通对象是使用字符串作为属性名的,
而数组是使用数字来作为索引操作元素
索引:
从0开始的整数就是索引
数组的存储性能比普通对象要好,在开发中我们经常使用数组来存储一些数据
*/
//创建数组对象
var arr=new Array();
//使用typeof检查一个数组时,会返回object
//console.log(typeof arr);
/*
向数组中添加元素
语法:数组[索引]=值
*/
arr[0]=10;
arr[1]=33;
arr[2]=22;
arr[3]=44;
/* arr[10]=31;
arr[100]=90; */
/*
读取数组中的元素
语法:数组[索引]
如果读取不存在的索引,他不会报错而是返回undefined
*/
//console.log(arr[3]);
/*
获取数组的长度
可以使用length属性来获取数组的长度(元素的个数)
语法:数组.length
对于连续的数组,使用length可以获取到数组的长度(元素的个数)
对于非连续的数组,使用length会获取到数组的最大的索引+1
尽量不要创建非连续的数组
*/
/* console.log(arr.length);
console.log(arr); */
/*
修改length
如果修改的length大于原长度,则多出部分会空出来
如果修改的length小于原长度,则多出的元素会被删除
*/
/* arr.length=10;
console.log(arr.length);
console.log(arr); */
arr[4]=50;
arr[5]=60;
//向数组的最后一个位置添加元素
//语法:数组[数组.length]=值;
arr[arr.length]=70;
arr[arr.length]=80;
arr[arr.length]=90;
console.log(arr);
script>
<script>
//创建一个数组
//var arr=new Array();
//使用字面量来创建数组
//语法:[]
//var arr=[];
//console.log(typeof arr);
//使用字面量创建数组,可以在创建时就指定数组中的元素
var arr=[1,2,3,4,5,10];
//console.log(arr[3]);
//使用构造函数创建数组时,也可以同时添加元素,将要添加的元素作为构造函数的参数传递
//元素之间使用,隔开
var arr2=new Array(10,20,30);
//console.log(arr2);
//创建一个数组数组中只有一个元素10
arr=[10];
//创建一个长度为10的数组
arr2=new Array(10);
//console.log(arr2.length);
//数组中的元素可以是任意的数据类型
arr=["hello",1,true,null,undefined];
//也可以是对象
var obj={name:"孙悟空"};
arr[arr.length]=obj;
arr=[{name:"孙悟空"},{name:"沙和尚"},{name:"猪八戒"}];
//也可以是一个函数
arr=[function(){alert(1)},function(){alert(2)}];
//console.log(arr);
//arr[0]();
//数组中也可以放数组,如下这种数组我们称为二维数组
arr=[[1,2,3],[3,4,5],[5,6,7]];
console.log(arr[1]);
script>
<script>
//创建一个数组
var arr=["孙悟空","猪八戒","沙和尚"];
/*
push()
该方法可以向数组的末尾添加一个或多个元素,并返回数组的新的长度
可以将要添加的元素作为方法的参数传递,
这样这些元素将会自动添加到数组的末尾。
该方法会将数组新的长度作为返回值返回
*/
var result=arr.push("唐僧","蜘蛛精","白骨精","玉兔精");
//console.log(arr);
//console.log("result="+result);
/*
pop()
该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
*/
result=arr.pop();
/* console.log(arr);
console.log("result="+result); */
/*
unshift()
向数组开头添加一个或多个元素,并返回新的数组长度
向前边插入元素以后,其他的元素索引会依次调整
*/
//console.log(arr);
arr.unshift("牛魔王","二郎神");
console.log(arr);
/*
shift()
可以删除数组的第一个元素,并将被删除的元素作为返回值返回
*/
result=arr.shift();
result=arr.shift();
console.log(arr);
console.log("result="+result);
script>
<script>
//创建一个数组
var arr=["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
//所谓的遍历数组,就是将数组中所有的元素都取出来
/* console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
console.log(arr[3]); */
for(var i=0;i<arr.length;i++){
console.log(arr[i]);
}
script>
<script>
function Person(name,age){
this.name=name;
this.age=age;
}
//修改原型的toString
Person.prototype.toString=function(){
return "Person[name="+this.name+",age="+this.age+"]";
};
//创建一个Person对象
var per=new Person("孙悟空",18);
var per3=new Person("猪八戒",28);
var per2=new Person("红孩儿",8);
var per4=new Person("蜘蛛精",16);
var per5=new Person("二郎神",38);
/*
将这些person对象放入到一个数组中
*/
var perArr=[per,per2,per3,per4,per5];
/*
创建一个函数,可以将perArr中的满18岁的Person提取出来,
然后封装到一个新的数组中并返回
arr
形参,要提取信息的数组
*/
function getAdult(arr){
//创建一个新的数组
var newArr=[];
//遍历arr,获取arr中Person对象
for(var i=0;i<arr.length;i++){
var p=arr[i];
//判断Person对象的age是否大于等于18
if(p.age>=18){
//如果大于等于18,则将这个对象添加到newArr中
//将对象放入到新数组中
newArr.push(p);
}
}
//将新的数组返回
return newArr;
}
var result=getAdult(perArr);
console.log(result);
script>
<script>
/*
一般我们都是使用for循环去遍历数组,
JS中还为我们提供了一个方法,用来遍历数组
forEach()
这个方法只支持IE8以上的浏览器IE8及以下的浏览器均不支持该方法,所以如果需要兼容IE8,则不要使用forEach
还是使用for循环来遍历
*/
//创建一个数组
var arr=["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
/*
forEach()方法需要一个函数作为参数
像这种函数,由我们创建但是不由我们调用的,我们称为回调函数
数组中有几个元素函数就会执行几次,每次执行时,浏览器会将遍历到的元素
以实参的形式传递进来,我们可以来定义形参,来读取这些内容
浏览器会在回调函数中传递三个参数:
第一个参数,就是当前正在遍历的元素
第二个参数,就是当前正在遍历的元素的索引
第三个参数,就是正在遍历的数组
*/
arr.forEach(function(value,index,obj){
console.log(value);
});
script>
<script>
var arr=["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
/*
slice()
可以用来从数组提取指定元素
该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回
参数:
1.截取开始的位置的索引,包含开始索引
2.截取结束的位置的索引,不包含结束索引
第二个参数可以省略不写,此时会截取从开始索引往后的所有元素
索引可以传递一个负值,如果传递一个负值,则从后往前计算
-1倒数第一个
-2倒数第二个
*/
var result=arr.slice(1,4);
result=arr.slice(3);
result=arr.slice(1,-2);
//console.log(result);
/*
splice()
可以删除数组中的指定元素
使用splice()会影响到原数组,会将指定元素从原数组中删除
并将被删除的元素作为返回值返回
参数:
第一个,表示开始位置的索引
第二个,表示删除的数量
第三个及以后。。
可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
*/
arr=["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
var result=arr.splice(3,0,"牛魔王","铁扇公主","红孩儿");
console.log(arr);
//console.log(result);
script>
<script>
//创建一个数组
var arr=[1,2,3,2,2,1,3,4,2,5];
//去除数组中重复的数字
//获取数组中的每一个元素
for(var i=0;i<arr.length;i++){
//console.log(arr[i]);
/* 获取当前元素后的所有元素 */
for(var j=i+1;j<arr.length;j++){
//console.log("---->"+arr[j]);
//判断两个元素的值是否相等
if(arr[i]==arr[j]){
//如果相等则证明出现了重复的元素,则删除j对应的元素
arr.splice(j,1);
//当删除了当前j所在的元素以后,后边的元素会自动补位
//此时将不会再比较这个元素吧,我需要在比较一次j所在位置的元素
//使j自减
j--;
}
}
}
console.log(arr);
script>
<script>
var arr=["孙悟空","猪八戒","沙和尚"];
var arr2=["白骨精","玉兔精","蜘蛛精"];
var arr3=["二郎神","太上老君","玉皇大帝"];
/*
concat()可以连接两个或多个数组,并将新的数组返回
该方法不会对原数组产生影响
*/
var result=arr.concat(arr2,arr3,"牛魔王","铁扇公主");
/*
join()
该方法可以将数组转换为一个字符串
该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符
如果不指定连接符,则默认使用,作为连接符
*/
arr=["孙悟空","猪八戒","沙和尚","唐僧"];
result=arr.join("@-@");
/*
reverse()
该方法用来反转数组(前边的去后边,后边的去前边)
该方法会直接修改原数组
*/
arr.reverse();
//console.log(arr);
arr=["b","d","e","a","c"];
/*
sort()
可以用来对数组进行排序
也会影响原数组,默认会按照Unicode编码进行排序
*/
arr.sort();
//arr.reverse();
/*
即使对于纯数字的数组,使用sort()排序时,也会按照Unicode编码来排序,
多以对数字进行排序时,可能会得到错误的结果。
我们可以自己来指定排序的规则
我们可以在sort()添加一个回调函数,来指定排序规则,
回调函数中需要定义两个形参,
浏览器将会分别使用数组中的元素作为实参去调用回调函数
使用哪个元素调用不确定,但是肯定的是在数组中a一定在b前边
浏览器会根据回调函数的返回值来决定元素的顺序,
如果返回一个大于0的值,则元素会交换位置
如果返回一个小于0的值,则元素位置不变
如果返回一个0,则认为两个元素相等,也不交换位置
如果需要升序排列,则返回a-b
如果需要降序排列,则返回b-a
*/
arr=[5,4,2,1,3,6,8,7];
arr.sort(function(a,b){
//前边的大
/* if(a>b){
return -1;
}else if(a
//升序排列
//return a-b;
//降序排列
return b-a;
});
console.log(arr);
script>
<script>
function fun(a,b){
console.log("a="+a);
console.log("b="+b);
//alert(this);
}
var obj={
name:"obj",
sayName:function(){
alert(this.name);
}
};
/*
call()和apply()
这两个方法都是函数对象的方法,需要通过函数对象来调用
当对函数调用call()和apply()都会调用函数执行
在调用call和apply()可以将一个对象指定为第一个参数
此时这个对象将会成为函数执行时的this
call()方法可以将实参在对象之后依次传递
apply()方法需要将实参封装到一个数组中统一传递
this的情况:
1.以函数形式调用时,this永远都是window
2.以方法的形式调用时,this是调用方法的对象
3.以构造函数的形式,this是新创建的那个对象
4.使用call和apply调用时,this是指定的那个对象
*/
//fun.call(obj,2,3);
fun.apply(obj,[2,3]);
var obj2={
name:"obj2"
};
/* fun.apply();
fun.call();
fun(); */
//fun.call(obj);
//fun.apply(obj);
//fun();
//obj.sayName.apply(obj2);
script>
<script>
/*
在调用函数时,浏览器每次都会传递进两个隐含的参数:
1.函数的上下文对象 this
2.封装实参的对象 arguments
arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度
在调用函数时,我们所传递的实参都会在arguments中保存
arguments.length可以用来获取实参的长度
我们即使不定义形参,也可以通过arguments来使用实参,
只不过比较麻烦
arguments[0] 表示第一个实参
arguments[1] 表示第二个实参。。。
它里边有一个属性叫做callee,
这个属性对应一个函数对象,就是当前正在执行的函数的对象
*/
function fun(a,b){
//console.log(arguments instanceof Array);
//console.log(Array.isArray(arguments));
//console.log(arguments.length);
//console.log(arguments[1]);
console.log(arguments.callee==fun);
}
fun("hello",true);
script>
<script>
/*
Date对象
在JS中使用Date对象来表示一个时间
*/
//创建一个Date对象
//如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间
var d=new Date();
//创建一个指定的时间对象
//需要在构造函数中传递一个表示时间的字符串作为参数
//日期的格式 月份/日/年 时:分:秒
var d2=new Date("2/18/2011 11:10:30");
/*
getDate()
获取当前日期对象是几日
*/
var date=d2.getDate();
/*
getDay()
获取当前日期对象是周几
会返回0-6的值
0表示周日
1表示周一
。。。
*/
var day=d2.getDay();
/*
getMonth()
d2=new Date("12/13/2011 11:10:30");
获取当前时间对象的月份
会返回0-11的值
0表示1月
1表示2月
11表示12月
*/
var month=d2.getMonth();
/*
getFullYear()
获取当前日期对象的年份
*/
var year=d2.getFullYear();
//console.log(d2);
//console.log("date="+date);
//console.log("day="+day);
//console.log("month="+month);
//console.log("year="+year);
/*
getTime()
获取当前日期对象的时间戳
时间戳,指的是从格林威治标准时间的1970年1月1日,0时0分0秒
到当前日期所花费的毫秒数(1秒=1000毫秒)
计算机底层在保存时间时使用都是时间戳
*/
var time=d2.getTime();
//console.log(time/1000/60/60/24/365);
/* var d3=new Date("1/1/1970 0:0:0");
time=d3.getTime();
console.log(time); */
//利用时间戳来测试代码的执行的性能
//获取当前的时间戳
var start=Date.now();
for(var i=0;i<100;i++){
console.log(i);
}
var end=Date.now();
console.log("执行了,"+end-start+"毫秒");
script>
<script>
/*
Math
Math和其他的对象不同,它不是一个构造函数,
它属于一个工具类不用创建对象,它里边封装了数学运算相关的属性和方法
比如
Math.PI 表示的圆周率
*/
//console.log(Math.PI);
/*
abs()可以用来计算一个数的绝对值
*/
//console.log(Math.abs(-1));
/*
Math.ceil()
可以为一个数进行向上取整,小数位只要有值就自动进1
Math.floor()
可以对一个数进行向下取整,小数部分会被舍掉
Math.round()
可以对一个数进行四舍五入取整
*/
//console.log(Math.ceil(1.1));
//console.log(Math.floor(1.99));
//console.log(Math.round(1.4));
/*
Math.random()
可以用来生成一个0-1之间的随机数
生成0-10的随机数
生成一个0-x之间的随机数
Math.round(Math.random()*x)
生成一个1-10
生成一个x-y之间的随机数
Math.round(Math.random()*(y-x)+x)
*/
/* for(var i=0;i<100;i++){
//console.log(Math.round(Math.random()*10));
//console.log(Math.round(Math.random()*20));
//console.log(Math.round(Math.random()*9)+1);
//console.log(Math.round(Math.random()*8)+2);
//生成1-6之间的随机数
console.log(Math.round(Math.random()*5)+1);
} */
/*
max() 可以获取多个数中的最大值
min() 可以获取多个数中的最小值
*/
var max=Math.max(10,45,30,100);
var max=Math.min(10,45,30,100);
//console.log(min);
/*
Math.pow(x,y)
返回x的y次幂
*/
//console.log(Math.pow(12,3));
/*
Math.sqrt()
用于对一个数进行开方运算
*/
console.log(Math.sqrt(2));
script>
<script>
/*
基本数据类型
String Number Boolean Null Undefined
引用数据类型
Object
在JS中为我们提供了三个包装类,通过这三个包装类可以将基本数据类型的数据转换为对象
String()
可以将基本数据类型字符串转换为String对象
Number()
可以将基本数据类型的数字转换为Number对象
Boolean()
可以将基本数据类型的布尔值转换为Boolean对象
但是注意,我们在实际应用中不会使用基本数据类型的对象,
如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果
*/
//创建一个Number类型的对象
//num=3;
var num=new Number(3);
var num2=new Number(3);
var str=new String("hello");
var str2=new String("hello");
var bool=new Boolean(true);
var bool2=true;
//向num中添加一个属性
num.hello="abcdefg";
//console.log(str==str2);
var b=new Boolean(false);
/* if(b){
alert("我执行了~~~");
} */
/*
方法和属性只能添加给对象,不能添加给基本数据类型
当我们对一些基本数据类型的值去调用属性和方法时,
浏览器会临时使用包装类将其转换为对象,然后在调用对象的属性和方法
调用完以后,再将其转换为基本数据类型
*/
var s=123;
s=s.toString();
s.hello="你好";
console.log(s.hello);
console.log(typeof s);
script>
<script>
//创建一个字符串
var str="Hello Atguigu";
/*
在底层字符串是以字符数组的形式保存的
["H","e","l"]
*/
/*
length属性
可以用来获取字符串的长度
*/
//console.log(str.length);
//console.log(str[5]);
/*
charAt()
可以返回字符串中指定位置的字符
根据索引获取指定的字符
*/
str="Hello Atguigu";
var result=str.charAt(6);
/*
charCodeAt()
获取指定位置字符的字符编码(Unicode编码)
*/
result=str.charCodeAt(0);
/*
String.fromCharCode()
可以根据字符编码去获取字符
*/
result=String.fromCharCode(0x2692);
/*
concat();
可以用来连接两个或多个字符串
作用和+一样
*/
result=str.concat("你好","再见");
/*
indexOf()
该方法可以检索一个字符串中是否含有指定内容
如果字符串中含有该内容,则会返回其第一次出现的索引
如果没有找到指定内容,则返回-1
可以指定一个第二个参数,指定开始查找的位置
lastIndexOf();
该方法的用法和indexOf一样,
不同的是indexOf是从前往后找
而lastIndexOf是从后往前找
也可以指定开始查找的位置
*/
str="hello hatguigu";
result=str.indexOf("h",1);
result=str.lastIndexOf("h",5);
/*
slice()
可以从字符串中截取指定的内容
不会影响原字符串,而是将截取到内容返回
参数:
第一个,开始位置的索引(包括开始位置)
第二个,结束位置的索引(不包括结束位置)
如果省略第二个参数,则会截取到后边所有的
也可以传递一个负数作为参数,负数的话会从后边计算
*/
str="abcdefghijk";
result=str.slice(1,4);
result=str.slice(1,-1);
/*
substring()
可以用来截取一个字符串,和slice()类似
参数:
第一个,开始截取位置的索引(包括开始位置)
第二个,结束位置的索引(不包括结束位置)
不同的是这个方法不能接受负值作为参数
如果传递了一个负值,则默认使用0
而且它会自动调整参数的位置,如果第二个参数小于第一个,则自动交换
*/
result=str.substring(0,1);
/*
substr()
用来截取字符串
参数:
1.截取开始位置的索引
2.截取的长度
*/
str="abcdefg";
result=str.substr(3,2);
/*
split()
可以将一个字符串拆分为一个数组
参数:
需要一个字符串作为参数,将会根据该字符串去拆分数组
*/
str="abcbcdefghij";
result=str.split("d");
/*
如果传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素
*/
result=str.split("");
//console.log(Array.isArray(result));
//console.log(result[0]);
console.log(result);
str="abcdefg";
/*
toUpperCase()
将一个字符串转换为大写并返回
*/
result=str.toUpperCase();
str="ABCDEFG";
/*
toLowerCase()
将一个字符串转换为小写并返回
*/
result=str.toLowerCase();
//console.log(result);
script>
<script>
/*
正则表达式
[email protected]
[email protected] adminatguigu.com
邮件的规则:
1.前边可以是xxxx乱七八糟
2.跟着一个@
3.后便可以是xxxx乱七八糟
4..com获取其他的乱七八糟
正则表达式用于定义一些字符串的规则,
计算机可以根据正则表达式,来检查一个字符串是否符合规则,
获取将字符串中符合规则的内容提取出来
*/
//创建正则表达式的对象
/*
语法:
var 变量=new RegExp("正则表达式","匹配模式");
使用typeof检查正则对象,会返回object
var reg=new RegExp("a");这个正则表达式可以来检查一个字符串中是否含有a
在构造函数中可以传递一个匹配模式作为第二个参数,
可以是
i 忽略大小写
g 全局匹配模式
*/
var reg=new RegExp("ab","i");
var str="a";
/*
正则表达式的方法:
test()
使用这个方法可以以用来检查一个字符串是否符合正则表达式的规则,
如果符合返回true,否则返回false
*/
var result=reg.test(str);
//console.log(result);
console.log(reg.test("Ac"));
script>
<script>
/*
使用字面量来创建正则表达式
语法:var 变量=/正则表达式/匹配模式
使用字面量的方式创建更加简单
使用构造函数创建更加灵活
*/
//var reg=new RegExp("a","i");
var reg=/a/i;
//console.log(typeof reg);
//console.log(reg.test("abc"));
//创建一个正则表达式,检查一个字符串中是否有a或b
/*
使用|表示或者的意思
*/
reg=/a|b|c/;
/*
创建一个正则表达式来检查一个字符串中是否有字母
*/
//reg=/a|b|c|d|e|f|g/;
/*
[]里的内容也是或的关系
[ab]==a|b
[a-z]任意小写字母
[A-Z]任意大写字母
[A-z]任意字母
[0-9]任意数字
*/
reg=/[A-z]/;
//检查一个字符串中是否含有abc或adc或aec
reg=/a[bde]c/;
/*
[^]除了
*/
reg=/[^ab]/;
reg=/[^0-9]/;
console.log(reg.test("12a3456"));
script>
<script>
var str="1a2b3c4d5e6f7";
/*
split()
可以将一个字符串拆分为一个数组
方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
这个方法即使不指定全局匹配,也会全都拆分
*/
/*
根据任意字母来将字符串拆分
*/
var result=str.split(/[A-z]/);
//console.log(result);
/*
search()
可以搜索字符串中是否含有指定内容
如果搜索到指定内容,贼会返回第一次出现的索引,如果没有搜索到返回-1
它可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串
search()只会查找第一个,即使设置全局匹配也没用
*/
str="hello abc hello aec afc";
/*
搜索字符串中是否含有abc 或aec 或afc
*/
result=str.search("/a[bef]c/");
//console.log(result);
/*
match()
可以根据正则表达式,从一个字符串中将符合条件的内容提取出来
默认情况下我们的match只会找到第一个符合要求的内容,找到以后就停止检索
我们可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容
可以为一个正则表达式设置多个匹配模式,且顺序无所谓
match()会将匹配的内容封装到一个数组中返回,即使只查询到一个结果
*/
str="1a2a3a4a5e6f7A8B9C";
result=str.match(/[a-z]/ig);
//console.log(result[2]);
/*
replace()
可以将字符串中指定内容替换为新的内容
参数:
1.被替换的内容,可以接受一个正则表达式作为参数
2.新的内容
默认值会替换第一个
*/
//result=syr.replace("/[a-z]/gi","@_@");
result=syr.replace("/[a-z]/gi","");
//console.log(result);
script>
<script>
/*
创建一个正则表达式检查一个字符串中是否含有aaa
*/
/*
量词
通过量词可以设置一个内容出现的次数
量词只对它前边的一个内容起作用
{n} 正好出现n次
{m,n} 出现m-n次
{m,} m次以上
+ 至少一个,相当于{1,}
* 0个或多个,相当于{0,}
? 0个或1个,相当于{0,1}
*/
var reg=/a{3}/;
//ababab
reg=/(ab){3}/;
reg=/b{3}/;
reg=/ab{3,}c/;
reg=/ab+c/;
reg=/ab*c/;
reg=/ab?c/;
//console.log(reg.test("ac"));
/*
检查一个字符串中是否以a开头
^ 表示开头
$ 表示结尾
*/
reg=/^a/;//匹配开头的a
reg=/a$/;//匹配结尾的a
//console.log(reg.test("abcabca"));
/*
如果在正则表达式中同时使用^ $则要求字符串必须完全符合正则表达式
*/
reg=/^a$/;
//console.log(reg.test("bbca"));
/*
创建一个正则表达式,用来检查一个字符串是否是一个合法手机号
手机号的规则:
1 3 567890123(11位)
1.以1开头
2.第二位3-9任意数字
3.三位以后任意数字9个
^1 [3-9] [0-9]{9}$
*/
var phoneStr="13067890123";
var phoneReg=/^1[3-9][0-9]{9}$/;
console.log(phoneReg.test(phoneStr));
script>
<script>
/*
检查一个字符串中是否含有 .
. 表示任意字符
在正则表达式中使用\作为转义字符
\. 来表示 .
\\ 表示 \
注意:使用构造函数时,由于它的参数是一个字符串,而\是字符串中转义字符
如果要使用\则需要使用\\来代替
*/
var reg=/\./;
reg=/\\/;
reg=new RegExp("\\.");
reg=new RegExp("\\\\");
/*
\w
任意字母、数字、_ [A-z0-9_]
\W
除了字母、数字、_ [^A-z0-9_]
\d
任意的数字 [0-9]
\D
除了数字 [^0-9]
\s
空格
\S
除了空格
\b
单词边界
\B
除了单词边界
*/
reg=/\w/;
reg=/\W/;
reg=/\d/;
reg=/\D/;
reg=/\s/;
reg=/\S/;
/*
创建一个正则表达式检查一个字符串中是否含有单词child
*/
reg=/\bchild\b/;
//console.log(reg.test("hello children"));
//接受一个用户的输入
//var str=prompt("请输入你的用户名:");
var str=" he llo ";
//去除掉字符串中的前后的空格
//去除空格就是使用""来替换空格
console.log(str);
//str=str.replace(/s/g,"");
//去除开头的空格
//str=str.replace(/^\s*/,"");
//去除结尾的空格
//str=str.replace(/\s*$/,"");
///^\s*|\s*$/g 匹配开头和结尾的空格
str=str.replace(/^\s*|\s*$/g,"");
console.log(str);
script>
<script>
/*
电子邮件
[email protected]
任意字母数字下划线.任意字母数字下划线.@任意字母数字.任意字母(2-5位).任意字母(2-5位)
\w{3,} (\.\w+)* @ [A*z0-9]+ (\.[A-z]{2-5}){1,2}
*/
var emaiReg=/^\w{3,}(\.\w+)*@[A*z0-9]+(\.[A-z]{2-5}){1,2}$/;
var email="[email protected]";
console.log(emaiReg.test(email));
script>
如何学好web前端
感兴趣,够努力。