
1995年,NetScape公司,布兰登艾奇发明了一种运行在浏览器网页里的脚本语言Livescript。
通过本地而不是服务器进行验证,为了快速的验证表单信息,这在当时来说是一个前所未有的壮举。
LiveScript打开了浏览器市场,各大互联网巨头,都嗅到了蛋糕的味道,都想着分一杯羹,首当其中就是微软IE浏览器。
IE当年为了跟NetScape争夺市场份额。不甘落后很快退出适用于IE浏览器的JScript脚本语言。
由于缺乏统一标准,各个浏览器厂商发明的脚本语言,在用法和规范上不一致,成为了网页开发人员的噩梦。
1997年,ECMA(欧洲计算机制造商协会)成立了TC39委员会,委员会的成员基本都来自各大浏览器厂商。
这里面最重要的成员,就是当时如日中天的SUN公司,大家坐下来讨论之后,经过了大概1个月的世界,就快速制定出了浏览器脚本语言第一个全球标准。官方名称为ECMA Script编号ECMA-262。
由于总所周知的原因,大家没有忍住,蹭了一把JAVA热度,最终将其命名为JavaScript
至此,JavaScript诞生
如果非要说Java和Javascript有什么关系的话,就是Javascript在语法及很多API设计,内存结构设计上,直接借鉴和抄袭了Java
从这件事情可以看出,Java能这么经久不衰,是因为它非常优秀的设计(Java世界第一~~~
| 属性 | 值 | 描述 |
|---|---|---|
| async | async | 规定异步执行脚本(仅适用于外部脚本)。 |
| defer | defer | 规定当页面已完成解析后,执行脚本(仅适用于外部脚本)。 |
| type | MIME_type | 规定脚本的 MIME 类型。 |
| charset | character_set | 规定在脚本中使用的字符编码(仅适用于外部脚本)。 |
| src | URL | 规定外部脚本的 URL。 |
注意:为了提高整个程序运行的效率,我们可以将声明变量时,没有值赋值给这个变量的时候,默认值设成null,提高程序运行效率
+ - * / %(取余)> < >= <= == != === !==&& || !++ --特殊值:
| 关系式 | 值 |
|---|---|
| null==undefined | true |
| 'NaN'==NaN | false |
| 5==NaN | false |
| NaN==NaN | false |
| false==0 | true |
| true==1 | true |
| true==2 | false |
| undefined==0 | false |
| null==0 | false |
| '100'==100 | true |
| '100'===100 | false |
与运算短路操作:当表达式1为false的时候,表达式2就不执行,直接得出结果为false。
或运算短路操作:
Boolean() 其他数据类型强制转成布尔值
Number() 其他数据类型转数字
parseInt()取整
1.取整
parseInt("25a")//25
parseInt("2a5a")//2
parseInt("a25a")//NaN
parseInt("3.14)//3
2.将别的进制转成十进制 必须传入字符串
var str1="110100"
alert(parseInt(str1,2))//52
parseFloat() 取浮点数
举例
parseFloat("3.14b")//3.14
parseFloat("3.1b4b")//3.1
parseFloat("a3.1b4b")//NaN
var year = 2000;
var month = 1;
var date = 15;
var sum = 0;
switch(month){
case 12:
sum += 30;
case 11:
sum += 31;
case 10:
sum += 30;
case 9:
sum += 31;
case 8:
sum += 31;
case 7:
sum += 30;
case 6:
sum += 31;
case 5:
sum += 30;
case 4:
sum += 31;
case 3:
sum += 28;
if(uear % 4==0 && year %100 !=0 ||year % 400==0){
sum += 1;
}
case 2:
sum += 31;
case 1:
sum += date;
break;
default:
alert("error")
break;
}
alert("这是第"+sum+"天");
var week = Math.ceil(sum/7);
alert("这是第"+week+"周");
//无参无返回值
function 函数名(){
函数体;
}
//调用
函数名();
//有参无返回值
function 函数名(形参1,形参2...){
函数体;
}
//调用
函数名(实参1,实参2...)
//有参数有返回值
function 函数名(形参1,形参2...){
函数体;
return 表达式;
//函数调用的结果为表达式的值
//函数遇到return会中止
}
注意:见名思意,函数名必须体现其功能。
//编写一个函数 计算两数加减乘除 使用传参
function operation(num1,operator,num2){
switch(operator){
case "+":
return num1 + num2;
break;
case "-":
return num1 - num2;
break;
case "*":
return num1 * num2;
break;
case "/":
return num1 / num2;
break;
default:
alert("error");
break;
}
}
//输入n为偶数 1/2+1/4+...+1/n,奇数,1/1+1/3+...+1/n
function sum(n){
var res=0;
if(n % 2==0){
for(var i = 2 ; i <= n; i += 2){
res += 1/i;
}else{
for(var i = 1;i <= n; i += 2){
res += 1/i;
}
}
return res;
}
任何程序在执行的时候都要占用内存空间。函数调用的时候也要占用内存空间。
垃圾回收机制:调用函数时,系统会分配对应的空间给这个函数使用(空间大小一般情况由这个函数里声明的变量和形参决定)。当函数使用完毕之后,这个内存空间要释放,还给系统。
注意:在函数内部声明的变量和形参是属于当前函数的内存空间里的。
内存管理机制:在函数中声明的变量和形参,会随着函数的调用被创建,随着函数的调用结束而被销毁。在函数中声明的变量和形参,有效范围是当前函数(当前函数的大括号),这个范围被称为局部作用域。
就近原则:离哪个作用域近,就使用哪个作用域内的同名变量。
//举例
var a = 10,b=20;
function show(a){
var b = 100;
a += 5;
alert(a + "," + b);
}
show(a);//15,100
alert(a + ","+ b)//10,20
满足以下三个特点就是递归:
作用:递归可以解决循环能做的所有事情,有一些循环不容易解决的事情,递归也能轻松解决。
递归编写方法:
//计算1~n的和
function sum(n){
var res=0;
for(var i = 1; i<=n; i++){
res += i;
}
return res;
}
alert(sun(100));//5050
//递归写法
//sum(100)=sum(99)+100;
//sum(n)=sun(n-1)+n
function sum2(n){
if(n==1){
return 1;
}
return sum(n-1)+n;
}
alert(sum(100));//5050
注意:一般公司明文禁止使用递归。(一旦出现故障瞬间开出一堆内存空间)
练习1:
斐波那契数列,兔子繁衍问题,设有一对新生兔子,从第四个月开始他们每个月月初都生一对兔子,新生的兔子从第四个月月初开始又每个月生一对兔子,按此规律,并假定兔子没有死亡,n(n<=20)个月月末共有多少对兔子?
| 一月兔 | 二月兔 | 三月兔 | 四月兔 | 总数 | |
|---|---|---|---|---|---|
| 一月 | 1 | 0 | 0 | 0 | 1 |
| 二月 | 0 | 1 | 0 | 0 | 1 |
| 三月 | 0 | 0 | 1 | 0 | 1 |
| 四月 | 1 | 0 | 0 | 1 | 2 |
| 五月 | 1 | 1 | 0 | 1 | 3 |
| 六月 | 1 | 1 | 1 | 1 | 4 |
| 七月 | 2 | 1 | 1 | 2 | 6 |
| 八月 | 3 | 2 | 1 | 3 | 9 |
| 九月 | 4 | 3 | 2 | 4 | 13 |
//1. 首先找临界值,即无需计算,获得的值。
//2. 找这一次和上一次的关系。
//3. 假设当前函数已经可以试用,调用自身计算上一次
//rabbit(4) = rabbit(3) + rabbit(1);
//rabbit(n) = rabbit(n-1) + rabbit(n - 3)
function rabbit(n){
if(n<4){
return 1;
}
return rabbit(n-1) + rabbit(n - 3)
}
练习2:
有一堆桃子不知数目,猴子第一天吃掉一半,觉得不过瘾,又多吃了一只,第二天照此办法,吃掉剩下桃子的一半另加一只,天天如此,到第num(num<=10)天早上,猴子发现只剩一只桃子了,问这堆桃子原来有多少只?(思路:n为还剩n天吃完的桃子数)
peach(10)/2 - 1 = peach(9);
peach(10) = (peach(9) + 1) * 2;
peach(n) = (peach(n-1) + 1) * 2;
function peach(n){
if(n == 1){
return 1;
}
return(peach(n-1) + 1) * 2;
}
练习3:
输入一个n,打印n个hello world的运行结果,
//print(n) =print(n - 1) + 一次输出
function print(n){
if(n == 0){
return;
}
document.write("hello world<br/>");
return print(n - 1);
}
当我们需要表示一组数据,或者叫做一次性定义很多相似的数字或变量时,就需要使用数组,如:表示一个班级学生的成绩,一年十二个月的销售数据等等
// 1.通过new创建数组
// 参数:传入任意的数据,存储到数组中
var arr = new Array(100,true,"hello");
// 2.省略new运算符创建数组
var arr = Array(100,true,"hello");
// 3.数组常量进行赋值。(JS一般使用中括号[])
var arr = [100,true,"hello"];
注意:使用1、2方法时,传入参数只有一个,并且为数字的时候,直接声明这么长的一个数组(数字为数组的长度)。
Math.random() //随机生成[0,1)中的数
paerseInt(Math.random()*10) //随机生成0~9的整数
//给数组每个元素赋值随机数
var arr = new Array(10);
for(var i = 0; i < arr.length; i++){
arr[i] = paerseInt(Math.random()*10);
}
差别:不用判断数组长度,运行过程中数组长度改变会出错(一般不写奇奇怪怪的代码不会发生错误)。
var arr = [10,20,30,40,50];
//页面上分别将每一个数输出
for(var i in arr){
document.write(arr[i]+"<br/>");
}
格式:数组.splice(start,length,数据1,数据2...)
增加
var arr = [10,20,30,40,50];
var res = arr.splice(2,0,"hello","world");
alert(arr);//10,20,hello,world,30,40,50
alert(res);//空数组
删除
var arr = [10,20,30,40,50];
var res = arr.splice(1,2);
alert(arr);//10,40,50
alert(res);//20,30
修改(先删后增)
var arr = [10,20,30,40,50];
arr.splice(2,1,"hello");
alert(arr);//10,20,hello,40,50
var arr = [10,20,30];
var str = arr.join("==");
alert(str);10==20==30
alert(arr);10,20,30
var arr = [true,"hello",100];
arr.reverse();
alert(arr);//100,hello,true
格式:数组.sort() 默认从小到大排序,按字符串排序
参数:一个函数,代表要怎么进行排序(固定用法)
按数值排序方法
var arr=[1,10,20,30,25,5];
//从小到大
arr.sort(function(value1,value2){
return value1 - value2;
})
//从大到小
arr.sort(function(value1,value2){
return value2 - value1;
})
定义一个含有38个整型元素的数组,按顺序分别赋予从2开始的偶数;然后按顺序每五个数求出一个平均值,放在另一个数组中并输出。
var arr=new Array(30);
for(var i=0;i<arr.length;i++){
arr[i]=i*i+2;
}
var avgArr=[];
for(var i=0;i<6;i++){
var newArr.splice(0,5);//splice对原数组进行修改
//var newArr = arr.slice(i*5,(i+1)*5);也行
var sum=0;
for(var j=0;j<newArr.length;j++){
sum+=newArr[j];
}
avgArr.push(sum/5);
}
alert(avgArr);
//声明提升
alert(num);
var num=10;
alert(num);
//undefined 10
/*
内存分配,一次分配
预编译:所有代码运行之前,计算机将代码从头到尾看一遍。
将这个程序需要运行的空间一次性分配好。
var num=10在第二行 声明var num在所有程序之前
相当于:*/
var num;
alert(num);
num=10;
alert(num);
//函数也会声明提升,预编译时会将函数提到代码最前面
//总结:在当前作用域,声明变量和函数,会直接提升在整个代码的最前面运行
/*
通过循环按顺序为一个5x5的二维数组a赋1到25的自然数,然后输出该数组的左下半三角
*/
var arr = {
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15],
[16,17,18,19,20],
[21,22,23,24,25]
};
//打印靠左三角形图案
for(var i=0;i<5;i++){
for(var j=0;j<=i;j++){
document.write("o")
}
document.write("<br/>")
}
//结合一下
for(var i=0;i<arr.length;i++){
for(var j=0;j<=i;j++){
document.write(arr[i][j]+" ")
}
document.write("<br/>")
}
冒泡排序:
var arr=[9,8,4,2,4,6];
for(var i=0;i<arr.length-1;i++){
//每一轮比较的次数
for(var j=0;j<arr.length-(i+1);j++){
if(arr[j]>arr[j+1]){
//交换位置
var tmp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
}
}
}
选择排序(打擂台):
var arr=[9,8,4,2,4,6];
for(var i=0;i<arr.length-1;i++){
for(var j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
var tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
}
}
//随机给出一个五位以内的数,然后输出该数共有多少位,每位分别是什么
function count0fNum(num){
var arr=[];
while(num){
arr.unshift(num % 10);
num = parseInt(num/10);
}
alert("一共是:"+arr.length+"位,每一位分别是"+arr)
}
//编写函数has(arr,60)判断数组中是否存在60这个元素,返回布尔类型
function has(arr,item){
for(var i=0;i<arr.length;i++){
if(arr[i]===item){
return true;
}
}
return false;
}
/*
生成13位条形码
Ean-13码规则:第十三位数字是前十二位数字经过计算得到的校验码。
例如:690123456789
第十三位计算其验证码的过程为:
@前十二位的奇数位和6+0+2+4+6+8=26
@前十二位的偶数位和9+1+3+5+7+9=34
@将奇数和与偶数和的三倍相加26+34*3=128
@取结果的个位数:128的个位数为8
@用10减去这个个位数10-8=2
所以校验码为2(如果结果个位数为0,校验码为0)
例如:输入692223361219输出6922233612192
*/
functino ean13(num){
//1、将其中每一位数取下来
var arr=[];
while(num){
arr.unshift(num%10);
parseInt(num/10);
}
var odd=0;
var even=0;
for(var i=0;i<arr.length;i++){
if(i%2==0){
//奇数
odd += arr[i];
}else{
//偶数
even += arr[i];
}
}
var sum=(odd+even*3)%10;
if(sum){
sum=10-sum;
}
//生成第13位数
arr.push(sum);
return Number(arr.join(""));
}
简介:除正常运行模式,ECMAscript 5 添加了第二种运行模式:“严格模式”(strict mode)。顾名思义,这种模式使得Javascript在更严格的条件下运行。
目的:
格式:
/*
严格模式:写在哪个作用内下,就在哪个作用域内生效。
"use strict";
注:尽量注意不要把严格模式写在全局。
*/
全局变量声明时,必须加var
<script>
"use strict";
a=10;//报错,因为a没有被var声明
</script>
this无法指向全局对象。
<script>
"use strict";
function a(){
this.b=10;//报错,因为this是undefined
}
a()
</script>
函数内重名属性
<script>
"use strict";
function a(b,b,c){
//语法错误:上下文中不允许重复的参数名称
}
</script>
arguments对象不允许被动态改变 :
function show(num1,num2){
"use strict";
num1="hello";
alert(num1+","+num2);//hello,20
alert(arguments[0]+","+arguments[1])//10,20
}
show(10,20);
新增保留字:implements,interface,let,package,private,protected,public,static,yield。
注:保留字不能声明为变量名
<script>
"use strict";
function package(protected){//语法错误
var implements;//语法错误
}
</script>
格式:数组.index(item,start)
参数:
功能:在数组中查找第一次出现item元素的下标,从start开始查找
返回值:
举例:
var arr[1,2,3,4,5,6,7,2,5,6];
var index = arr.indexOf(20,2);
alert(index);
var arr=[10,20,30,40,50];
arr.forEach(function(item,index,arr){
/*
item当前遍历到的元素
index当前遍历到元素的下标
arr数组本身
*/
});
var arr=[10,20,30,40,50];
var newArr=arr.map(function(item,index,arr){
//遍历要做的事情
return item*1.3;
});
alert(newArr)//;12,26,39,52,65
alert(arr);//10,20,30,40,50
var arr=[5,1,2,3,4,5]
var newArr=arr.filter(function(item,index,arr){
return item>2;//找出所有大于2的元素
});//结果:[5,3,4,5],不改变原数组新生成数组
var arr=[10,20,30,40,50];
var newArr=arr.some(function(item,index,arr){
//遍历要做的事情
return item>20;
});
var arr=[10,20,30,40,50];
var newArr=arr.every(function(item,index,arr){
return item>20;
});
var arr=[10,20,30,40,50];
var newArr=arr.reduce(function(prev,next,index,arr){
/*
prev 第一次 下标为0的元素
第二次开始 上一次遍历return的值
next 从下标1开始,当前遍历到的元素
arr数组本身
*/
alert(prev+","+next);
return prev + next;
});
alert(newArr)
/*
10,20
30,30
60,40
100,50
150
*/
var str =new String(100);
alert(typeof str);//object
var str1 = String(100);
alert(typeof str1);//string
var str2 = "100";
alert(typeof str2);//string
big() 大好字体显示字符串
blink() 显示闪动字符串(ie无效)
bold() 粗体显示字符串
fixed() 以打字机文本显示字符串
strike() 使用删除线来显示字符串
fontcolor() 指定颜色显示字符串
fontsize() 指定尺寸显示字符串
link() 字符串显示为链接
sub() 字符串显示为下标
sup() 字符串显示为上标
//document.write()中使用,用特殊样式输出字符串
charAt(3) //获取下标为3的字符
charCodeAt(3) //获取下标为3的字符的编码
//上面2个方法使用字符串对象调用
fromCharCode(94) //编码转换成字符串
//该方法是String静态方法,所以用String调用,
如:var str = String.fromCharCode(98,99);
/*
indexOf()
格式:supStr.indexOf(subStr,start);
参数:第一个,要查的字符串
start 从哪个下标开始 默认为0
功能:在supStr中查找subStr第一次出现的位置,从start这个位置开始查找。
返回值:-1 没有找到
*/
var supStr="abcabcabc";
var subStr="abc";
var index = supStr.indexOf(subStr);//0
var index = supStr.indexOf(subStr,1);//3
var index = supStr.indexOf(subStr,4);//6
//======================================================
/*
lastIndexOf()
格式:supStr.lastIndexOf(subStr);
功能:在supStr中查找subStr最后一次出现的位置
参数:第二个参数是开始查找的索引位置,查找方向是从右往左
返回值:-1 没有找到
*/
var supStr="abcabcabc";
var subStr="abc";
var index = supStr.lastIndexOf(subStr);//6
var index = supStr.lastIndexOf(subStr)
var arr=[10,5,2,3,4,5,7,8,9];
//索引值:0 1 2 3 4 5 6 7 8
console.log(arr.lastIndexOf(4));//4
console.log(arr.lastIndexOf(7));//6
console.log(arr.lastIndexOf(5));//5
/*
//======================================================
search()
格式:supStr.search(subStr);
参数:字符串/正则表达式
功能:在supStr中查找subStr第一次出现的位置
返回值:-1 没有查找到
*/
var supStr="Abcabcabc";
var subStr="/abc/i";
var index = supStr.search(subStr);//0
/*
substring
格式:字符串.substring(start,end);
功能:将字符串中[start,end)提取这部分字符,生成新字符串
返回值:新字符串
*/
var str = "hello";
var newStr=str.substring(1,4);
alert(newStr);//ell
alert(str);//hello
//======================================================
/*
substr
格式:字符串.substr(start,length);
返回值:新字符串
*/
var str="hello";
var newStr = str.substr(1,3);
alert(newStr);//ell
alert(str)//hello
//======================================================
/*
slice(数组方法)
格式:字符串.slice(start,end);
*/
var newStr=str.slice(1,4);
alert(newStr);//ell
alert(str);//hello
/*
replace() 字符串替换
格式:supStr.replace(oldStr,newStr);
功能:用newStr将oldStr,替换,生成新字符串。
参数:
第一个参数传入的是字符串只能替换一次。
第一个参数可以传入正则表达式
返回值:新生成的字符串。
*/
var str="how are are you";
var newStr = str.replace("are","old are")
var newStr2 = str.replace("/are/g","old are")
alert(newStr);//how old are are you
alert(str);//how are are you
alert(newStr2);//how old are old are you
//======================================================
/*
split() 字符串分割
格式:字符串.split(分隔符,length)
参数:
第一个参数,用这个分隔符对字符串进行分割
第二个参数,控制返回的数组的元素格式,一般不用
功能:用分隔符对原字符串分割分割玩的字串放在数组中返回
返回值:数组
*/
var str="how are are you";
var newStr = str.split(" s")
alert(newStr);//how,are,you
alert(str);//how are you
/*
注意:1.相邻两个分隔符,会产生空字符串。
2.分割符是空字符串"",直接将每一个字符单独分割成字串,放在数组中返回。
*/
/*
toLowerCase() 转成全小写
toUpperCase() 转成全大写
注:生成新字符串
*/
//1、将字符串str="When I was young,I love a girl in neighbor class."中,从young提取到girl生成新字符串
var str="When I was young,I love a girl in neighbor class."
var start = str.indexOf("young");
var end=str.indexOf("girl")+"girl".length;
var newStr = str.substring(start,end);
alert(newStr);
/*
2、将字符中单词用空格隔开,已知传入的字符串只有字母,每个单词首字母大写,把每个单词用空格隔开,值保留第一个单词首字母大写
传入:"HelloMyWorld"
返回:"Hello my world"
思路
1、字符串转数组 split("")
2、数组转字符串 join("")
*/
function wordOfStr(str){
var arr=str.split("");
for(var i = 1;i<arr.length;i++){
if(arr[i]>="A"&&arr[i]<="Z"){
//大写转小写,插空格
arr[i]=arr[i].toLowerCase();
arr.splice(i,0," ");
}
}
return arr.join("");
}
wordOfStr("HelloMyWorld");
/*
3.将字符串安单词进行排序,空格作为划分单词的唯一条件
传入"Welcome to Beijing"
改为"Beijing to Welcome"
*/
function reverseStr(str){
var arr=arr.split(" ");
}
//纯数字验证码
function numTestCode(n){
var arr=[];
for(var i=0;i<n;i++){
var num=parseInt(Math.random()*10);
arr.push(num);
}
return arr.join("");
}
//字母数字验证码
/*
0-9
a-z 97-122
A-Z 65-90
随机ASCII码值
*/
function testCode(n){
var arr=[];
for(var i=0;i<n;i++){
var num=parseInt(Math.random()*123);
if(num>=0&&num<=9){
arr.push(num);
}else if(num>=97&&num<=122||num>=65&&<=90){
arr.push(String.fromCharCode(num));
}else{
i--;
}
}
return arr.join("");
}
发展历史
汇编语言:
思想:
面向过程→面向对象
面向过程:只考虑数学逻辑
面向对象:分析实体、设计实体属性功能、实体间相互作用,对生活逻辑的映射。
//一辆车60km/h,一条路100km,问跑完时间
/*
面向过程:var hours=100/60;
面向对象:
车
速度 60km/h
功能 跑路上
路
属性
length 100km
让车真的跑在路上得出结果
*/
//贪吃蛇
/*
面向过程:坐标 蛇速度
面向对象:
蛇
食物
砖块
*/
语法
类:一类具有相同特征事物的抽象概念。(狗
对象:具体某一个个体,唯一的实例。(小白
举例
/*
1、通过new运算符声明对象
2、通过省略new
3、对象常量赋值(使用大括号表示对象)
*/
var obj1=new Object();
var obj2=Object();
var obj3={};
//新增属性 除加前缀使用起来和普通变量无区别
obj3.username='钢铁侠'
obj3.age=18;
alert(obj3.username);
alert(obj3.age);
//通过中括号设置访问
obj3['username']='钢铁侠'
obj3['age']=18;
alert(obj3['username'])
alert(obj3['age'])
//新增方法 除加前缀使用其阿里和普通函数没有区别
obj3.show=function(){
alert("我的名字叫"+obj3.name+"。"+obj3.age+"岁")
}
obj3.show();
//通过对象常量赋值
var obj3={
username:"钢铁侠",
"age":18,
show:function(){
alert("我的名字叫"+obj3.name+"。"+obj3.age+"岁")
}
}
//delete 关键字 删除对象属性或方法
delete obj3.show;
数据结构回顾
//上面车的例子
var car={
speed:60,
run:function(road){
return road.length/car.length;
}
};
var gaosugonglu={
length:100
};
var hours=car.run(gaosugonglu);
alert("一共花了"+hours.toFixed(2)+"小时");
声明
没有传参:当前系统时间
var d=new Date();
alert(d);//Wed Oct 09 2019 09:01:01 GMT+0800 (中国标准时间)
// GMT 格林尼治时间
传参:
/*
参数:
1.字符串 "2000-01-01"
Sat Jan 01 2000 08:00:00 GMT+0800 (中国标准时间)
2.数字(按顺序 年月日时分秒毫秒)
注:月份从0开始
var d=new Date(2000,1,1,8,30,50);
Tue Feb 01 2000 08:30:50 GMT+0800 (中国标准时间)
3.数字(毫秒数)
起点:1970/1/1 0:0:0
var d=new Date(1000);
Thu Jan 01 1970 08:00:01 GMT+0800 (中国标准时间)
*/
| 方法 | 功能 |
|---|---|
| box.toDateString() | 特定格式显示星期几、月、日和年 |
| box.totimeString() | 特定格式显示时、分、秒和时区 |
| box.toLocaleDateString() | 特定地区格式显示星期几、月、日和年 |
| box.toLocaleTimeString() | 特定地区格式显示时、分、秒和时区 |
| box.toUTCString() | 特定格式显示完整UTC日期 |
var d = new Date();
var year = d.getFullYear();
var month = d.getMonth()+1;
var date = d.getDate();
var week = d.getDay()//0~6 0是星期天
var min = d.getMinutes();
var sec = d.getSeconds();
/*
Date.parse()
格式:Date.parse(日期对象)
功能:可以将日期对象转换成毫秒数
d.getTime()/d.setTime()
格式:日期对象.getTime/setTime
功能:将当前日期对象转换成毫秒数
*/
var d=new Date();
alert(Date.parse(d));
alert(d.getTime());//调用格式不一样
/*
传入:"xxxx-xx-xx" "xxxx/xx/xx"
*/
function countOfDate(d1,d2){
var dd1=new Date(d1);
var dd2=new Date(d2);
var time1=dd1.getTime();
var time2=dd2.getTime();
var time=Math.abs(time1-time2);
return parseInt(time/1000/3600/24)
}
function afterOfDate(n){
var d = new Date();
var day = d.getDate();
d.setDate(day + n);//超过30 31自动进1
return n
}
格式:var timer = setInterval(函数,毫秒数);
功能:隔对应毫秒数,执行一次传入函数
返回值:系统分配的编号
取消定时器:clearInterval(timer);
例子:
var i = 0;
function show(){
if(i==5){
clearInterval(timer);
}
document.write(i++ + "<br/>")
}
var timer = setInterval(show,1000);
//1 2 3 4 5
//======================================
var i = 0;
var show = function(){
if(i==5){
clearInterval(timer);
}
document.write(i++ + "<br/>")
}
//匿名函数
//======================================
var timer = setInterval(function(){
if(i==5){
clearInterval(timer);
}
document.write(i++ + "<br/>")
},1000);
浏览器可以通过alert()、confirm()和prompt()方法调用系统对话框向用户显示信息.
//弹出警告框
alert("Lee")
//提示框(确定和取消)
confirm("请确定或者取消");
if(confirm(("请确定或者取消")){
alert("按了确定")//返回true
}else{
alert("按了取消")//返回false
}
//输入提示框
var num = prompt("请输入一个数字",0);
//参数1:提示 ; 参数2:默认值
alert(num);//得到输入的值
/*
功能:打开窗口
open()
- 参数1:跳转url 打开一个新窗口加载url
- 参数2:字符串,给打开的窗口命名
- 本窗口打开 _parent
- 新建窗口打开 _blank
- 参数3:特殊含义字符串
- 可以设置宽高
*/
open("https://www.baidu.com","_blank","width=400,height=400,top200,left=200")
| 第三个参数属性 | 值 |
|---|---|
| channelmode=yes|no|1|0 | 是否使用剧院模式显示窗口。默认为no。 |
| directories=yes|no|1|0 | 是否添加目录按钮。默认yes |
| funllscreen=yes|no|1|0 | 是否使用全屏模式显示浏览器。默认no。处于全屏模式的窗口必须同时处于剧院模式。 |
| height=pixels | 窗口显示区高度 |
| left=pixels | 窗口x坐标 |
| location=yes|no|1|0 | 是否显示地址字段。默认yes |
| menubar=yes|no|1|0 | 是否显示菜单栏。默认yes |
| resizable=yes|no|1|0 | 窗口是否可调节尺寸。默认yes |
| scrollbars=yes|no|1|0 | 是否显示滚动条。默认yes |
| status=yes|no|1|0 | 是否添加状态栏。默认yes |
| titlebar=yes|no|1|0 | 是否显示标题栏。默认yes |
| toolbar=yes|no|1|0 | 是否显示浏览器的工具栏。默认yes |
| top=pixels | 窗口y坐标 |
| width=pixels | 窗口宽度 |
属性
history.length;//记录数
方法
history.back()//后退
history.forward()//前进
history.go(num)//跳转到第num个记录
- 0刷新
- 2 正整数 前进2个
- -2 负整数 后退2个
window下location
属性
url:统一资源定位符。
- 协议://IP(域名)/:端口号/路径/?查询字符串#锚点
location.protocal//获取访问协议
- http:
- https:(证书认证协议)
location.hostname//获取主机名
- 一般主机名为IP(网络地址) 不好记
- 域名:ip的别称
location.port//获取端口号,默认隐藏
- 当前电脑使用网络的软件,随机分配的一个编号 0-65535
- 定位到当前使用网络的进程
- 浏览器默认端口 8080
- http 80
- https 443
location.pathname//获取路径
location.search//获取查询字符串
- 查询字符串格式:?name1=value1&name2=value2
location.hash //获取锚点
document下location
alert(window.loaction===window.document.location);//true
属性:
方法
assign() //跳转到指定页面,与href等效
- 产生历史记录
reload() //刷新
- reload(true)//不经浏览器缓存,强制重载
repalce()//用新url替换当前页面
- 不产生记录
<div></div>/*
查找指定元素指定CSS属性值
@ elem 指定的元素
@ attr 指定的CSS属性
@ return 返回对指定元素查找到的css属性值
*/
function getStyle(elem,attr){
return elem.currentStyle ? elem.currentStyle[attr]:getComputedStyle(elem)[attr];
}
//elem.currentStyle[attr]兼容ie
//getComputedStyle(elem)[attr]其他
| nodeType | nodeName | nodeValue | |
|---|---|---|---|
| 元素节点 | 1 | 标签名 | null |
| 属性节点 | 2 | 属性名 | 属性值 |
| 文本节点 | 3 | #text | 文本内容 |
获取其中某一个节点
概念:只要封装函数,任何一个函数系统都会内置一个叫做this的变量,this变量存储的是地址,当前函数主人的地址。函数主人通过上下文判断。this类似于现实生活中,用到的“我”。
常用情况:
var person={
username:"钢铁侠",
sex:"男",
show: function(){//函数主人为person
alert(person.username);
alert(this.username);//2个结果一样
}
}
function show(){
alert(this);
}
show();//全局函数 函数主人默认为window
window.show();
window.onload=function(){
var oBtn=dcument.getElementById("btn1");
//给页面上btn1的一个对象添加了一个函数
//函数主人为当前按钮 this指向oBtn
oBtn.onclick=function(){
alert(this);
}
}
/*
1.创建10w个节点,添加到页面上
*/
console.time("test1");
for(var i=0;i<100000;i++){
var newDiv=document.createElement("div");
}
console.timeEnd("test1");
/*
2.创建10w个节点,将10w节点插入到一个节点上,最后将这一个节点添加到页面上
*/
console.time("test2");
var node=document.createElement("div");
for(var i=0;i<100000;i++){
var newDiv=document.createElement("div");
node.appendChild(newDiv);
}
document.body.appendChild(node);
console.timeEnd("test2");
/*
第一种方式耗时120毫秒 第二种耗时78毫秒
而第二种方式就是 文档碎片操作(效率高)
生活中的例子:
1.想吃干脆面,下楼买一趟,想喝可乐,再下楼一趟,想吃方便面,再下楼一趟。
2.一趟把东西买完。
*/
数组遍历:
for循环
for...in快速遍历 (效率高无判断
forEach
var arr[10,20,30,40]
for(var i=0;i<arr.length;i++){
document.write(i+","+arr[i]);
}
for(var i in arr){
document.write(i+","+arr[i]);
}
arr.forEach(function(item,index,arr){
document.write(indexi+","+item);
});
对象遍历:
for...in
var person={
username:"钢铁侠",
age:18,
sex:"男"
}
for(var i in person){
document.write("属性名:"+i+"属性值:"+person[i])
}
JavaScript事件是由访问Web页面的用户引起的一系列操作,例如:用户点击。当用户执行某些操作的时候,再去执行一系列代码。
JavaScript有两种事件模型:内联模型、外联/脚本模型。
内联模型:
这种模型是最传统接单的一种处理事件的方法。在内联模型中,事件处理函数是HTML标签的一个属性,用于处理指定事件。虽然内联在早期使用较多
<button onclick='btn();'> </button>
外联模型:
var btn=document.getElementById("btn1");
btn.onclick=function(){
alert("外连模式")
}
绑定格式:
实际开发中我们希望js代码和html css是分离的 所以推荐使用外联模型。
一、鼠标事件(可以绑定在任何元素节点上)
| 事件名 | 事件详情 |
|---|---|
| click | 单击 |
| dblclick | 双击 |
| mouseover | 鼠标移入 |
| mouseout | 鼠标移出 |
| mousemove | 鼠标移动(不停触发 |
| mouseenter | 鼠标移入 |
| mouseleave | 鼠标移出 |
mouserleave和mouseout的区别
mouseleave是当鼠标指针离开了目标元素以及目标元素的所有子元素以后才会触发。
而mouseout是只要鼠标指针离开了目标元素或者目标元素的所有子元素中的任何一个就会被触发,即使鼠标指针还在目标元素内。也就是离开子元素后,mouseout事件会冒泡到父元素上。直到取消了冒泡或者到达了最外层根元素,才会停止冒泡。
https://www.w3school.com.cn/tiy/t.asp?f=jquery_event_mouseleave_mouseout
mouseenter与mouseove同理
二、键盘事件(表单元素、全局window)
三、HTML事件
- load
- 页面加载完以后触发
- unload
- 当页面解构的时候触发(刷新,关闭)仅兼容ie
- scroll
- 页面滚动
- resize
- 窗口大小发生变化
2. 表单事件
- blur
- 失去焦点
- foucs
- 获取焦点
- select
- 当我们在输入框内选中文本的时候触发
- change
- 当我们对输入框的文本进行修改并且失去焦点的时候
- 必须添加到form元素的事件
- submit
- 当我们点击submit的按钮才能触发
- reset
- 当我们点击reset的按钮才能触发
引例:番茄炒蛋 番茄+鸡蛋+条例炒出来的味道是全新的味道,不是番茄也不是鸡蛋的味道了
事件绑定:
系统会在事件绑定完成的时候,生成一个事件对象,将事件对象当作第一个参数传入
触发事件的时候,系统会自动去调用事件绑定的函数
function show(){
alert(arguments.length);//1
alert(arguments[0]);//object MouseEvent
alert("hello world");
}
window.onload=function(){
var btn=document.getElementById("btn1");
btn.onclick=show;
}
可以设置一个形参,传入事件对象的时候可以通过形参拿到 ie8以下不兼容
function show(ev){
//浏览器兼容
var ev = ev || window.event
alert(arguments.length);//1
alert(arguments[0]);//object MouseEvent
alert(ev)//object MouseEvent
alert("hello world");
}
window.onload=function(){
var btn=document.getElementById("btn1");
btn.onclick=show;
}
最终写法:
window.onload=function(){
var btn=document.getElementById("btn1");
btn.onclick=function(ev){
//事件对象获取,固定写法
var ev=ev||window.event;
alert(e);
}
}
获取当前鼠标位置:区别(原点位置不同)
获取功能键:
获取键码
获取字符码
概念:是事件对象的属性,代表触发对象
兼容IE8:window.event.srcElement;
例子:
...
<script>
window.onload=function(){
var li=doucment.getElementById("li1")
li.onclick=function(ev){
var e=ev||window.event;
var target = e.target||window.event.srcElement;
alert(target.innerHTML);//1111
}
var ul=doucment.getElementById("ul1")
li.onclick=function(ev){
var e=ev||window.event;
var target = e.target||window.event.srcElement;
//点击内容2222的li
alert(this.tagName);//ul this指向函数主人ul
alert(target.innerHTML);//2222 由li而起的
//就好像隔了一层纸打了你一下,然后你叫了一声,但是我打的是纸,触发对象是纸,疼的是你。
}
}
</script>
...
<body>
<ul id='ul1'>
<li id='li1'>1111</li>
<li>2222</li>
</ul>
</body>
...
冒泡:一个页面中的多个dom如果呈现父子类关系,并且都绑定了事件,则会有事件冒泡的情况发生,从最里面的dom冒泡到外层,由里向外逐级触发。
捕获:冒泡反过来,由外向里逐级触发
阻止事件冒泡:
function stopbUBBLE(e){
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble=true;
}
}
1.阻止官方右键菜单
window.onload=function(){
//关闭官方右键菜单
document.oncontextmenu=function(){
return false;
}
}
2.阻止超链接跳转
link.onclick=function(evt){
evt.preventDefault();//W3C,阻止默认行为,放哪里都可以
alert('1');
}
link.onclick=function(ev){
window.event.returnValue=false;//IE,阻止默认行为
alert('1');
}
//兼容写法
function preDef(e) {
if (e.preventDefault) {
e.preventDefault();
}else{
window.event.returnValue=false;
}
}
案例:自定义右键菜单,跳转链接阻止加操作
拖拽:
window.onload=function(){
var ul=document.getElementByid("ul");
var li=docuemnt.getElementByTagName("li");
//添加点击事件
for(var i=0;i<li.length;i++){
li[i].onclick=function(){
this.style.backgroundColor='red';
}
}
/*
这种添加方法
- 1.浪费
- 2.如果新增节点是没有事件的
相当于5个人想喝水一个人带一个水龙头(函数) 谁要喝就拧上去,喝完把水龙头拧下来。而且新来的同学不知道规矩没有水龙头(惨)
解决这种情况的方式就叫事件委托
*/
}
/*
委托:
A委托B去买饭。
A发布任务 委托方
B执行任务 受理方
A要吃饭 B去买饭
*/
/*
事件委托步骤:
- 1.找到当前节点的父节点或者祖先节点
- 2.将事件添加到你找的父节点或者祖先节点上
- 3.找到触发对象,判断触发对象是否是想要的触发对象,进行后续操作。
*/
window.onload=function(){
/*
li要变红
li委托ul去做
li变红
li要吃饭
ul去买饭
li吃到饭
*/
var ul=document.getElementByid("ul");
ul.onclickk=function(){
var e=ev||window.event;
var target=e.target||window.event.srcElement;
if(target.nodeName.toLowerCase()=="li"){
target.style.backgroundColor='red';
}
}
//所有li的变红都由ul的一个点击函数实现 1.不浪费 2.新增li也可以添加到效果,相当于5个同学 用一个水龙头(函数)。
}
//传统事件绑定格式
var btn=docuement.getElementById("btn1");
btn.onclick=function(){
alert("点击1")
}
btn.onclick=function(){
alert("点击2")
}
/*
缺点:
- 1.重复添加覆盖
- 因为是赋值,覆盖,点击后输出点击2
*/
/*
事件监听器:
- 事件绑定的另一种方式
- addEventListener()
- 格式:node.addEventListener(“click”)
- 参数:
- 1.事件类型
- 2.绑定函数
- 3.布尔值 true:捕获 false:冒泡(默认
- removeEventListener()
*/
//事件监听器绑定格式
var btn=docuement.getElementById("btn1");
btn.addEventListener("click",function(){
alert("点击1");
},false);
btn.addEventListener("click",function(){
alert("点击2");
},false);
/*
优点:
1.不会覆盖
2.可精确删除某个函数
适用情况:
- 给一个控件添加多个函数
- 精确删除某一个函数
*/
//点击后输出点击1然后输出点击2
//应用情况:写了好多代码 想加功能 不用回去找
function addEvent(node,evenType,funcName){
if(node.addEventListener){
node.addEventListener(evenType,funcName,false);
}else{
node.attachEvent("on"+evenType,funcName);
}
}
function removeEvent(node,evenType,funcName){
if(node.removeEventListener){
node.removeEventListener(eventType,funcName);
}else{
node.detachEvent("on"+eventType,funcName);
}
}
案例:生成表格,放大镜
通过new去声明正则表达式
var box1=new RegExp("hello","ig");
alert(box1) // /hello/gi
省略new运算符声明正则表达式
var box1=RegExp("hello","ig");
alert(box1) // /hello/gi
通过常量赋值声明正则表达式
var box1=/hello/gi;
alert(box1) // /hello/gi
match()
replace()
格式:字符串.replace(旧字符串/正则,新字符串);
功能:新替换旧
返回值:替换成功的新字符串
var str="how are Are ARE you";
var newStr=str.replace(/are/ig,"*");
alert(newStr) // how * * * you
split()
格式:字符串.replace(分隔符/正则);
功能:用分隔符将原字符串进行分割
返回值:分割剩下的子串组成的数组。
var str="how are Are ARE you";
var newStr=str.split(/are/i);
alert(arr);//how,,,you
search()
格式:字符串.search(字符串/正则);
功能:找到符合字符串第一次出现位置
返回值:找到返回>=0下标,否则返回-1
var str="how Are are ARE you";
var newStr=str.search(/are/i);
alert(arr);//4
| 元字符 | 匹配情况 |
|---|---|
| . | 匹配除换行符外任意单个字符 |
| [a-z0-9] | 匹配括号中字符集任意字符 |
| [^a-z0-9] | 匹配不在括号中字符集的字符 |
| \d | 匹配数字 |
| \D | 匹配非数字同[ ^0-9]相同 |
| \w | 匹配字母数字下划线 |
| \W | 匹配非字母数字下划线 |
| 元字符 | 匹配情况 |
|---|---|
| x? | 匹配0或1个x |
| x* | 匹配0或任意多个x |
| x+ | 匹配至少一个x |
| (xyz)+ | 匹配至少一个xyz |
| x{m,n} | 匹配最少m个、最多n个x |
| 元字符 | 匹配情况 |
|---|---|
| \s | 匹配空白字符、空格、制表符和换行符 |
| \S | 匹配非空白字符 |
| \0 | 匹配null字符 |
| \b | 匹配空格字符 |
| \f | 匹配换页符 |
| \n | 匹配换行字符 |
| \r | 匹配回车字符 |
| \t | 匹配制表符 |
| 元字符 | 匹配情况 |
|---|---|
| ^ | 必须以这个正则开头 |
| $ | 必须以这个正则结尾 |
| | | 两项之间的一个选择 |
loacalStorage本地存储对象
在HTML5中,新加入了一个loaclStorage特性,这个特性作为本地存储使用,解决了cookie存储空间不足问题(每条cookie的存储空间为4k),localStorage中一般浏览器支持的是5M大小,这个在不同浏览器中localStoarage会有所不同。
setItem(name,value);
getItem(name);
removeItem(name);
if(!window.localStorage){
alert("当前页面不支持localStorage")
}else{
//设置
localStorage.setItem("a","1");
localStorage.b='2';
localStorage["c"]='3';
//获取
console.log(localStorage.getItem("b"));
console.log(localStorage.c);
console.log(localStorage['a']);
//删除
localStorage.removeItem("a");
}
this回顾
每一个函数的内置变量 指向当前函数主人
全局函数this指向window对象
对象内的函数的this指向对应名称对象
var person={
name:"123";
show:function(){
this.name;//this指向person
}
}
绑定事件的函数中的this指向绑定函数的对象
call()
apply()
格式:函数名.apply();
参数1:传入改函数this指向的对象,传入什么强制指向什么
参数2:数组,放入我们原有所有参数
apply()应用小技巧
var arr=[1,2,3,4,5]
alert(Math.min.apply(null,arr))
bind() 预设this指向
function show(x,y){
alert(this);
alert(x+","+y);
}
var res=show.bind("bind");//不调用
res(40,50);//bing 40,50
三者区别点:
主要应用场景:
//类似var 但是所声明的变量,只在let命令所在的代码块内有效。
//不存在变量提升
//暂时性死区 只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
//不允许重复声明
//应用在循环中每次不同循环会生成不同作用域
{
let a=10;
let b=1;
}
alert(a);//报错
alert(b);
/*
变量值只能在声明时确定 后续无法修改
相当于常量
*/
var IP="10.30.152.33";
//避免中途被修改
const IP="10.30.152.33";
function add(x){
return x+10;
}
var add=x => x+10;
//适当省略 函数中的function和return关键字。除了形式不一样其他完全一样。不推荐使用,可读性差
//1.无参数,无返回值
function show(){
alert("1");
}
var show=() => {alert("1")}
//2.有一个参数,无返回值
function xxx(num){
alert(num);
}
var xxx=num =>{alert(num);}
//3.有一个参数,有返回值
function add(x){
return x+10;
}
var add=x => x+10;
//==================
function add(x){
//代码
return x+10;
}
var add=x => {
//代码
return x+10
}
//4.多个参数,有返回值
function show(x,y){
return alert(x+y);
}
var show=(x,y)=>{
return alert(x+y);
}
与数组方法结合使用
//filter 过滤
var arr=[1,2,3,4,5,6];
var newArr=arr.filter(function(item){
return item>2;
})
alert(newArr);//3,4,5,6
//转换成箭头函数
var newArr=arr.filter(item => item>2);
//====================
var newArr=arr.map(item=>item*1.3);
注意:
var x=10,y=20,z=30;
var [x,y,z]=[10,20,30];
var [x,[y,z]]=[10,[20,30]];
//上面3个效果一样
var name="钢铁侠",age=18,sex="男"
var {name,age,sex}={
age:18,
name:"钢铁侠",
sex:"男"
}
//上面2个效果一样
/*
好处:
1.交换2个值
2.函数可以返回多个值
3.函数定义参数和传入参数顺序改变
- 参数可以带默认值
4.快速取出数组中某一元素
*/
//1
var [x,y]=[10,20];
[x,y]=[y,x];
//2
function xxx(){
return [1,2,3]
}
var [a,b,c]=xxx();
//3
function show({name,age=20,sex}){
alert("我叫"+name+"今年"+age+","+sex);
}
show({
age:18,
sex:"男",
name:"小明"
})
//4
var arr=[10,20,30,40,50];
var {0:first,4:last}=arr;
alert(first);
/*
传统字符串:单引号双引号
ECMA6字符串:反引号
ECMA6字符串新特性:
1.回车和缩进保留
2.${变量/表达式/函数调用}字符串拼接
*/
//2
function show({name,age=20,sex}){
alert(`我叫${name},今年${age},+${sex}`);
}
/*
Array.from() 伪数组转真数组
find()
- 功能:中查找符合条件的元素(短路操作
- 返回值;找到的元素
findIndex()
- 功能:中查找符合条件的元素(短路操作
- 返回值;找到的元素的下标
arr.copyWithin(target, start = 0, end = this.length)
- 功能:把某些个位置的元素复制并覆盖到其他位置上去
- target:目的起始位置。
start:复制源的起始位置,可以省略,可以是负数。
end:复制源的结束位置,可以省略,可以是负数,实际结束位置是end-1。
*/
//find()
var arr=[10,20,30,40,50];
var res=arr.find(function(item,index,arr){
//查找条件
return item>20;
})
//箭头函数写法
var res=arr.find(item=>item>20)
//copyWithin
var arr=[1,2,3,4,5,6,7,8,9,10];
arr.copyWithin(2,4,9) //1,2,5,6,7,8,9,8,9,10
var obj1={
a:30
b:20,
c:30,
d:40,
f:"地址"
}
var obj2={
b:20,
c:30
}
var obj3={
d:40,
f:["hello","world",true]
}
Object.assign(obj1,obj2,obj3);//从第二个参数开始,把后面的对象合并到第一个对象
//只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性
//浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
//浅拷贝:拷贝地址 深拷贝:复合数据类型重新生成一份
//遇到同名属性处理方法为替换
//为对象添加属性
集合:
Set
let imgs=new Set();
imgs.add(100);
imgs.add(100);//重复 添加不进去
imgs.add("hello");
imgs.add("hello");//重复 添加不进去
imgs.add(true);
imgs.add(new String("world"));
imgs.add(new String("world"));//每次新建一个 添加的进去
/*
集合遍历
for...of
*/
for(let item of imgs.keys()){
console.log(item);
}
for(let item of imgs.values()){
console.log(item);
}
for(let item of imgs.entries()){
console.log(item);
}
/*
利用集合去重
*/
var set=new Set([2,3,3,4,4]);
var arr=[...set];//将数据结构展开成数组
var arr=[1,1,2,2,3,3];
arr=[...new Set(arr)];
Map映射
//声明
let map =new Map();
//添加
map.set("张三","打渔");
map.set("李四","种地");
map.set("王五","挖煤");
//取值
alert(map.get("王五"));
//遍历for of
for(let [key,value] of map){
console.log(key,value);
}
数组
for循环
var arr=[10,20,30,40,60];
for(var i=0;i<arr.length;i++){
document.write(arr[i]+","+i);
}
for...in
for(var i in arr){
document.write(arr[i]+","+i);
}
foreach
arr.forEach(function(item,index){
document.write(item+","+index);
})
for...of
for(var item of arr){
//item是当前遍历元素
document.write(item);
}
对象
for...in
for(var attr in obj){
//attr是obj对象的属性
document.write(attr+","+obj[attr]);
}
集合
/*
prototype原型对象
概念:每一个函数,都有一个原型对象prototype
用在构造函数上,我们可以给构造函数的原型prototype,添加方法,构造出来的对象共享原型上所有方法
*/
//通过new调用函数:构造函数,可以构造对象
//构造函数首字母大写
function Person(name,sex){
//1.原料
//var obj=new Object();
//加new this=new Object
//2.加工
this.name=name;
this.sex=sex;
this.showName=function(){
alert("我的名字叫"+this.name);
}
this.showSex=function(){
alert("我的性别是"+this.sex+"的");
}
//3.出厂
//return obj;
//加new return this;
}
var p1= new Person("blue","男");
/*
如果某一函数使用new运算符调用
1.当前函数中的this指向新创建的对象
2.自动去完成1.原料和3.出厂
*/
//=============================================
//最终效果 类似于 类
function Person(name,sex){
this.name=name;
this.sex=sex;
}
Person.prototype.showName=function(){
alert("我的名字叫"+this.name);
}
Person.prototype.showSex=function(){
alert("我的性别是"+this.sex+"的");
}
父类
function Person(name){
this.name=name;
this.sum=function(){
alert(this.name)
}
}
Person.prototype.age=10;
function Per(){
this.name="ker";
}
Per.prototype=new Person();//原型链继承
var per1=new Per();
console.log(per1.age);//10
概念:让新实例的原型等于父类的实例
特点:实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:
function Per(){
Person.call(this,"jer");//借用构造函数继承
this.age=12;
}
var per1=new Per();
console.log(per1.name);//jer
console.log(per1.age);//12
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:
缺点:
function Per(name){
Person.call(this,name);//借用构造函数
}
Per.prototype=new Person();//原型链继承
var per=new Per("ker");
console.log(sub.name);//gar 继承构造函数属性
console.log(sub.age);//10 继承父类原型属性
重点:结合了两种模式的优点,传参和复用
特点:
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
function Person(name){
this.name=name;
this.sum=function(){
alert(this.name)
}
}
Person.prototype.age=10;
//先封装一个函数容器,用来输出对象和承载继承的原型
function content(obj){
function F(){}
F.prototype=obj;//继承传入参数
return new F();//返回函数对象
}
var sup=new Person();//拿父类实例
var sup1=content(sup);
console.log(sup1.age);//10 继承了父类函数属性
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:
//先封装一个函数容器,用来输出对象和承载继承的原型
function content(obj){
function F(){}
F.prototype=obj;//继承传入参数
return new F();//返回函数对象
}
var sup=new Person();//拿父类实例
function subobject(obj){
var sub=content(obj);
sub.name="gar";
return sub;
}
var sup2=subobject(sup);
//这个函数经过声明之后成了可增添属性的对象
console.log(typeof subobject);//function
console.log(typeof sup2);//object
console.log(sup2.name);//"gar",返回sub对象 继承了sub的属性
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
寄生:在函数内返回对象然后调用
组合:1、函数原型等于另一个实例。2、在函数中用apply或call引入另一个构造函数,可以传参
//寄生
function content(obj){
function F(){}
F.prototype=obj;
return new F();
}
//content就是F实例的另一种表示法
var con=content(Person.peototype);
//con实例(F实例)的原型继承了父类函数的原型
//上述更像是原型链继承,只不过只继承了原型属性
//组合
function Sub(){
Person.call(this);//继承了父类构造函数属性
}//解决了组合式量词调用构造函数属性缺点
//重点:
Sub.prototype=con;//继承了con实例
con.constructor=Sub;//一定要修复实例
var sub1=new Sub();
//Sub的实例就继承了构造函数属性,父类实例,con的函数属性
console.log(sub1.age);//10;
重点:修复了组合继承的问题
多态背后的思想是将”做什么“和”谁去做以及怎样去做分开“。
非多态代码示例
var makeSound = function(animal) {
if(animal instanceof Duck) {
console.log('嘎嘎嘎');
} else if (animal instanceof Chicken) {
console.log('咯咯咯');
}
}
var Duck = function(){}
var Chiken = function() {};
makeSound(new Chicken());
makeSound(new Duck());
多态代码实例
var makeSound = function(animal) {
animal.sound();
}
var Duck = function(){}
Duck.prototype.sound = function() {
console.log('嘎嘎嘎')
}
var Chicken = function() {};
Chiken.prototype.sound = function() {
console.log('咯咯咯')
}
makeSound(new Chicken());//咯咯咯
makeSound(new Duck());//嘎嘎嘎
__proto__,指向构造出这个对象的构造函数的原型。传统构造函数写法
function Person(name,sex,age){
this.name=name;
this.sex=sex;
this.age=age;
}
Person.prototype.show=function(){
alert('我的名字叫${this.name},今年${this.age}岁,${this.sex}');
}
ECMA6 class
class Person{
constructor(name,sex,age){
this.name=name;
this.sex=sex;
this.age=age;
}
show(){
alert('我的名字叫${this.name},今年${this.age}岁,${this.sex}');
}
}
//继承
class Worker extends Person{
construtor(name,sex,age,job){
//继承父级属性
super(name,sex,age);
this.job=job;
}
showJob(){
alert("我的工作是"+this.job);
}
}