JavaScript基础知识_笔记
JS的特点:
- 解释型语言
- 动态语言
- 基于原型的面向对象
基本输出:
alert(‘这是第一个js代码’);//弹出警告框
document.write(“啦啦啦啦啦啦啦”);//可以向body输出一个内容
console.log(“向控制台输出一个内容”);//控制台输出内容
基本语法:
- JS注释:多行注释,注释内容不会被执行,但是可以在源代码中查看。(养成良好的代码注释习惯);
- JS中严格区分大小写;
- 每一条语句都以;结尾。(如果不添加分号,浏览器会自动添加,但那还是会消耗一些系统资源,有时候会加错分号)。
- JS会忽略多个空格和换行;
字面量和变量
- 字面量,都是些不可变的量:1,2,3,4,…,字面量都是可以直接使用的,但一般不会直接使用;
- 变量:可以用来保存字面量,变量的值可以直接改变,变量更加方便我们使用,所以自爱开发中都是通过变量保存一个字面量,而且很少直接使用字面量;
声明变量:var a;
标识符
- 在JS中所有的可以由我们自主命名的都可以称为是标识符;例如:变量名、函数名、属性名;
- 命名一个标识符时需遵守如下的规则:
1.标识符中可以含有字母、数字、_、KaTeX parse error: Double subscript at position 11: ,如:var a_1_̲ =12;
2.不能以数字开头;
3.不能是ES中的关键字或保留字;
4.标识符一般都采用驼峰命名法:首字母小写,每个单词的开头字母大写,其余小写; - JS底层标识符时实际上是采用的UNicode编码,所以理论上讲,所有的Utf-8中含有的内容都可以作为标识符;
数据类型
- String:字符串
- Number:数值
- Boolean:布尔值
- Null:空值
- Undefined:未定义
- Object:对象
- String,number,boolean,null,undefined属于基本数据类型;
- Object属于引用数据类型;
#####String字符串
1.在JS字符串中需要使用引号引起来
2.使用双引号或者单引号都可以,但是不要混着用;
3.引号不能嵌套,双引号里不能放双引号,单引号里不能放单引号;
4.在字符串中可以使用\作为转义字符,当表示一些特殊符号是可以使用\进行转义:
" 表示 "
’ 表示 ’
\n 表示换行
\t 制表符
\ 表示 \
Number
- 在JS中所有的数值都是Number类型,包括整数和浮点数;
- JS中可以表示的数字的最大值:
Nmuber.MAX_VALUE : 1.7976931348623157e+308
如果使用Number表示的数字超过了最大值,则会返回Infinity表示正无穷; - NAN是一个特殊的数字,表示 “Not A Number”;使用typeof检查一个NaN会返回number;
var a = NaN; typeof a 返回number;
var a = “NaN”; typeof a 返回string;
可以使用一个运算符typeof来检查一个变量类型
语法:typeof 变量
检查字符串时会返回string,
检查数值时会返回number.
console.log(typeof a);
- 在JS中整数的运算基本可以保证精确;
- 如果使用JS进行浮点运算,可能得到一个不精确的结果,所以千万不要使用JS进行对精确度要求比较高的运算;
#####Boolean 布尔值
布尔值只有两个,主要用来做逻辑判断 - true 表示真
- false 表示假
Null
Null类型的值只有一个,就是null;
null这个值专门用来表示一个为空的对象;
typeof 检查null 返回"Object";
Undefined
Undefined类型的值只有一个,就是undefine;
当声明一个变量但并没有赋值时,它的值就是undefined;
var a = undefined;
console.log(typeof a);
//返回undefined;
强制类型转换
指将一个数据类型强制转换为其他的数据类型
类型转换主要指,将其他的数据类型转换为String Number Boolean;
- 将其他类型转换为String:
方式一:调用被转换数据类型的toString()方法,该方法不会影响到原变量,它将转换的结果返回;
toString(16)转化进制;
如:var a =255; a = a.toString(16); // 16
注意:null和undefined这两个值没有tostring()方法,若是调用则报错;
var a = 123;
a = a.toString();
console.log(typeof a);//返回string
console.log(a);
方式二:调用String()函数,并将被转换的数据作为参数传递给函数;
使用String()函数做强制类型转换时,对于Number 和 Boolean实际上就是调用的toString()方法,但是对于null 和 undefined不会调用toString()方法,它会将null直接转换为"null",将undefined转换为"undefined",都转换成字符串类型。
var b = 456;
b = String(b);//转换b,参数就是b
console.log(typeof b);//返回string
console.log(b);
- 将其他类型转换为Number:
方式一:使用Number()函数,
1. 字符组 - -> 数字
(1)如果是纯数字的字符串,则直接将其转换为数字:
var a = "123";
a = Number(a);
console.log(typeof a); //number
console.log(a); //123
(2)如果字符串中有非数字的内容,则转换为NaN:
var a = "abc";
a = Number(a);
console.log(typeof a); //number
console.log(a); //NaN
(3)如果字符串是一个空串或者是一个全是空格的字符串,则转换为0:
var a = " ";
a = Number(a);
console.log(typeof a); //number
console.log(a); //0
2.布尔 --> 数字
- true 转成 1
- false 转成 0
3.null --> 数字
- null 转成 0
4.undefined --> 数字
- undefined 转成 数字NaN
方式二:这种方式专门用来对付字符串,
parseInt()把一个字符串转换为一个整数,能够获取字符串中的有效的整数内容取出来,然后转换为Number。
注意:如果对非String使用parseInt()或者parseFloat()它会先将其转换为String,然后再操作。
var a = "123px";
a = parseInt(a);
console.log(typeof a);// number
console.log(a); //123
parseFloat()把一个字符串转换为一个浮点数;
var a = "123.456px";
a = parseFloat(a);
console.log(typeof a);//number
console.log(a);//123.456
-
将其他类型转换为Boolean:
方式一:使用Boolean()函数:
(1). 数字 --> 布尔:
除了0和NaN,其余的都是true
(2). 字符串 --> 布尔:
除了空串,其余的都是true
(3).null 和 undefined 都是false
(4).对象也会转换为true具体举例:
var a = 123;
a = Boolean(a);
console.log(typeof a);
console.log(a);
a = 0;//false
a = Indinity; //true
a = NaN ;//false
a = "hello"; //true
方式二:隐式类型转换:
为任意数据类型做两次非运算,即可将其转换为Boolean值
var b =10;
b = !!b; //true
console.log(typeof b); //boolean
补充: 其他进制的数字
1.在JS中,如果需要表示16进制的数字,则需要以0x开头:
var a = 0x10;
console.log(a);// 16
2.如果需要表示8进制的数字,则需要以0开头:
var a = 070;
console.log(a);// 56
3.如果需要表示2进制的数字,则需要以0b开头,但是不是所有浏览器都支持:
var a = 0b10;
console.log(a);// 2
4.可以在parseInt()中传递第一个第二个参数,来指定数字的进制:
var a = "070";
var b = parseInt(a, 8);
var c = parseInt(a, 10);
console.log(b); //56
console.log(c); //70
运算符
运算符也叫操作符,通过运算符可以对一个或多个值进行运算,并获取运算结果,比如typeof就是运算符,可以来获得一个值的类型,它会将该值的类型以字符串的形式返回。
如 number string boolean undefined object 这些都是字符串的形式,只不过是用来描述类型。
var a =123;
var result = typeof a;
console.log(result);//number
console.log(typeof result);//string
- 算数运算符: + - * / %
当对非Number类型的值进行运算时,会将这些值转换为Number然后再运算。
任何值和NaN做运算都是NaN;
“+”:
-
可以对两个值进行加法运算,并将结果返回;
-
如果对两个字符串进行加法运算,则会做拼串;(两个字符串拼接在一起) ;
var str = "你好" + "我是" + "啦啦啦啦啦"; console.log(str); //你好我是啦啦啦啦啦
-
任何的值和字符串做加法运算,都会先转换为字符串,然后再和字符串做拼串的操作。
var str = 123 + "1"; console.log(str); // 1231
-
任何值和字符串相加都会转换成字符串,做拼接操作;利用这一特点,将任意数据类型转换为String,只需将任意的数据类型 + 一个 ""即可将其转换为String,这是一种隐式的类型转换,由浏览器自动转换,实际上也是调用String()函数;
-
var c = 123; c = c + ""; console.log(typeof c); //string console.log("c = "+c); //c = 123 //从左往右进行运算 var c = 1 + 2 + "3"; var re = "1" + 2 + 3; console.log(typeof c); console.log("c = "+c); // c =33 console.log("re = "+re);//re = 123
"-":
-
可以对两个值进行减法运算,并将结果返回
var a;
a = 100 - “1”;
console.log(a); //99
“*”: -
可以对两个值进行乘法运算;
a = 2 * "8"; //16 a = 2 * undefined; //NaN a = 2 * null; //0
“/”:
- 可以对两个值进行乘法运算;
a = 4 / "2"; // 2
任何值做 - * /运算都会自动转换为Number;
我们可以利用这一特点做隐式类型转换,可以通过一个值 -0、 *1、 /1来将其转换为Number,原理和Number()函数一样,使用起来更加简单;
“%”:
- 取模运算
2.一元运算符,只需一个操作符:
“+ ”正号
+ 正号不会对数字产生任何影响
var a = 123;
a = +a;
console.log(a); //123
“- ”负号
- 可以对数字进行负号的取反
对于非Number类型的值:它会将先转换为Number,然后在运算;可以对其他数据类型使用+,来将其转换为Number,它的原理和Number()函数一样;
a =true;
a = -a;
console.log(a);
a = 1 + + "2" + 3; // +"2" = 2;所以就是a=1+2+3
b = 1 + "2" +3;
console.log("a = "+a); //a=6
console.log("b = "+b); //b=123
自增:通过自增可以使变量在自身的基础上增加1;
自增分成两种:i++ 和 ++i;
- 无论是i++还是++i,都会使原变量值立即自增1;
- 不同的是i++ 和 ++i的值不同:
-
i++的值等于原变量的值(自增前的值),先输出再计算
var i = 1; console.log(i++); //1 console.log("i = "+i); //i=2
-
++i的值等于原变量的新值(自增后的值),先计算再输出
-
var i = 1; console.log(++i); //2 console.log("i = "+i); //i = 2 var a = 1; console.log(a++); //2 console.log(++a); //3 var b = 20; //20 + 22 + 22 = 64 var result = b++ + ++b + b; console.log("result = "+result); //64
-
自减:通过自减可以使变量在自身的基础上减1;
分成两种:i-- 和 --i
- 不同的是i-- 和 --i的值不同:(原理同自增);
练习:
var n1=10, n2 = 20;
var n = n1++; //n1 = 11, n1++ = 10
console.log('n='+n); //10
console.log('n1='+n1); //11
n = ++n1; //n =12 ++n1 = 12
console.log('n='+n); //12
console.log('n1='+n1); // 12
n = n2--; //n2=19 n=20
console.log('n='+n); //20
console.log('n2='+n2); //19
n = --n2; //n = 18 --n2=18
console.log('n='+n); //18
console.log('n2='+n2); //18
3.逻辑运算符
三种逻辑运算符:!、&&、||
-
!:如果对非布尔值进行运算,则会将其转换为布尔值,然后再取反,所以我们可以利用该特点来将一个其他的数据类型转换为布尔值,可以为任意一个数据类型取两次反,来将其转换为布尔值,原理和Boolean()函数一样。
var b =10; b = !b; // false b = !!b; // true console.log(typeof b); //boolean
-
&&:两个值中只要有一个值为false就返回false;
JS中的“与”为短路与,如果第一个值为false,则不会看第二个值。若第一个值为true,则会检查第二个值; -
||:两个值中只要有一个值为true就返回true;
JS中的“或”为短路或,如果第一个值为true,则不会检查第二个;若第一个值为false,则会检查第二个值;
&& || 非布尔值的情况:
-
对于非布尔值进行与或运算的,会先将其转换为布尔值然后再运算,并且返回原值。
-
规则:
与运算:
如果第一个值为true,则必然返回第二个值;
如果第一个值为false,则直接返回第一个值;//true && true //若两个值都为true,则返回后边的值 var res = 1 && 2; console.log("res = "+res); // 2 var res = 2 && 1; console.log("res = "+res);// 1 var res = 0 && 1; console.log("res = "+res); // 0 var res = 1 && 0; console.log("res = "+res); // 0 //false && false var res = NaN && 0; console.log("res = "+res);// NaN var res = 0 && NaN; console.log("res = "+res);// 0
或运算:
如果第一个值为true,则直接返回第一个值;
如果第一个值为false,则返回第二个值;
res = NaN || 1; // 1
res = “” || “hello”; // hello
4.赋值运算符:+=
5.关系运算符:>、>=、<、<=:如果关系成立,则返回true;
比较两个字符串时,比较的是字符串的字符编码。
比较字符编码时是一位一位进行比较,
如果两位一样,则比较下一位,所以借用它来对英文进行排序;
比较两个字符串数字大小时,一定要注意转型;(“5” --> +“5”)
res = "abc" < "b";
//先是比较a与b的大小,若a<b,则比较b与b的大小,b<b不成立,返回false;
在字符串中使用转义字符输入unicode编码:\u四位编码;
console.log("\u2620"); //☠
6.相等运算符:比较两个值是否相等;相等返回true,否则返回false;
-
使用 == 来做相等运算;
当使用 ==来比较两个值时,如果值的类型不同,则会自动进行类型转换,然后再比较;console.log("1" == 1); //true //undefined 衍生自null console.log(undefined == null); //true NaN不和任何值相等,包括它本身 console.log(NaN == NaN); //false 可以通过isNaN()函数来判断一个值是否是NaN,是就返回true;
-
!=:不相等返回true,相等返回false;
-
不相等也会对便利进行自动的类型转换,如果转换后相等它也会返回fasle;
-
===:判断两个值是否全等,和相等类型;
- 不同的是:如果两个值的类型不同,直接返回false;
-
!==:判断两个值是否不全等,和不等类型;
- 不同的是:如果两个值的类型不同,直接返回true;
7.条件运算符:
- 不同的是:如果两个值的类型不同,直接返回true;
-
语法:条件表达式?语句1:语句2
-
执行流程:条件运算符在执行时,首先对条件表达式进行求值,如果该值为true,则执行语句1,并返回执行结果,如果为false,则执行语句2,并返回执行结果。
var max = a > b ? a : b; //判断a b c中的最大值 max = max > c ? max : c;
8.运算符的优先级:优先级越高越先计算,若是一样高,则从左往右计算;
图中越上优先级越高:
/*
分析:
如果||的优先级高,或者两个一样高,则应该返回3
如果&&的优先级高,则应该返回1
*/
var res = 1 || 2 && 3;
console.log("res = "+ res);// 1
当不清楚优先级高低时,可以用括号改变运算顺序
语句:{}:代码块
语句分类:
1.条件判断语句:if{…} else if{…}else{…}
prompt()可以弹出一个提示框,该提示框中会有一个文本框
用户可以在文本框中输入一段内容,该函数需要一个字符串作为参数
该字符串将会作为提示框的提示文字
用户输入的内容将会作为函数的返回值返回,可以定义一个变量来接收该内容
var score = prompt("请输入小明的期末成绩:");
alert(score);
2.条件分支语句:switch() { case:}
3.循环语句:
var a = prompt();
for(var i=0; i < a; i++){
document.write(i + "<br/>");
}
//输入 3;
//输出:0
// 1
// 2
-
while语句在执行时:先对条件表达式进行求值判断,如果为true则继续执行循环体,执行完毕继续对表达式进行判断,如果为fasle则终止循环。
-
do…while循环:先执行循环体,执行完毕后对while后的条件表达式进行判断,如果为true继续执行,若为false,则终止循环。
-
for语句:for(初始表达式; 条件表达式; 更新表达式)
①执行初始表达式,初始化变量
②执行条件表达式,判断是否执行循环,
③若为true,则执行循环,若为false,则终止;
④执行更新表达式,执行完毕继续重复②for( ; ; ){ //死循环 }
练习:判断输入的数是否是质数
var num = prompt("请输入一个数字:");
if(num < 0)
{
alert("不合法~");
}
else
{
//默认当前num是质数
var flag = true;
for(var i =2; i < num; i++)
{
if(num % i== 0 )
{
flag = false;
}
}
if(flag)
{
alert(num + "是质数");
}
else{
alert(num + "不是质数");
}
}
//九九乘法表
for(var i=1; i<10; i++)
{
for(var j = 1; j <= i; j++)
{
document.write( i + "*"+ j +" ="+i*j);
// document.write( "<span>" + i +" * "+ j +" = "+ i*j +"</span>");
document.write(" ");
}
document.write("<br />");
}
break 和 continue 关键字
-
break关键字可以用来退出switch或循环语句;
- 不能在if语句中使用break和continue;
- break关键字会立即终止离它最近的那个循环语句;
-当想结束指定的循环语句时,
可以为循环语句创建一个label,来标识当前的循环
label:循环语句
使用break语句时,可以在break后跟着一个label,
这样break将会结束指定的循环,而不是最近的 ;outer: for(var i=0; i<5; i++) { console.log("@外层循环"+i); for(var j=0; j<5; j++) { break outer; console.log("内层循环:"+ j); } }
2.continue关键字:立即结束当前循环,同样默认对离它最近的那个循环语句起作用;
补充:
//测试以下程序的性能
//在程序开始之前,开启计时器
//console.time("计时器的名字")可以用来开启一个计时器
//它需要一个字符串作为参数,这个字符串将会作为计时器的标识
console.time("test");
for(var i=2; i<=100; i++)
{
var flag = true;
for(var j=2; j<Math.sqrt(i); j++)
{
if(i%j == 0)
{
flag = false;
}
}
if(flag)
{
//console.log(i);
}
}
console.timeEnd("test");
Object 对象
对象属于一种符合的数据类型,在对象中可以保存多个不同数据类型的属性;
对象的分类:
-
内建对象
- 由ES标准中定义的对象,在任何的ES的实现中都可以使用
- 比如:Math String Number Boolean Function Object…
2.宿主对象
- 由JS的运行环境提供的对象,目前来讲主要由浏览器提供的对象
- 比如:BOM DOM
3.自定义对象:由开发人员自己创建的对象(1)创建对象: 在对象中保存的值称为属性 (2)向对象添加属性: 语法: 对象.属性名 = 属性值 var obj = new Object(); obj.name = "张三"; obj.gender = "男"; obj.age = 20; console.log(obj); //{name: "张三", gender: "男", age: 20} (3)读取对象中的属性: 语法:对象.属性名 console.log(obj.gender); //男 (4)修改对象的属性值: 语法:对象.属性值 = 新值 (5)删除对象的属性值 语法:delete 对象.属性值
对象更像一个容器,可以装不同的属性
属性名:
对象的属性名不强制要求遵守标识符的规范,但是我们还是尽量按照标识符的规范去做。
如果使用特殊的属性名,不能采用 . 的方式来操作,需要使用另一种方式,读取时也要采取这种方式;
语法:对象[“属性名”] = 属性值
如:obj["123"] = 789;
读取: console.log(obj["123"]);
(一般情况下来说,属性名不能以数字开头,除非你真的想用,就采取以上方法)
使用 [ ]这种形式去操作属性更加的灵活
在[ ]中可以直接传递一个变量,这样变量值是多少就会读取哪个属性;
obj["123"] = 789;
var n = "123";
console.log(obj[n]); //789
//根据不同的变量取不同的值,这种方式更灵活
属性值:
-
JS对象的属性值,可以是任意的数据类型,甚至也可以是一个对象
obj.test = "hello"; obj.test = 123; obj.test = true; obj.test = null; var obj = new Object(); var obj2 = new Object(); obj2.name = "李四"; //将obj2设置为obj的属性 obj.test = obj2; console.log(obj.test); // {name: "李四"} console.log(obj.test.name); //李四
-
in 运算符:通过该运算符可以检查一个对象中是否含有指定的属性,如果有则返回true,没有返回false;
- 语法:“属性名” in 对象
//检查属性是否存在
console.log("test2" in obj); //没有 false
- JS的变量都是保存到栈内存中的,
- 基本数据类型的值直接在栈内存中存储;
值与值之间是独立存在的,修改一个变量不会影响其他的变量 - 对象保存在堆内存中,每创建一个新对象,就会在堆内存中开辟出一个新的空间,两变量保存的是对象的内存地址(对象的引用),如果两个对象保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响。
- 基本数据类型的值直接在栈内存中存储;
var a = 123;
var b = a;
a++;
console.log("a = "+a); //124
console.log("b = "+b); //123
//变量a分配了一个内存,b也分配了一个内存,两个都拥有独立的内存地址,当a的值发生改变并不影响b的值
var obj = new Object();
obj.name = "李四";
var obj2 = obj;
console.log(obj.name);//李四
console.log(obj2.name);//李四
//当name的值发生改变时,这两个输出都会随之改变,
//当obj2设置为null时,相当于与obj断了联系,obj不会受到影响
/*
比较两个基本数据类型的值时,就是比较值,
而比较两个引用数据类型时,它是比较对象的内存地址,
如果两个对象是一模一样的,但是地址不同,它也会返回false;
*/
var c =10;
var d =10;
console.log(c == d);//true
var obj3 = new Object();
var obj4 = new Object();
obj3.name = "王五";
obj4.name = "王五";
console.log(obj3 == obj4); //false
//相当于是长得很像的双胞胎,但本质上是不一样的
总结:基本数据类型保存的是值,引用数据类型保存的是地址
对象字面量
- 使用对象字面量来创建一个字面量
- 使用对象字面量:可以在创建对象时,直接指定对象中的属性
语法:{属性名 :属性值,属性名 :属性值…};
对象字面量的属性名可以加引号也可以不加,建议不加,
如果要使用一些特殊的名字,必须加引号;
属性名和属性值是一组一组的名值对结构
名和值之间使用 :连接,多个名值之间使用 ,隔开
如果一个属性之后没有其他属性了,就不要写逗号;
函数
- 函数也是一个对象
- 函数中可以封装一些功能,在需要时可以执行这些功能;
- 使用typeof检查一个函数对象时会返回function;
- 函数中的代码会在函数调用的时候执行
调用函数语法,函数对象();
当调用函数时,函数中封装的代码会按顺序执行 - 使用函数声明来创建一个函数
语法:function 函数名([形参1,形参2…形参N]){
语句…
}
function fun2()
{
console.log("这是我的第二个函数~~");
alert("哈哈哈哈哈");
}
fun2();
//console.log(fun2);
立即执行函数
函数定义完, 立即被调用,这种函数叫做立即执行函数
立即执行函数往往只会执行一次
(function(){
alert("我是一个立即执行函数~~~");
})();
- 使用函数表达式来创建一个函数
var 函数名 = function ([形参1,形参2…形参N]){
语句…
} var fun3 = function(){
console.log(“我是啦啦啦啦啦啦啦啦~”);
};//相当于赋值函数
fun3();
补充:
函数也可以成为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法,调用函数就调用对象的方法;
var obj = {
name: "张三",
age : 20,
gender : "男"
};
obj.sayName = function(){
console.log(obj.name);
};
obj.sayName();//张三
函数参数
- 定义一个用来求两个数和的函数
可以在函数()中来指定一个或多个形参;
多个形参之间使用,隔开
function sum(a, b){
console.log(a+b);
}
sum(123,456);
// 在调用函数时,可以在()指定实参
// 实参将会赋值给函数中对应的形参
/*
调用函数时解析器不会检查实参的类型
所以要注意,是否有可能接收到非法的参数,
如果有可能则需要岁参数进行类型的检查
函数的实参可以是任意的数据类型
*/
sum(123,"hello");
/*
调用函数时解析器不会检查实参的数量
多余的实参不会被赋值
如果实参的数量少于形参的数量,则没有对应的实参的形参将是undefined;
*/
sum(123,345,"hello",true);//486
sum(123); //NaN
- 实参可以是任意数据类型,也可以是一个对象,
当我们的参数过多时,可以将参数封装到一个对象中,然后通过对象传递
function sayHello(o){
//console.log("o = "+ o);
console.log("我是"+o.name+ ",我今年" +o. age + ",性别" + o.gender);
}
sayHello("张三",20,"男");
var obj = {
name : "张三",
age:20,
gender : "男"
};
sayHello(obj);
- 实参可以是一个对象,也可以是一个函数
function fun(a){
//console.log("a ="+a);
a(obj);
}
fun(sayHello);//直接调用函数也可
function mianji(r){
return 3.14 * r * r;
}
fun(mianji);
/*输出:a =function mianji(r){
return 3.14 * r * r;
}
函数对象,相当于直接使用函数对象;
*/
fun(mianji(4));
//输出:a =50.24;调用函数,相当于使用的函数的返回值
通俗的说,mianji()函数可以比喻成可以做冰激凌的机器,调用mianji()相当于直接做出一个冰激凌给别人,返回最终结果,而调用mianji相当于是直接把整台机器给别人,返回函数本身。
返回值
- return 后的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果
- 如果return语句后不跟任何值就相当于返回一个undefined。
- 如果函数中不写return,则也会返回undefined。
枚举对象中的属性
- 使用 for … in 语句
语法:
for(var 变量 in 对象)
{
}
for .. in 语句对象中有几个属性,循环体就会执行几次
var obj = {
name: "张三",
age : 20,
gender : "男",
address : "长沙"
};
for(var n in obj){
console.log("属性名:"+n);
console.log("属性值:"+obj[n]);
//根据变量取对象的值用[ ],用 obj.n 是获取不到obj里的属性值,因为不存在n这个属性;
}
作用域
指一个变量的作用范围
在JS中有两种作用域:
1.全局作用域
(1)直接编写在script标签中的JS代码,都在全局作用域
(2)全局作用域在页面打开时创建,在页面关闭时销毁
(3)在全局作用域中有一个全局对象window,它代表的事一个浏览器窗口,它由浏览器创建我们可以直接使用
在全局作用域中:
①创建的变量都会作为window对象的属性保存。
var a = 10;
console.log(a);// 10; 相当于console.log(window.a)
②创建的函数都会作为window的方法保存
function fun(){
console.log("我是fun函数");
}
window.fun();//window才是最大套娃~~
③全局作用域中的变量都是全局变量,在页面的任意部分都可以访问的到;
2.函数作用域
(1)调用函数是创建函数作用域,函数执行完毕后,函数作用域销毁
(2)每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的
(3)函数作用域中可以访问到全局作用域的变量,
在全局作用域中无法访问到函数作用域的变量
var a = 10;
function fun(){
var b =8;
console.log("a = "+a);
}
fun(); //a =10
console.log("b = "+b);//报错
(4)当在函数作用域操作一个变量时,它会现在自身作用域中寻找,如果有直接使用,若没有则向上一级作用域中寻找(就近原则);如果全局作用域依然没有找到,则会报错;
var a = 10;
function fun(){
var b = 8;
var a = "我是函数中的变量a~";
console.log("a = "+a);// a = 我是函数中的变量a~
}
fun(); //a =10
console.log("a = "+a);// a = 10
(5)在函数中要访问全局变量可以使用window对象
var a = 10;
function fun(){
var a = "我是函数中的变量a~";
console.log("a = "+a);//我是函数中的变量a~
function fun2(){
console.log("a = "+window.a);// a=10;访问全 局变量
}
fun2();//我是函数中的变量a~
}
fun(); //a =10
(6)注意:在函数中,不使用var声明的变量都会成为全局变量;函数中定义了形参相当于声明了变量
var c =10;
function fun5(){
console.log("c = "+c); // c =10
c = 10;//这里的C相当于是全局变量
d = 100;//没有设置var关键字,这里的d相当于是全局变量
}
fun5();
console.log("c = "+c);//c =10,就近原则:输出就近的全局变量C
console.log("d = "+d);// d = 100
补充:
- 变量的声明提前:
- 使用var关键字声明的变量,会在所有代码执行之前被声明,(但是不会被赋值);
console.log("a = "+a); // a = undefined
var a = 123;
//相当于下面这种:
var a;
console.log("a = "+a); //a = undefined
a = 123;
- 如果声明变量时不使用var关键字,则声明变量不会被提前声明;
console.log("a = "+a); //直接报错
a = 123;
2.函数的声明提前
- 使用函数声明形式创建的函数function函数(){},它会在所有的代码执行之前就被创建,所以我们可以在函数声明提前来调用函数
fun();
function fun(){//函数声明会被提前创建
console.log("我是fun函数");
}
//相当于下面这种
function fun(){
console.log("我是fun函数");
}
fun();
- 使用函数表达式创建的函数不会被声明提前,所以不能再声明前调用;
var fun2 = function (){
console.log("我是fun2函数");
};
fun2();//我是fun2函数
//而下面这种声明是不可取的
fun2(); //报错
var fun2 = function (){//函数表达式,不会被提前创建
console.log("我是fun2函数");
};
- 在函数作用域也有声明提前的特性,使用var关键字声明的变量,会在函数中所有的代码执行之前被声明;函数声明也会在函数中所有的代码执行之前被执行;
function fun3(){
console.log(a);//undefined
var a=35;
}
function fun3(){
var a;
console.log(a);//undefined
a=35;
}
this
解析器在调用函数每次都会向函数内部传递一个隐含的参数
-
这个隐含的参数就是this,this指向的是一个对象,
-
这个对象我们称为函数执行的上下文对象,
-
根据函数的调用方式的不太,this会指向不同的对象(this指向当前引用的对象)
1.以函数的形式调用时,this永远都是window
2.以方法的形式调用的,this就是调用方法的那个对象function fun() { console.log(this.name); } var obj1 = { name : "张三", sayName: fun }; var obj2 = { name : "李四", sayName: fun }; //obj.sayName();// this 指向 obj obj1.sayName(); // 张三;this 指向obj1 obj2.sayName(); // 李四;this 指向obj2
this 的情况:
1.当以函数的形式调用时,this就是window
2.当以方法的形式调用时,谁调用方法this就是谁
3.当以构造函数的形式调用时,this就是新创建的那个对象
使用工厂方法创建对象
- 使用工厂方法创建的对象,使用的构造函数都是Object,所以创建的对象都是Object这个类型,就导致我们无法区分出多种不同类型的对象
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; //返回对象
}
var obj2 = createPerson("小陈", 20, "女");
var obj3 = createPerson("小赵",20,"女");
console.log(obj2);//{name: "小陈", age: 20, gender: "女", sayName: ƒ}
console.log(obj3);//{name: "小赵", age: 20, gender: "女", sayName: ƒ}
构造函数
- 创建一个构造函数,专门用来创建Person对象的
构造函数就是一个普通的函数,创建方式和普通函数没有区别
不同的是构造函数习惯上首字母大写 - 构造函数和普通函数的区别就是调用方式的不同
普通函数直接调用,构造函数需要new关键字来调用
var per = Person();//普通函数
var per = new Person();//构造函数
- 构造函数的执行流程:
1.立即创建一个新的对象
2.将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
3.逐行执行函数中的代码
4.将新建的对象作为返回值返回
function Person(){
this.name = "张三";//this指新建的对象
this.age = 20;
this.gender = "男";
}
var per = new Person();//构造函数
console.log(per);
//上面这种方式会把属性值写死,可以利用传参会更灵活些
function Person(name, age, gender){
this.name = name;//this指新建的对象
this.age = age;
this.gender = gender;
}
var per = new Person("张三", 22, "男");//构造函数的实例
console.log(per);
- 使用同一个构造函数创建的对象,我们称为一类对象,也将构造函数称为一个类。
我们将通过一个构造函数创建的对象,称为是该类的实例
构造函数就是类,构造函数创建的对象就是实例
使用instanceof可以检查一个对象是否是一个类的实例
如果是则返回true,否则返回false语法:对象 instanceof 构造函数
var per = new Person("张三", 22, "男");//构造函数
console.log(per instanceof Person);// true
所有的对象都是Object的后代,任何对象和Object做
instanceof检查是都会返回true
原型对象
-
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype
- 如果函数作为普通函数调用prototype没有任何作用
当函数以构造函数的形式调用时,它所创建的对象都会有一个隐含的属性,指向该构造函数的原型对象 - 我们可以通过__proto__来访问该属性
原型对象就相当于公共区域,所有同一个类的实例都可以访问到这个原型对象 - 我们可以将对象*有的内容,统一设置到原型对象中
作个比喻:对象相当于教学楼,实例是里面的教室,而原型则相当于厕所,属于公共区域!
- 如果函数作为普通函数调用prototype没有任何作用
-
当我们访问对象的一个属性或者方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
-
以后我们创建构造函数时,可以将这些对象共有的属性和方法,同统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了;
function MyClass(){
}
//向MyClass的原型中添加属性a
MyClass.prototype.a = 123;
MyClass.prototype.sayHello = function (){
console.log("Hello");
};
var mc = new MyClass();
mc.sayHello()
console.log(mc.a);
- 使用in 检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
console.log("a" in mc); //true
- 可以使用对象的
hasOwnProperty()
来检查对象自身中是否含有该属性;使用该方法只有当对象自身含有属性时,才会返回true;
console.log(mc.hasOwnProperty("a"));//fasle
原型补充:
原型对象也是对象,所以它也有原型
( 套娃开始~~ 找爷爷的爷爷)
- 当我们使用一个对象的属性或方法时,会在自身中寻找, 自身中有直接使用,如果没有,则去原型对象中寻找,
- 如果原型对象中有,则使用,如果没有则去原型的原型中寻找;直到找到Object对象的原型
- Object对象的原型没有原型,如果在Object中依然没有找到,则返回undefined;
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));// true
console.log(mc.__proto__.__proto__);//Object(祖宗)
console.log(mc.__proto__.__proto__.__proto__);// null(祖宗已经到头,再往后就是空)
垃圾回收
- 当一个对象没有任何的属性或者便利对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,
这种对象过多会占用大量的内存空间,导致程序运行变慢,所以必须进行清理; - JS中拥有自动垃圾回收机制,会自动将垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收操作;
我们需要做的只是要将不再使用的对象设置为null即可
var obj = new Object();//obj是变量,它的值指向对象的地址
obj = null;//obj设置为ull时,此时断开了与对象的连接,该对象应被当作垃圾进行回收
数组
- 数组也是一个对象
它和普通对象的功能类似,也是用来存储一些值的
不同的是普通对象是使用字符串作为属性名的,而数组是使用数字来作为索引操作元素的 - 索引(index):从0开始的整数
- 数组的存储性能比普通对象好,在开发中我们经常使用数组来存储一些数据
- 向数组中添加属性
语法 : 数组[索引] = 值
var arr = new Array();
arr[0] = 0;
arr[1] = 3;
console.log(arr);
- 读取数组中的元素,如果读取不存在的索引不会报错而是返回undefined
语法:数组[元素]
console.log(arr[0]);// 0
console.log(arr[2]);//undefined
- 获取数组的长度:
1. 对于连续的数组可以用length属性获取语法:数组.length
arr.length
2.对于非连续的数组,使用length会获取到数组的最大的索引+1
- 修改length
如果修改的length大于原长度,则多出的部分会空出来 如果修改的length小大于原长度,则多出的元素会被删除
- 向数组的最后一个位置添加元素
语法:数组[数组.length] = 值
arr[arr.length] = 6
补充:
- 使用字面量来创建数组
- 使用字面量创建数组时,可以在创建时就指定数组中的元素
语法:[]
var arr = [];
var arr = [1, 2, 3, 4];
- 使用构造函数添加数组时,也可以同时添加元素,将要添加的元素作为构造函数的参数传递
元素之间使用,
隔开
var arr2 = new Array(10,20,30);
- 创建一个数组,数组中只有一个元素10
arr = [10];
console.log(arr[0]);// 10
- 创建一个长度为10的数组(用的少)
arr2 = new Array(10);
- 数组中的元素可以是任意的数据类型,也可以是对象
arr = ["hello", 1, true, null, undefined];
console.log(arr);
var obj = {name: "张三"};
arr[arr.length] = obj;
console.log(arr[5]);
- 可以是一个函数
arr = [function(){alert(1)}, function () { }];
arr[0]();//调用第一个函数
- 二维数组
arr = [[1,2,3], [4,5,6],[7,8,9]];
数组的方法
-
push()
该方法可以向数组的末尾添加一个或多个元素,并返回数组的新的长度
可以将添加的元素作为方法的参数传递,这样这些元素将会自动添加到数组的长度var arr = ["张三", "李四", "王五"]; arr.push("小赵", "小陈", "小明"); console.log(arr);// (6) ["张三", "李四", "王五", "小赵", "小陈", "小明"]
该方法会将数组新的长度作为返回值返回;
2.pop()
该方法可以删除数组的最后一个元素,并将删除元素作为返回值返回;arr.pop(); console.log(arr);// ["张三", "李四", "王五", "小赵", "小陈"]
3.unshift()
向数组的开头添加一个或多个元素,并返回新的数组长度
向前面加入元素以后,其他的元素会依次调整javascript arr.unshift("小高", "小花"); console.log(arr); // ["小高","小花" "张三", "李四", "王五", "小赵", "小陈"]
4.shift()
可以删除数组的第一个元素,并将删除元素作为返回值返回
5.slice()
可以用来从数组提取指定元素
该方法不会改变元素,而是将取到的元素封装到一个新数组返回
参数:
1.截取开始的位置的索引,包含开始索引
2.截取结束的位置的索引,不包含结束索引
(第二个参数可以省略不写,此时会截取从开始索引往后所有的元素)
索引可以传递一个负值,如果传递一个负值,则从后往前计算;如 -1:倒数第一个
var arr = ["张三", "李四", "王五","小张","小赵", "小陈"];
var res= arr.slice(2, 4);
res = arr.slice(2, -1);//["王五", "小张","小赵"]
console.log(res);//["王五", "小张"]
//包括第二个,不包括第四个
6.splice()
可以用于删除数组中的指定元素
参数:
第一个:表示开始位置的索引
第二个:表示删除的数量
第三个及以后:可以传递新的元素,这些元素将会自动插入开始位置索引前边
res = arr.splice(0,2);//返回被删除的元素: 张三,李四
res = arr.splice(0,2, "小明");//["小明", "王五", "小张", "小赵", "小陈"]
练习:去除数组里重复的元素
var arr = [1,2,3,2,2,1,3,4,2,5];
//去除数组中重复的数字
//获取数组中的每一个元素
for(var i =0; i < arr.length; i++)
{
//获取当前元素后的所有元素
for(var j = i+1; j < arr.length; j++)
{
//判断两个元素的值是否相等
if(arr[i] == arr[j])
{
//如果相等则证明出现了重复,则删除j对应的元素
arr.splice(j, 1);
//当删除了当前j所在的元素以后,后边的元素会自动补位
//此时将不会再比较这个元素,则需要再比较一次j所在位置的元素
//使j自减
j--;
}
}
}
console.log(arr);// [1, 2, 3, 4, 5]
数组的遍历
将数组中所有的元素都取出来
使用该方法会影响到原数组,会将指定元素从原数组中删除,并将被删除的元素作为返回值返回。
var arr = ["张三", "李四", "王五"];
for(var i=0; i<arr.length; i++)
{
console.log(arr[i]);
}
练习:取出数组里年龄大于等于18的person
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.toString = function(){
return "Person"[name = "+this.name+ ",age = "+this.age+"];
}
var per = new Person("张三", 18);
var per1 = new Person("李四", 19);
var per2 = new Person("王五", 20);
var per3 = new Person("赵六", 20);
var per4 = new Person("刘七", 15);
//将这些person放入到一个数组中
var perArr = [per, per1, per2,per3, per4];
console.log(perArr);
/*
创建一个函数,可以将perArr中的满18岁的Person取出来
然后封装到一个新的数组中并返回
arr
形参,要提取新的数组
*/
function getAdult(arr){
//创建一个新的数组
var newArr = [];
//遍历arr 获取Person
for(var i=0; i < arr.length; i++)
{
//判断Person对象的age是否大于18
if(arr[i].age >= 18)
{
//如果大于等于18,则将这个对象添加到newArr中
newArr.push[arr[i]];
}
}
return newArr;
}
var res = getAdult(perArr);
console.log(res);
forEach
一般我们都是使用for循环去遍历数组,JS中还为我们提供了一个方法,用来遍历数组;(该方法只支持IE8以上的浏览器)
foEach()方法需要一个函数作为参数
像这种函数,由我们创建但不由我们调用,我们称为回调函数
数组中有几个元素,函数就会执行几次,每次执行时,浏览器会将遍历到的元素以实参的形式传递进来,我们可以定义形参来读取这些内容
浏览器会在回调函数中传递三个参数:
第一个参数:就是当前正在遍历的元素
第二个参数:就是当前正在遍历的元素的索引
第三个参数:就是正在遍历的数组
var arr = ["张三", "李四", "王五"];
arr.forEach(function fun(a, b, c){//(value, index, obj)
console.log("a = "+a);
console.log("b = "+b);
console.log("c = "+c);
});
//
a = 张三
b = 0
c = 张三,李四,王五
a = 李四
b = 1
c = 张三,李四,王五
a = 王五
b = 2
c = 张三,李四,王五
数组的剩余方法
- concat()可以连接两个或或多个数据,并将新的数组返回
该方法不会对原数组产生影响
var res = arr.concat(arr2, arr3, "小于");
console.log(res);//["张三", "李四", "王五", "小张", "小赵", "小陈","小于"];
- 该方法可以将数组转换为一个字符串
该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符
如果不指定连接符,则默认使用,作为连接符
res = arr.join();//张三,李四,王五
res = arr.join("你好,");
console.log(res);//张三你好,李四你好,王五
- join()
该方法可以将数组转换为一个字符串
该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符
如果不指定连接符,则默认使用,作为连接符
res = arr.join();//张三,李四,王五
res = arr.join("你好,");
console.log(res);//张三你好,李四你好,王五
- reverse()
该方法用来反转数组(前边的去后边,后边的去前边)
该方法会直接修改原数组
console.log(arr.reverse());//["王五", "李四", "张三"];
- sort()
可以用来对数组中的元素进行排序
也会影响原数组,默认会按照unicode编码进行排序
即使对于纯数字的数组,使用sort()排序时,也会按照unicode编码进行排序
所以对数字排序时,可能会得到错误的答案;
对于数字排序:
我们可以自己来指定排序的规则
我们可以在sort()添加一个回调函数,来指定排序规则
回调函数中需要定义两个形参
浏览器将会分别使用数组中的元素作为实参去调用回调函数
使用哪个元素调用不确定,但是肯定的是在数组中a一定在b的前面
浏览器会根据回调函数的返回值来决定元素的顺序,
如果返回一个大于0的值,则元素会交换位置
如果返回一个小于0的值,则位置不变
如果返回一个等于0的值,则认为两个元素相等,也不交换位置
res = arr.sort();
console.log(res);//["a", "b", "c", "d", "e"]
arr.sort();
console.log(arr);// [11, 3, 5, 6, 8]
//
arr = [3,5,11,8,6,1,2];
arr.sort(function(a,b){
// console.log("a = "+ a);
// console.log("b = "+ b);
/* if(a >b ){
return 1;
}
else if(a <b){
return -1;
}else{
return 0;
} */
// 升序排列
return a-b;
//降序排列
// return b - a;
});
console.log(arr);
本文地址:https://blog.csdn.net/qq_43216593/article/details/107448720