JavaScript基础内容
关于js
<!-- 1.JavaScript历史
布兰登 艾奇(Brendan Eich)
神奇的大哥在1995年利用10天完成JavaScript设计。
网景公司最初命名为LiveScript,后来在与Sun合作之后将其改名为JavaScript;
2.JavaScript是:
JavaScript是世界上最流行的语言之一,是一种运行在客户端的脚本语言(script是脚本的意思);
脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行;
现在也可以基于Node.js技术进行服务器端编程;
3.JavaScript的作用:
表单动态效验(密码强度检测);
网页特效;
服务端开发(node.js);
桌面程序(Electron);
APP(Cordova);
控制硬件-物联网(Ruff);
游戏开发(cocos2d-js);
4.HTML/CSS/JS的关系:
HTML决定网页结构和内容,css决定网页呈现给用户的样式,js脚本语言实现业务逻辑和页面控制功能。
5.浏览器执行js简介
浏览器分成两部分:
渲染引擎:用来解析HTML与css,俗称内核,比如Chrome浏览器的blink,老版本的webkit;
js引擎:也称js解释器,用来读取网页中的JavaScript代码,对其处理后运行,比如Chrome浏览器的v8;
浏览器本身并不会执行js代码,而是通过内置JavaScript引擎来执行js代码,js引擎执行代码时会逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以JavaScript语言归为脚本语言,会逐行解释执行。
6.ECMAScript:
是由ECMA国际(原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为JavaScript或JScript,但实际上后两者是ECMAScript语言的实现和扩展;ECMAScript规定了js的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套js语法工业标准。
7.js的组成:
DOM-文档对象模型,是W3C组织推荐的可处理可扩展标记语言的标准编程接口,通过DOM提供的接口可以对页面上的各种元素进行操作(大小位置颜色等);
BOM-浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构;通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等;
-->
<!-- js三种书写位置:
行内:onclick="alert('行内式')"
内部;
外部<script src="my.js"></script>; -->
<!-- //单行注释
/* */多行注释 -->
js输出
//js输出:
// prompt('这是一个网页弹窗输入框');
// alert('弹出警示框');
// console.log('控制台输出打印信息,测试使用');
js变量
//变量
//1.声明变量并赋值,即变量初始化: var age=18; var name='name';自动分配内存空间
// 常用变量名:
// var name = prompt("请输入你的名字"); //prompt所取值是字符型
// alert(name);
//只声明不赋值则:未定义undefined
//不声明不赋值直接使用会报错
//变量命名规范:字母数字下划线美元符 首字母小写后面单词大写
// //
// var temp;
// var app1=1;
// var app2=2;
// temp=app1;
// app1=app2;
// app2=temp;
// js的变量数据类型由值确定,与变量名无关;
// js是动态语言,变量数据类型可变;
// 数据类型: 默认值
// Number 0
// (八进制(以0开头);十六进制(以0x开头) 数字型最大值alert(Number.MAX_VALUE);最小值alert(Number.MIN_VALUE); 无穷大alert(Infinity);无穷小alert(-Infinity); NaN代表一个非数值;
// isNaN()是数字返回true,否则false)
Number
JavaScript不区分整数和浮点数,统一用Number表示,以下都是合法的Number类型:
123; // 整数123
0.456; // 浮点数0.456
1.2345e3; // 科学计数法表示1.2345x1000,等同于1234.5
-99; // 负数
NaN; // NaN表示Not a Number,当无法计算结果时用NaN表示
Infinity; // Infinity表示无限大,当数值超过了JavaScript的Number所能表示的最大值时,就表示为 Infinity
// String
// 字符串转义;console.log(str.length);
// 字符串拼接:数值相加,字符相连;
// var age=prompt('请输入您的年龄');
// var str='您今年'+age+'岁';
// alert(str);
// 输出数据类型:conole.log(typeof str);
// 数据类型转换:toString()转成字符串 var num=2;alert(num.toString());
// String()强制转换 var num=1;alert(String(num));
// 加号拼接字符串
// conole.log(parseInt(age));字符型转换为数字型,取整
// 去掉单位parseInt('120px'); 120
// parseInt('rem120px'); NaN
// parseFloat('age'); 取小数
// 数字型强制转换Number(str);
// 例1:
// var year = prompt('请输入您的出生年份');
// alert('您今年' + (2020 - year) + '岁了');
// 例2:
// var num1 = prompt('请输入第一个数');
// var num2 = prompt('请输入第二个数');
// alert('您的结果是' + (Number(num1) + Number(num2)));
null表示一个“空”的值,它和0以及空字符串''不同,0是一个数值,''表示长度为0的字符串,而null表示“空”。
大多数情况下,我们都应该用null。undefined仅仅在判断函数参数是否传递的情况下有用。
ASCII字符可以以\x##形式的十六进制表示,例如:
'\x41'; // 完全等同于 'A'
还可以用\u####表示一个Unicode字符:
'\u4e2d\u6587'; // 完全等同于 '中文'
标识符及运算符
// 标识(zhi)符,关键字,保留字
// 运算符oprerator
// + 加 - 减 * 乘 / 除 % 取余
// 浮点数直接运算会出现误差,也不能进行等值比较,一般化为整数后运算
// num++;
// var e = 10;
// var f = e++ + ++e; //e++=10 e=1 e=12 ++e=12
// console.log(f); //22 e++遇到+使用e值后便自增,不用等到分号
// console.log(18 == '18'); //true 默认转换数据类型,会把字符串型转换为数字型
// console.log(18 === '18'); //false ===全等于 数据类型与数据要完全相同
这里有个特殊情况,NaN===NaN;返回false 唯一能判断的方法是isNaN(),isNaN(NaN);返回true
// 逻辑与 &&
// 逻辑或 ||
// console.log(123 && 456); //456
// &&和||存在逻辑中断,即会产生计算中断,&和|不会
// 运算优先级 先 && 后 ||
字符串常用方法
toUpperCase
toUpperCase()
把一个字符串全部变为大写:
var s = 'Hello';
s.toUpperCase(); // 返回'HELLO'
toLowerCase
toLowerCase()
把一个字符串全部变为小写:
var s = 'Hello';
var lower = s.toLowerCase(); // 返回'hello'并赋值给变量lower
lower; // 'hello'
indexOf
indexOf()
会搜索指定字符串出现的位置:
var s = 'hello, world';
s.indexOf('world'); // 返回7
s.indexOf('World'); // 没有找到指定的子串,返回-1
substring
substring()
返回指定索引区间的子串:
var s = 'hello, world'
s.substring(0, 5); // 从索引0开始到5(不包括5),返回'hello'
s.substring(7); // 从索引7开始到结束,返回'world'
类型转换
强制转换
通过String(),Number(),Boolean()函数强制转换
var str=123;
var str1='123';
var str2='123a';
console.log(typeof str); //number
console.log(typeof str1); //string
console.log(typeof String(str)); //string
console.log(typeof Number(str1)); //number
console.log(typeof Number(str2)); //NaN
隐式转换
JavaScript的数据类型分为六种,分别为null,undefined,boolean,string,number,object。(array数组也属于object类型)object是引用类型,其它的五种是基本类型或者是原始类型。我们可以用typeof方法打印来某个是属于哪个类型的。不同类型的变量比较要先转类型,叫做类型转换,类型转换也叫隐式转换。隐式转换通常发生在运算符加减乘除,等于,还有小于,大于等。
1.字符串加数字,数字就会转成字符串。
2.数字减字符串,字符串转成数字。如果字符串不是纯数字就会转成NaN。字符串减数字也一样。两个字符串相减也先转成数字。
3.乘,除,大于,小于跟减的转换也是一样
console.log(10+'20') //2010
console.log(10-'20')//-10 number
console.log(10-'a') //NaN not a number
console.log(10-'101a') //NaN
console.log(10*'20') //200 number
console.log('10'*'20') //200 number
console.log(20/'10') //2 number
console.log('20'/'10') //2 number
console.log('20'/'one') //NaN
关于==
1.undefined等于null
2.字符串和数字比较时,字符串转数字
3.数字为布尔比较时,布尔转数字
4.字符串和布尔比较时,两者转数字
console.log(undefined==null) //true
console.log('0'==0) //true 字符串转数字
console.log(0==false) //true 布尔转数字
console.log('0'==false) //2个都转成数字
console.log(null==false) //false
console.log(undefined==false)//false
分支和循环
// var age = prompt('请输入年龄:');
// if (age > 18) {
// alert('ok');
// }
// 三元表达式 ? :
// var time = prompt('0~59');
// result = time < 10 ? '0' + time : time;
// switch(num){
// case value1: ;break;
// case value2: ;break;
// default: ;
// // num===value1才匹配
// }
// for (var i = 1; i <= 100; i++) {
// console.log('1');
// }
// 断点调试
// var sum = 0;
// for (var i = 1; i <= 100; i++) {
// console.log(sum += i);
// }
// 打印几行几列星星
// var x = prompt('请输入打印星星的行数');
// var y = prompt('请输入打印星星的列数');
// var str = '';
// for (var i = 1; i <= x * y; i++) {
// str += '☆';
// if (i % y == 0) {
// str += '\n';
// }
// }
// console.log(str);
// var rows = prompt('请输入打印星星的行数');
// var cols = prompt('请输入打印星星的列数');
// var str = '';
// for (var i = 1; i <= rows; i++) {
// for (var j = 1; j <= cols; j++) {
// str += '☆';
// }
// str += '\n';
// }
// console.log(str);
//单循环打印倒三角形未实现
// var xin = prompt('请输入打印行数');
// var num = xin;
// var str = '';
// for (var i = 1; i <= xin * (xin + 1) / 2; i++) {
// str += '☆';
// if (i == num) {
// var j = i - num;
// str += '\n';
// num--;
// }
// }
// 双重循环打印倒三角形
// var xin = prompt('请输入打印行数');
// var str = '';
// for (var i = 1; i <= xin; i++) {
// for (var j = i; j <= xin; j++) {
// str += '☆';
// }
// str += '\n';
// }
// console.log(str);
// 九九乘法表
// var str = '';
// for (var i = 1; i <= 9; i++) {
// for (var j = 1; j <= i; j++) {
// str += j + '*' + i + '=' + i * j + ' ';
// }
// str += '\n';
// }
// console.log(str);
// var message = '我爱你';
// while (message !== '我爱你') { //当 为真则重复执行,为假退出
// prompt('你爱我吗');
// }
// do {
// prompt('你爱我吗');
// } while (message !== '我爱你') //直到 为真重复执行,为假退出
// continue 退出当前次循环,通常结合if使用
// break 退出整个循环,循环结束
数组
// 命名规范
// var arr = new Array();
// var arr = [];
// 遍历数组:
// var arr = [1, 2, 3, 4, 5];
// for (var i = 0; i < arr.length; i++) {
// console.log(arr[i]);
// }
// 找出最大数
// var num = [2, 4, 1, 9, 5, 7];
// var max = num[0];
// for (var i = 0; i < num.length; i++) {
// if (max < num[i]) {
// max = num[i];
// }
// }
// console.log(max);
// 1.数组新增元素 修改length长度 arr.length+=s; 新增元素为empty空 undefined
// 2.直接追加 arr[4]='num';
// var arr = [1, 2];
// arr[arr.length] = 3;
// console.log(arr.length);
// console.log(arr);
// var arr = [];
// for (var i = 0; i < 10; i++) {
// arr[i] = i + 1;
// }
// 冒泡排序
// var num = [2, 4, 1, 9, 5, 7];
// for (var i = 0; i < num.length; i++) {
// for (var j = 0; j < num.length - i-1; j++) {
// if (num[j] > num[j + 1]) {
// var temp = num[j];
// num[j] = num[j + 1];
// num[j + 1] = temp;
// }
// }
// }
// console.log(num);
数组常用方法
indexOf
与String类似,Array
也可以通过indexOf()
来搜索一个指定的元素的位置:
var arr = [10, 20, '30', 'xyz'];
arr.indexOf(10); // 元素10的索引为0
arr.indexOf(20); // 元素20的索引为1
arr.indexOf(30); // 元素30没有找到,返回-1
arr.indexOf('30'); // 元素'30'的索引为2
注意了,数字`30`和字符串`'30'`是不同的元素。
slice
slice()
就是对应String的substring()
版本,它截取Array
的部分元素,然后返回一个新的Array
:
var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
arr.slice(0, 3); // 从索引0开始,到索引3结束,但不包括索引3: ['A', 'B', 'C']
arr.slice(3); // 从索引3开始到结束: ['D', 'E', 'F', 'G']
注意到slice()
的起止参数包括开始索引,不包括结束索引。
如果不给slice()
传递任何参数,它就会从头到尾截取所有元素。利用这一点,我们可以很容易地复制一个Array
:
var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
var aCopy = arr.slice();
aCopy; // ['A', 'B', 'C', 'D', 'E', 'F', 'G']
aCopy === arr; // false
push和pop
push()
向Array
的末尾添加若干元素,pop()
则把Array
的最后一个元素删除掉:
var arr = [1, 2];
arr.push('A', 'B'); // 返回Array新的长度: 4
arr; // [1, 2, 'A', 'B']
arr.pop(); // pop()返回'B'
arr; // [1, 2, 'A']
arr.pop(); arr.pop(); arr.pop(); // 连续pop 3次
arr; // []
arr.pop(); // 空数组继续pop不会报错,而是返回undefined
arr; // []
unshift和shift
如果要往Array
的头部添加若干元素,使用unshift()
方法,shift()
方法则把Array
的第一个元素删掉:
var arr = [1, 2];
arr.unshift('A', 'B'); // 返回Array新的长度: 4
arr; // ['A', 'B', 1, 2]
arr.shift(); // 'A'
arr; // ['B', 1, 2]
arr.shift(); arr.shift(); arr.shift(); // 连续shift 3次
arr; // []
arr.shift(); // 空数组继续shift不会报错,而是返回undefined
arr; // []
sort
sort()
可以对当前Array
进行排序,它会直接修改当前Array
的元素位置,直接调用时,按照默认顺序排序:
var arr = ['B', 'C', 'A'];
arr.sort();
arr; // ['A', 'B', 'C']
reverse
reverse()
把整个Array
的元素给调个个,也就是反转:
var arr = ['one', 'two', 'three'];
arr.reverse();
arr; // ['three', 'two', 'one']
splice
splice()
方法是修改Array
的“万能方法”,它可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素:
var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];
// 从索引2开始删除3个元素,然后再添加两个元素:
arr.splice(2, 3, 'Google', 'Facebook'); // 返回删除的元素 ['Yahoo', 'AOL', 'Excite']
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
// 只删除,不添加:
arr.splice(2, 2); // ['Google', 'Facebook']
arr; // ['Microsoft', 'Apple', 'Oracle']
// 只添加,不删除:
arr.splice(2, 0, 'Google', 'Facebook'); // 返回[],因为没有删除任何元素
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
concat
concat()
方法把当前的Array
和另一个Array
连接起来,并返回一个新的Array
:
var arr = ['A', 'B', 'C'];
var added = arr.concat([1, 2, 3]);
added; // ['A', 'B', 'C', 1, 2, 3]
arr; // ['A', 'B', 'C']
请注意,concat()
方法并没有修改当前Array
,而是返回了一个新的Array
。
实际上,concat()
方法可以接收任意个元素和Array
,并且自动把Array
拆开,然后全部添加到新的Array
里:
var arr = ['A', 'B', 'C'];
arr.concat(1, 2, [3, 4]); // ['A', 'B', 'C', 1, 2, 3, 4]
join
join()
方法是一个非常实用的方法,它把当前Array
的每个元素都用指定的字符串连接起来,然后返回连接后的字符串:
var arr = ['A', 'B', 'C', 1, 2, 3];
arr.join('-'); // 'A-B-C-1-2-3'
如果Array
的元素不是字符串,将自动转换为字符串后再连接。
函数
//累加函数
// function getSum(start, end) { //形参,仅代表一个未知数,用来接收实参的数用于计算,不需声明
// var sum = 0;
// for (var i = start; i <= end; i++) {
// sum += i;
// }
// console.log(sum);
// }
// getSum(1, 100); //实参,给定值 多余舍弃取前面有效的,少于形参个数则定义为undefined,结果NaN
// var get = function () { //匿名函数
// var sum = 0;
// for (var i = 1; i <= 100; i++) {
// sum += i;
// }
// return sum; //return后面的语句不执行,且只能返回一个值,返回多个值用数组 没有return则返回undefined
// }; //这里需要分号,上面一种方法不用
// console.log(get()); //这里犯了一个错误,之前get没有加括号,导致输出的是打印函数代码,这里的get此时已经作为函数对象而不是数,所以需要用调用函数的方法使用
// //求最大值
// function getArrMax(arr) {
// var max = arr[0];
// for (var i = 1; i < arr.length; i++) {
// if (arr[i] > max) {
// max = arr[i];
// }
// }
// return max;
// }
// var array = [5, 3, 6, 7];
// var re = getArrMax(array);
// console.log(re);
//arguments的使用
//arguments是一个伪数组,用于存储所有传递过来的实参
// 1. 具有数组的length属性
// 2. 按照索引的方式进行存储
// 3. 没有真正数组的pop(),push()等方法
// arguments 此时为数组的数据类型
// arguments.length
// arguments[2]
// 按照数组的方式遍历
// for(var i=0;i<arguments.length;i++){
// console.log(arguments[i]);
// }
//利用函数翻转任意数组 reverse 翻转
// function reverse(arr) {
// var newArr = [];
// for (var i = arr.length - 1; i >= 0; i--) {
// newArr[newArr.length] = arr[i];
// }
// return newArr;
// }
// var arr1 = [2, 6, 3, 8, 4];
// var re = reverse(arr1);
// console.log(re);
//求闰年
// function isRunYear(year) {
// var flag = false;
// if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
// flag = true;
// }
// return flag;
// }
// console.log(isRunYear(2000));
// function backDay(){
// var year=prompt('请输入年份');
// if(isRunYear(year)){
// console.log(29);
// }else{
// console.log(28);
// }
// }
作用域
//作用域
//var声明作用域
// 未声明时作为全局变量
// 执行效率:
// 1.全局变量只有浏览器关闭时才会销毁,比较占内存资源 任何地方都可使用
// 2.局部变量当我们程序执行完毕就会销毁,比较节约内存资源 只能在函数内部使用
// es6新增块级作用域{}
// 花括号外面的不能调用里面的
// 作用域链
// 内部函数可以访问外部函数的变量, 由内而外,就近原则
// 预解析 + 代码执行
// 预解析js引擎会把js里所有的 var 与 function 提升到当前作用域的最前面
// 变量预解析:只提升变量声明,不提升赋值操作;
// 函数预解析:同理
// var a = b = c = 9; 相当于var a = 9; b = 9; c = 9; 此时b和c是全局变量
对象
//对象
//包括属性和方法 :用逗号
// var object = {
// uname: 'zzh',
// sex: '男',
// sayHi: function () {
// console.log(s); //s未定义 undefined
// console.log('hi'); //输出hi
// }
// }
// object.属性名 = "属性值"; //添加属性 属性名可以为汉字
// object['属性名'] = "属性值"; //添加属性
// console.log(object.sex); // 得到属性值
// console.log(object['sex']); //得到属性值,属性名不是一个有效的变量时就要用此方法访问属性
// console.log(object.属性名);
// console.log(object);
// object.sayHi();
//第二种创建对象的方法 =用分号
// var obj = new Object();
// obj.uname = 'zz';
// obj.age = 20;
// obj.sayHi = function () {
// }
// 构造函数 构造函数名首字母大写
// function Star(uname, age, sex) {
// this.name = uname;
// this.age = age;
// this.sex = sex;
// this.sing = function (song) {
// console.log(song);
// }
// }
// var ldh = new Star('刘德华', 18, '男'); //利用构造函数创建对象
// ldh.sing('ss');
// new关键字执行过程:
// 1.在内存中创建一个新的空对象;
// 2.this指向这个新对象;
// 3.执行构造函数里的代码,给新对象添加属性和方法;
// 4.返回新对象。
// 遍历对象
// for (k in obj) { //一般用k 或key
// console.log(k); //得到的是属性名
// console.log(obj[k]); //得到的是属性值
// }
如果我们要检测xiaoming是否拥有某一属性,可以用in操作符:
var xiaoming = {
name: '小明',
birth: 1990,
school: 'No.1 Middle School',
height: 1.70,
weight: 65,
score: null
};
'name' in xiaoming; // true
'grade' in xiaoming; // false
不过要小心,如果in判断一个属性存在,这个属性不一定是xiaoming的,它可能是xiaoming继承得到的:
'toString' in xiaoming; // true
因为toString定义在object对象中,而所有对象最终都会在原型链上指向object,所以xiaoming也拥有toString属性。
要判断一个属性是否是xiaoming自身拥有的,而不是继承得到的,可以用hasOwnProperty()方法:
var xiaoming = {
name: '小明'
};
xiaoming.hasOwnProperty('name'); // true
xiaoming.hasOwnProperty('toString'); // false
JavaScript把null、undefined、0、NaN和空字符串''视为false,其他值一概视为true,因此上述代码条件判断的结果是true
map和set
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95
初始化Map
需要一个二维数组,或者直接初始化一个空Map
。Map
具有以下方法:
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉:
var m = new Map();
m.set('Adam', 67);
m.set('Adam', 88);
m.get('Adam'); // 88
Set
和Map
类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set
中,没有重复的key。
要创建一个Set
,需要提供一个Array
作为输入,或者直接创建一个空Set
:
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3
重复元素在Set
中自动被过滤:
var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}
注意数字3
和字符串'3'
是不同的元素。
通过add(key)
方法可以添加元素到Set
中,可以重复添加,但不会有效果:
s.add(4);
s; // Set {1, 2, 3, 4}
s.add(4);
s; // 仍然是 Set {1, 2, 3, 4}
通过delete(key)
方法可以删除元素:
var s = new Set([1, 2, 3]);
s; // Set {1, 2, 3}
s.delete(3);
s; // Set {1, 2}
小结
Map
和Set
是ES6标准新增的数据类型,请根据浏览器的支持情况决定是否要使用。
iterable
遍历Array
可以采用下标循环,遍历Map
和Set
就无法使用下标。为了统一集合类型,ES6标准引入了新的iterable
类型,Array
、Map
和Set
都属于iterable
类型。
具有iterable
类型的集合可以通过新的for ... of
循环来遍历。
用for ... of
循环遍历集合,用法如下:
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
console.log(x);
}
for (var x of s) { // 遍历Set
console.log(x);
}
for (var x of m) { // 遍历Map
console.log(x[0] + '=' + x[1]);
}
你可能会有疑问,for ... of
循环和for ... in
循环有何区别?
for ... in
循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array
数组实际上也是一个对象,它的每个元素的索引被视为一个属性。
当我们手动给Array
对象添加了额外的属性后,for ... in
循环将带来意想不到的意外效果:
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
console.log(x); // '0', '1', '2', 'name'
}
for ... in
循环将把name
包括在内,但Array
的length
属性却不包括在内。
for ... of
循环则完全修复了这些问题,它只循环集合本身的元素:
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
console.log(x); // 'A', 'B', 'C'
}
这就是为什么要引入新的for ... of
循环。
然而,更好的方式是直接使用iterable
内置的forEach
方法,它接收一个函数,每次迭代就自动回调该函数。以Array
为例:
`'use strict';`
var a = ['A', 'B', 'C'];
`a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
console.log(element + ', index = ' + index);
});`
注意,forEach()
方法是ES5.1标准引入的,你需要测试浏览器是否支持。
Set
与Array
类似,但Set
没有索引,因此回调函数的前两个参数都是元素本身:
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
console.log(element);
});
Map
的回调函数参数依次为value
、key
和map
本身:
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
console.log(value);
});
如果对某些参数不感兴趣,由于JavaScript的函数调用不要求参数必须一致,因此可以忽略它们。例如,只需要获得Array
的element
:
var a = ['A', 'B', 'C'];
a.forEach(function (element) {
console.log(element);
});
内置对象
- Math数学对象
//内置对象
//三大对象:自定义对象,内置对象,浏览器对象
//前两个属于ECMAScript
// // Math数学对象 直接使用
// console.log(Math.PI); //圆周率
// console.log(Math.max(3, 5, 7)); // 7
// console.log(Math.max(3, 's')); //NaN
//自己封装数学对象
// var myMath = {
// PI: 3.141592653,
// max: function () {
// var max = arguments[0];
// for (var i = 1; i < arguments.length; i++) {
// if (arguments[i] > max) {
// max = arguments[i];
// }
// }
// return max;
// },
// min: function () {
// var min = arguments[0];
// for (var i = 1; i < arguments.length; i++) {
// if (arguments[i] > min) {
// min = arguments[i];
// }
// }
// return min;
// }
// }
// console.log(myMath.max(1, 5, 7));
// Math常用方法 含隐式转换
// Math.PI //圆周率
// Math.floor() //向下取整 1.1取1
// Math.ceil() //向上取整 1.1取2
// Math.round() //四舍五入,就近取整 -3.5得-3
// Math.abs() //绝对值
// Math.max() /Math.min() //最大最小值
// 随机数
// Math.random(); 返回一个随机小数 [0,1)
// 包含端点的随机整数
// Math.floor(Math.random() * (max - min + 1)) + min
// 随机数函数
// function getRandom(min, max) {
// return Math.floor(Math.random() * (max - min + 1)) + min;
// }
// console.log(getRandom(1, 10));
// 猜数字游戏
// var random = getRandom(1, 10);
// var i = 0;
// while (1) {
// var num = prompt('请输入一个数字');
// if (num > random) {
// alert('你猜大了,还有' + (2 - i) + '次机会');
// } else if (num < random) {
// alert('你猜小了,还有' + (2 - i) + '次机会');
// } else {
// alert('恭喜你,猜对了');
// break;
// }
// i++;
// if (i >= 3) {
// alert('游戏结束');
// break;
// }
// }
Data日期对象
// Data()日期对象 是一个构造函数,必须使用new调用创建日期对象
// var date = new Date(); //有参数则返回参数时间 '2020-8-4'或'2020/8/4' 字符串形式
// var year = date.getFullYear();
// var month = date.getMonth() + 1; //返回月 0-11
// var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
// var day = date.getDay(); // 1-6 星期日为 0
// var oneday = arr[day];
// var hour = date.getHours();
// var h = hour < 10 ? '0' + hour : hour;
// var min = date.getMinutes();
// var s = date.getSeconds();
// console.log(date);
//返回当前时间函数
// function getTimer() {
// var hour = date.getHours();
// var hour = hour < 10 ? '0' + hour : hour;
// var min = date.getMinutes();
// var min = min < 10 ? '0' + min : min;
// var s = date.getSeconds();
// var s = s < 10 ? '0' + s : s;
// return hour + ':' + min + ':' + s;
// }
// console.log(getTimer());
//时间戳
// var date = new Date();
// //第一种方法
// console.log(date.valueOf()); //获取现在距离1970年1月1日过的毫秒数
// //第二种方法
// console.log(date.getTime()); //valueOf()与getTime效果相同
// //第三种方法
// var date1 = +new Date();
// //第四种方法 H5新增
// console.log(Date.now());
// 时分秒转换公式
// d = parseInt(总秒数 / 60 / 60 / 24); //计算天数
// h = parseInt(总秒数 / 60 / 60 % 24); //计算小时
// m = parseInt(总秒数 / 60 % 60); //计算分钟
// s = parseInt(总秒数 % 60); //计算当前秒数
//封装倒计时函数
function countDown(time) {
var nowTime = +new Date();
var inputTime = +new Date(time);
var times = Math.abs((inputTime - nowTime) / 1000); //1秒=1000毫秒
d = parseInt(times / 60 / 60 / 24); //计算天数 取整parseInt()
d = d < 10 ? '0' + d : d;
h = parseInt(times / 60 / 60 % 24); //计算小时
h = h < 10 ? '0' + h : h;
m = parseInt(times / 60 % 60); //计算分钟
m = m < 10 ? '0' + m : m;
s = parseInt(times % 60);
s = s < 10 ? '0' + s : s;
if (inputTime - nowTime >= 0) {
return d + '天' + h + '时' + m + '分' + s + '秒';
} else {
return '-' + d + '天' + '-' + h + '时' + '-' + m + '分' + '-' + s + '秒';
}
}
console.log(countDown('2020-12-1 14:00:00'));
- 数组对象
// 数组对象
// 1.字面量创建数组
// var srr=[1,2,3];
// 2.
// var arr1=new Array(2); 2表示数组长度为2,有两个空元素
// var arr2=new Array(2,4); 等价于[2,4]
//利用函数翻转任意数组 reverse 翻转
// function reverse(arr) {
// if(arr instanceof Array){
// var newArr = [];
// for (var i = arr.length - 1; i >= 0; i--) {
// newArr[newArr.length] = arr[i];
// }
// return newArr;
// }else{
// return 'error';
// }
// }
// var arr1 = [2, 6, 3, 8, 4];
// var re = reverse(arr1);
// console.log(re);
// 检测是否为数组
// 1.instanceof运算符
// console.log(arr instanceof Array);
// 2.Array.isArray() H5新增,ie9以上支持
// console.log(Array.isArray(arr));
//添加删除数组元素方法
//1.push() //推,在数组末尾添加数组元素
// var arr = [1, 2, 3, 4];
// arr.push(4, 5, 6);
// console.log(arr.push(4, 5, 6)); // push完毕后会返回新的数组长度 此例为7
// console.log(arr);
// 2.unshift //在数组开头添加数组元素
// console.log(arr.unshift(0, 10)); //unshif也有返回值,同push
// //3.pop() //删除最后一个元素,不跟参数,一次只能一个
// console.log(arr.pop()); // pop完毕后会返回删除的元素
// //4.shift() 删除第一个元素 一次一个,有返回值,不带参数
// console.log(arr.shift());
// 数组排序
// var arr=[1,3,5,7];
// arr.reverse(); //翻转
// console.log(arr);
// var arr1=[3,6,13,2,4];
// arr1.sort(function(a,b){
// return a-b; //升序排列
// // return b-a; //降序排列
// });
// console.log(arr1);
//数组索引
// var arr=[1,2,3,4];
// console.log(arr.indexOf(2)); //返回该元素索引号,只返回第一个,找不到则返回-1
// console.log(arr.lastIndexOf(3)); //从后往前查找
//数组去重(重点)
// function unique(arr) {
// var newArr = [];
// for (var i = 0; i < arr.length; i++) {
// if (newArr.indexOf(arr[i]) === -1) {
// newArr.push(arr[i]);
// }
// }
// return newArr;
// }
// var arr = ['c', 'a', 'x', 'a', 'c', 'z'];
// console.log(unique(arr));
// //数组转换为字符串
// var arr = [2, 5, 4];
// console.log(arr.toString());
// console.log(String(arr));
// //可自定义分隔符的转换字符串
// console.log(arr.join('&'));
// //concat() 连接两个或多个数组,不影响原数组 返回新数组
// const array1 = ['a', 'b', 'c'];
// const array2 = ['d', 'e', 'f'];
// const array3 = array1.concat(array2); //连接多个数组 array2,array3,array4
// console.log(array3);
// //slice() 数组截取
// const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
// console.log(animals.slice(2)); //从索引号2起往后截取,包括2
// // expected output: Array ["camel", "duck", "elephant"]
// console.log(animals.slice(2, 4)); // 包括2不包括4
// // expected output: Array ["camel", "duck"]
// console.log(animals.slice(1, 5));
// // expected output: Array ["bison", "camel", "duck", "elephant"]
//splice() 数组删除
//待续
//
//p176
- 遍历操作基础
//基本包装类型:把简单数据类型包装成为复杂数据类型,复杂数据类型如对象 才有属性和方法;
// var str = 'str';
// console.log(str.length);
// //如同
// var temp = new String('str');
// str = temp;
// temp = null;
// //字符串的不可变
// var str = 'red';
// console.log(str);
// str = 'pink'; //此时是重新开辟了一个空间存放pink,然后让str指向pink,原来的red空间仍然存在
// console.log(str);
//字符串所有的方法都不会修改字符串本身,操作完成会返回一个新字符串
//str.indexOf('要查找的字符串',[起始位置])
//查找字符串中某个字符出现的次数
// var str = 'sidjfhffosjdf';
// var num = 0;
// var index = str.indexOf('f'); //从第一个开始找,得索引值
// while (index !== -1) { //找到了则执行
// console.log(index); //打印索引值
// num++;
// index = str.indexOf('f', index + 1); //索引值+1了继续找,找到又得到索引值
// }
// console.log('f出现的次数是:' + num);
//查找数组中值出现的次数
// var color = ['red', 'blue', 'red', 'green', 'pink', 'red'];
// var index = color.indexOf('red');
// var n = 0;
// while (index !== -1) {
// console.log(index);
// n++;
// index = color.indexOf('red', index + 1);
// }
// console.log('red出现的次数是:' + n);
// //根据索引号返回字符
// var str = 'pink';
// console.log(str.charAt(2));
// //遍历所有字符
// for (var i = 0; i < str.length; i++) {
// console.log(str.charAt(i));
// }
// //返回根据索引号返回字符的ASCII码
// console.log(str.charCodeAt(2));
// //获取索引号位置处字符 HTML5,IE8 + 支持 同charAt
// console.log(str[2]);
//统计出现最多的字符和次数
// var str = 'abskbdaadsf';
// var obj = {};
// for (var i = 0; i < str.length; i++) {
// var ss = str.charAt(i);
// if (obj[ss]) {
// obj[ss]++;
// } else {
// obj[ss] = 1;
// }
// }
// console.log(obj);
//console.log(obj);
//这里有一个关键点:
//首先两种添加属性的方法
// obj.属性名 = "属性值";
// obj['属性名'] = "属性值";
//下列是第二种写法,大同小异:
// var str = 'abskbdaadsf';
// var obj = {};
// for (var i = 0; i < str.length; i++) {
// var ss = str.charAt(i);
// if (obj[str.charAt(i)]) {
// obj[str.charAt(i)]++;
// } else {
// obj[str.charAt(i)] = 1;
// }
// }
// console.log(obj);
// console.log(obj[ss]); //1
// console.log(obj['ss']); //undefined
// console.log(obj.ss); //undefined
// 这里主要看下面三者的区别,三种都是输出属性值,但写法不同,使用也截然不同
// console.log(obj[ss]); 这里的ss是变量名,先返回他的值作为obj的属性值
// console.log(obj['ss']); 这里的ss是属性名,本身是变量也会直接将ss作为obj的属性值,不会考虑其变量值
// console.log(obj.ss); 这里ss也是直接属性名,不会考虑其是否为变量
// 因此,在利用属性名求其属性值时,
// 1.确定属性名时用上面三种均可;
// 2.当属性名是包含函数公式时,先赋值给变量,然后将变量使用obj[变量]
// 其他方法比如直接将表达式代入行不通,此时会把表达式当做直接属性名
遍历对象
//遍历对象
// var max = 0;
// var ch = '';
// for (var k in obj) {
// //k得到的是属性名
// //obj[k]得到的是属性值
// if (obj[k] > max) {
// max = obj[k];
// ch = k;
// }
// }
// console.log(max);
// console.log('最多的字符是' + ch);
// 字符串操作
// 字符串拼接
// concat(str1,str2,str3); +更常用
// 字符串截取
// str.substr('截取起始位置(包括起点)索引号','截取几个字符');
// 字符串替换
// var str='aeiou';
// console.log(str.replace('a','b')); //将a替换为b,替换一个后停止
// 替换多个
// var str1='asfghff';
// while(str1.indexOf('f')!==-1){
// str1=str1.replace('f','*');
// }
// console.log(str1);
// split字符转换为数组 join数组转换为字符串
// var str2='red,pink,blue';
// console.log(str2.split(',')); //逗号为分隔符,字符串必须有分隔符才能转换
// 转换大小写
// toUpperCase() //转换大写
// toLowerCase() //转换小写
// 简单类型和复杂类型
// 简单类型又叫基本数据类型或值类型,
// string,number,boolean,undefined,null null返回的是一个空对象object
// 复杂类型又叫引用类型
// Object,Array,Date
// 栈 类似于数据结构栈,存放简单数据类型
// 堆 存放复杂数据类型
// 数据传参是重点,具体见pink老师js基础语法最后一节内容,赞!