JavaScript核心语法-EcmaScript
一. 表达式
- 表达式由运算符、操作数组成,会有一个表达式结果。
- 表达式可以放置在任何位置,可以是函数调用表达式等。
- 操作数的个数决定运算符的元数。
1. 变量未声明,进行变量的操作:输出、运算,会发生ReferenceError错误。
console.log(34 + val);//Uncaught ReferenceError: val is not defined
// 特殊情况
console.log(typeof val);//undefined,不推荐此操作
2. 数值与字符串比较、数值与布尔值比较、字符串与布尔值比较
- 比较大小的本质:数值比较
- 数值型数据比较,重点在于两个浮点数相等比较。(两个浮点数的差小于等于浮点数误差值)
- 字符串比较的是字符的UNICODE编码值。
- 字符串与数值比较:字符串转换为数值型数据,再进行比较。若是字符串不能转换为数值,则为NaN,比较结果始终为false。(NaN不能与任何值比较,包括其本身)。
- 字符串与布尔值比较:字符串转换为数值型数据,布尔值转换为数值型数据,再进行比较。若是字符串不能转换为数值,则为NaN,比较结果始终为false。
- 数值与布尔值比较:布尔值转换为数值型数据,再进行比较。
- 字符串与字符串比较:逐个比较字符串中字符的UNICODE编码值。
二. 语句
- 对于多分支条件结构,特别注意其隐含的条件。
- 对于switch语句,比较的是全等,只能作相等判断,不能做范围判断。
三. 代码调试(debug)技巧
- 代码调试的目的:
- 定位错误的原因和位置,并解决错误。
- 错误:
- 语法错误(一般会报错);
- 逻辑错误(一般不报错);
- 以前调试JS方式:
- alert();//不推荐
- console.log();
- 断点调试:
- Chrome Google调试JS代码,F12(开发者工具)–>Sources(选择要调试的文件)–> 打断点。
- 代码执行到断点处停止。
- 注意Watch中变量值的变化。
四. 冒泡排序
// 方式一:
原数组: 23, 45, 34, 0, 23, 12, 0, 67, 34, 0, 17 一共11个数
第一次结果: 23, 34, 0, 23, 12, 0, 45, 34, 0, 17, 67 确定1个数,内部比较次数10次
第二次结果: 23, 0, 23, 12, 0, 34, 34, 0, 17, 34, 67 确定2个数,内部比较次数9次
第三次结果: 0, 23, 12, 0, 23, 34, 0, 17, 34, 34, 67 确定3个数,内部比较次数8次
第四次结果: 0, 12, 0 ,23, 23, 0, 17, 34, 34, 34, 67 确定4个数,内部比较次数7次
第五次结果: 0, 0, 12, 23, 0, 17, 23, 34, 34, 34, 67 确定5个数,内部比较次数6次
第六次结果: 0, 0, 12, 0, 17, 23, 23, 34, 34, 34, 67 确定6个数,内部比较次数5次
第七次结果: 0, 0, 0, 12, 17, 23, 23, 34, 34, 34, 67 确定7个数,内部比较次数4次
第八次结果: 0, 0, 0, 12, 17, 23, 23, 34, 34, 34, 67 内部比较次数3次,验证数据是否排序完:数据无任何交换
结论: 数据最多进行: 数组.length - 1轮排序。
// 方式二:
原数组: 23, 45, 34, 0, 23, 12, 0, 67, 34, 0, 17 一共11个数
i = 0; j = i + 1;
冒泡排序优化
- 如何判断数据排序完成?
- 数据不再交换。
// 方式一:推荐,效率高
var nums = [23, 45, 34, 0, 23, 12, 0, 67, 34, 0, 17];//原数据
function sort(arr){
var temp;//数据交换中间值
var isSort;
var count = 0;
console.time('start');//计时开始
for(var i = 0, len = arr.length - 1; i < len; i++){
count++;
isSort = true;//检测每轮排序是否完成
for(var j = 0; j < len-i; j++){
count++;
if(arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
isSort = false;
}
}
if(isSort){
break;
}
}
console.timeEnd('start');//计时结束,并输出
console.log(count);
return arr;
}
// 方式二
var nums = [23, 45, 34, 0, 23, 12, 0, 67, 34, 0, 17];//原数据
function sort(arr) {
console.time('start'); //计时开始
var temp; //交换数据的第三者
var flag; //排序完成标识
var count = 0
for (var i = 0, len = arr.length; i < len; i++) {
flag = true;
count++;
for (var j = i + 1; j < len; j++) {
count++;
if (arr[i] > arr[j]) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
flag = false;
}
}
if (flag) {
break;
}
}
console.timeEnd('start'); //计时结束,并输出
console.log(count);
return arr;
}
五. 逻辑题
1. 输入某年某月某日,判断这一天是这一年的第几天?
实现方式一:switch
// 判断是否闰年,闰年2月29天,平年2月28天
function isLeapYear(year){
return (year % 4 === 0 && year % 100 !== 0)||(year % 400 === 0);
}
function getDays(year,month,day){
var days = day;
for(var i = 1; i < month; i++){
switch (i) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
days += 31;
break;
case 4:
case 6:
case 9:
case 11:
days += 30;
break;
case 2:
if (isLeapYear(year)) {
days += 29;
} else {
days += 28;
}
break;
}
}
return days;
}
实现方式二:数组
// 判断是否闰年,闰年2月29天,平年2月28天
function isLeapYear(year){
return (year % 4 === 0 && year % 100 !== 0)||(year % 400 === 0);
}
function getDays(year, month, day) {
var days = day; //当前月天数
var arrDays = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; //闰年每月
for (var i = 0, len = month - 1; i < len; i++) {
if (i == 1) {//2月天数处理
arrDays[i] = isLeapYear(year) ? 29 : 28;
}
days += arrDays[i];
}
return days;
}
六. JavaScript代码执行过程
- JavaScript代码的执行是由浏览器中的JavaScript解析器(引擎)来执行的。
- JavaScript解析器执行JavaScript代码分为两个过程:
- 预解析过程;
- 代码执行过程;
预解析过程:
- 把变量的声明提升到当前作用域的最前面,只提升变量声明,不提升变量赋值。
- 把函数的声明提升到当前作用域的最前面,只提升函数声明,不提升函数表达式和函数调用。
- 先提升变量声明,再提升函数声明。
七. 对象成员遍历和删除
- for…in,可以遍历对象或其原型中的可枚举成员。
- delete,可以删除对象或原型中的可配置成员。
- in, 检测对象或其原型中是否存在某个属性。
八. 基本数据类型和引用数据类型
- 基本数据类型:number、string、boolean、null、undefined;
- 引用数据类型:Object;
- JavaScript中没有堆栈概念,使用堆栈概念,便于理解JavaScript程序。
- 栈内存:由操作系统分配和释放,存储基本数据类型数据,引用数据类型地址。
- 堆内存:由程序员开辟堆内存空间,程序员未手工释放,则由垃圾回收器回收并释放。存储引用数据类型数据。
1. 基本数据类型
- 基本数据类型,变量存储值本身,存储在栈内存中。
- 基本数据类型复制的是值本身。
var n1 = 10;
var n2 = n1;//复制n1值
n1 = 20;
简单数据类型存储-示意图:
var x = 10;
var y = 20;
add(x, y);
function add(a, b){
a = a + 10;
b = b + 20;
}
简单数据类型作为函数参数:
2. 引用数据类型
- 引用数据类型,变量存储引用数据类型的地址,存储在栈内存中。
- 堆内存中存储引用数据类型的数据。
- 复制的是引用数据类型的地址。
- 栈内存与堆内存是一对一或多对一的关系。
function Person(name, age){
this.name = name;
this.age = age;
this.sayHi = function(){};
}
var per = new Person('ls', 20);
var son = per;
引用数据类型存储-示意图:
function Person(name, age){
this.name = name;
this.age = age;
this.sayHi = function(){};
}
var per = new Person('ls', 20);
function test(obj){
obj.name = 'zs';
}
test(per);
引用数据类型作为函数参数:
九. 内置对象
1. Math对象
随机生成[min,max]间的整数:
function getIntRandom(min, max){
return Math.ceil(Math.random()*(max-min)+min);
}
// 附加:生成[0,255]之间的RGB颜色值
function randomRGB(min, max){
var colorValues = new Array(3);
for(var i = 0, len = colorValues.length; i < len; i++){
colorValues[i] = getIntRandom(min,max);
}
return 'rgb('+colorValues[0]+','+colorValues[1]+','+colorValues[2]+')';
}
2. Date对象
- 两个日期时间对象可以相减,实际上是各自日期时间对象调用了valueOf()方法,转换为时间戳相减。
3. Array对象
sort方法
- sort方法,默认情况下(无参数)是按照ASCII码值进行排序。先将数组中的元素转换为字符串(toString()),然后按照ASCII码值排序。
- 排序规则:compareFunction,返回大于0,等于0,小于0。
// 若排序的是数值型数据,排序规则(按照从小到大排序:a-b,按照从大到小排序:b-a)
function compareFunction(a, b){
return a - b;
}
// 若排序的是字符串型数据,排序规则(按照ASCII进行排序,大写字母:65~90,小写字母:97~122)
function compareFunction(a, b){
// 不区分大小写排序
var a = a.toUpperCase();
var b = b.toUpperCase();
if(a < b){
return -1;
}
if(a > b){
return 1;
}
return 0;
}
// 模拟sort方法内部实现
function sort(arr, compareFunction) {
var temp; //中间值,负责交换数据
var flag; //检测是否排序完成
for (var i = 0, len = arr.length - 1; i < len; i++) {
flag = true;
for (var j = 0; j < len - i; j++) {
if (compareFunction(arr[j], arr[j + 1]) > 0) { //arr[j] > arr[j+1],控制排序规则
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = false;
}
}
if (flag) {
break;
}
}
return arr;
}
// 模拟join方法
function join(arr, separator) {
//参数处理
var arr = arr || [];
var separator = separator?',':separator;
var len = arr.length;
if (len === 0) {
return '';
}
var str = arr[0];
for (var i = 1; i < len; i++) {
str += separator + arr[i];
}
return str;
}
// 模拟reverse方法
function reverse(arr) {
if (!(arr instanceof Array)) {
throw new TypeError('not a define or not a array');
}
var temp; //中间值,用于交换数据
var lastIndex = arr.length - 1; //最后一个元素的索引值
for (var i = 0, len = parseInt(arr.length / 2); i < len; i++) {
temp = arr[i];
arr[i] = arr[lastIndex];
arr[lastIndex--] = temp;
}
return arr;
}
// 数组去重:保留前者,删除后者
function clearRepeat(arr) {
for (var i = 0, len = arr.length-1; i < len; i++) {
for (var j = i + 1; j < len; j++, len = arr.length) { //实时更新len,数组长度
if (arr[i] === arr[j]) {
arr.splice(j, 1);
j--;
}
}
}
return arr;
}
4. 字符串
- 字符串不可变。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yfzXswNW-1583755385034)(images/string.png)]
- 当大量拼接字符串的时候,会有性能问题。(不推荐字符串的大量拼接)
- 字符串的所有方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串。
十. 函数
- 函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。
- 函数是一个特殊的对象,但对象都是通过函数创建的。
- 函数的数据类型始终是:function。
- 函数创建的方式:
// 函数创建:
var func = new Function('代码');
func();//函数调用
console.log(typeof func);//function,函数的类型永远是function
console.log();
// 创建有参函数:
var func = new Function('a, b, c', 'console.log(a+b+c);');
func(1,2,3);//调用函数
// 函数声明-在JavaScript预解析过程会提升
function methodName(){
// 函数体内代码
}
// 函数表达式声明
var methodName = function (){
// 函数体内代码
}