JS与ECM的关系
JS基础
JS编写位置
-
<script>JS代码</script>标签内
-
<script src=”外部JS文件路径”></script>外部引入JS文件
-
<a href=”javascript:console.log(‘Test’)”>超链接</a>不推荐使用HTML标签中写入
字面量 变量 标识符
概述
字面量:不可改变的值,比如:1 2 3 “String”
变量:变量可以用来保存字面量
标识符:在JS中所有可以由我们自主命名的,比如:变量名、函数名、属性名。
字面量
数据类型
在JS中一共有六种数据类型
-
String 字符串
-
Number 数值
-
Boolean 布尔值
-
Null 空值
-
Undefined 未定义
-
Object 对象
前五种属于基本数据类型、Object属于引用数据类型。
String
/转移字符可以输出关键字本身
var a = "//";
Number
JS中所有的数值都是Number类型包括整数和浮点数
如果出现下列这种情况,可以使用typeof
判断类型
var a ="123";
var b = 123.01;
console.log(a);
console.log(b);
console.log(typeof a);
console.log(typeof b);
// 控制台
123
123.01
string
number
Number有值范围,如果超过的最大值就显示Infinity表示正无穷
console.log(Number.MAX_VALUE * Number.MAX_VALUE);
// 控制台
Infinity
使用非Number运算会显示NAN(Not a Number)但是类型仍然属于Number
var a = "abc" * "def";
console.log(a);
console.log(typeof a);
// 控制台
NaN
number
如果使用JS进行浮点运算,可能得到一个不准确的结果,虽然其它语言也有这个问题但是都有解决办法,而JS不好解决,所以尽量不要使用JS进行对精确度要求比较高的运算
Boolean
Boolean只有两个值:true,false
var a = true;
console.log(a)
console.log(typeof a)
// 控制台
true
boolean
Null
Null类型的值只有一个,就null,null这个值专门用来表示一个为空的对象。使用typeof返回类型为Object
Undefined
当变量没有初始化时为undefined
var a;
console.log(a);
console.log(typeof a);
// 控制台
undefined
undefined
强制类型转化
其它的数据类型转换为String
调用被转换数据类型的toString()方法或者使用String()函数,该方法不会影响到原变量,它会将转换的结果返回。
var num = 123;
console.log(num)
console.log(typeof num);
console.log(num.toString())
console.log(typeof num.toString())
var num = 123;
console.log(num)
console.log(typeof num);
num = String(num);
console.log(num)
console.log(typeof num);
// 控制台
123
number
123
string
这两方法不同的地方在于Null和Undefined不能调用toString()方法转化但是String()方法可以
var a = null;
console.log(a.toString());
console.log(typeof a);
var b = undefined;
console.log(b.toString());
console.log(typeof b);
// 控制台
Uncaught TypeError: Cannot read properties of null (reading 'toString')
var c = null;
c = String(c);
console.log(c);
console.log(typeof c);
var d = undefined;
d = String(d);
console.log(d);
console.log(typeof d);
// 控制台
null
string
undefined
string
将其它数据类型转换为Number
使用Number()函数
-
String类型转换:如果字符串为数字那么就可以正常转换(空字符串或全为空格·转换为0),如果为非数字那么就转换为NaN
-
Boolean类型转换:true为1,false为0
-
Null类型转换:0
-
undefined转换为NaN
var a = "123";
console.log(a);
console.log(typeof a);
a = Number(a);
console.log(a);
console.log(typeof a);
// 控制台
123.01
string
123.01
number
var a = "abc";
a = Number(a);
console.log(a);
console.log(typeof a);
// 控制台
NaN
number
var a = " ";
a = Number(a);
console.log(a);
console.log(typeof a);
// 控制台
0
number
该方法只针对String
如果对非String使用pareInt()或parseFloat()它会先将其转换为String
-
parseInt()函数 可以将一个字符串中第一个非数字之前整数内容提起出来转换为Number
var a = "123a456px";
a = parseInt(a);
console.log(a);
console.log(typeof a);
// 控制台
123
number
var a = "a123bc";
a = parseInt(a);
console.log(a);
console.log(typeof a);
// 控制台
NaN
number -
parseFloat()函数转换为浮点数
var a = "12.01.1px";
a = parseInt(a);
console.log(a);
console.log(typeof a);
// 控制台
12.01
number
其它进制的数字
<!--如果要表示16进制的数字,则需要以0x开头-->
var a = 0x10;
console.log(a);
<!--如果要表示8进制的数字,则需要以0o开头-->
a = 0o10;
console.log(a);
<!--如果要表示2进制的数字,则需要以0b开头-->
a = 0b10;
console.log(a);
// 浏览器根据不同的版本转换的结果也不同
其他数据类型转换为Boolean
-
Number类型,0、NaN为false,非0、Infinity、Undefined为true
-
String类型,非空串为true
-
Null和Undefined为false
var a = 11;
console.log(a);
console.log(typeof a);
a = Boolean(a);
console.log(a);
console.log(typeof a);
// 控制台
11
number
true
boolean
操作符
算数运算符
运算符也叫操作符,通过运算符可以对一个或多个值进行运算,并获取运算结果
+ String>Number>(Boolean,Null,Undefined)按照以上优先级运算,字符串+视为拼接操作运算顺序:从左往右
–
*
/ 不同于Java整除JS中/符合人类规则
%
除了+特殊其余都是转换为Number再进行计算
一元运算符
typeof 获得一个值的类型并且以字符串的形式返回
+ 正号
– 负号
对于非Number类型的值会将其转换为Number然后运算
自增和自减
++
—
逻辑运算符
其它数据类型转换为Boolean再进行运算
!
&&
||
输出Unicode编码表中字符
/u四位Unicode编码
相等运算符
除了个别用例基本保持 转换为Number再比较
NaN和任何值都不相等,所以只能使用isNaN()函数来判断是否为NaN
console.log(undefined == null); // true
console.log(0 == null); // false
===全等不会做类型转换
!==
对象 Object
对象的分类
-
内建对象:
-
由ES标准中定义的对象,在任何的ES实现中都可以使用 比如:Math、String、Number、Boolean
-
-
宿主对象:
-
由JS的运行环境提供的对象,目前来讲主要指由浏览器浏览器提供的对象 比如:BOM DOM
-
-
自定义对象:
-
由开发人员自定义
var obj = new Object();
// 在对象中保存属性 语法:对象.属性名 = 属性值
obj.name = "ccy";
obj.age = 22;
obj.gender = "男";
// 删除对象属性
delete obj.name;
// 如果要使用特殊的属性名,需要使用另一种方式 语法:对象["属性名"] = 属性值
obj["123"] = 789;
// []中也可以放入变量!!!
var n = "123";
console.log(obj[n]); // 789对象的属性不仅可以包含基本数据类型而且还包括对象本身
var obj1 = new Object();
var obj2 = new Object();
obj1.name = "ccy";
obj1.age = 22;
obj2.country = "中国";
obj2.address = "山西";
obj1.info = obj2;
/**
* in运算符
* - 通过该运算符可以检查该对象中是否含有指定属性,返回类型为Boolean
* - 语法:"属性名" in 对象
*/
console.log("info" in obj1);
console.log("test" in obj1);除了
var ojb = new Object()
构造方法创建对象以外还有一种声明方式使用方便var obj = {
name: "ccy",
age: 22,
isStudent: true
};
console.log(obj); -
方法
对象的属性可以是任意数据类型,所以也包括函数,当函数作为对象属性时又称作:方法
var obj = {
name: "ccy",
age: 22,
gender: "男"
};
function fun() {
console.log(obj.name);
};
obj.info = fun;
obj.info();
// 控制台
ccy
枚举对象属性
var obj = {
name: "ccy",
age: 22,
gender: "男",
};
for (var n in obj) {
// 这句代码的含义是得到obj属性n的属性值
// console.log(obj.n);
// 对象[变量] 的一个好处就是可以放变量
console.log(n);
console.log(obj[n]);
}
函数 Function
创建函数
函数属于对象具有对象的功能
使用构造方法创建函数
// 可以将封装的代码以字符串的形式传递给构造函数
var fun = new Function("console.log('我是Ccy');");
console.log(typeof fun); // function 也属于 object
// 封装到函数中的代码不会立即执行,当调用函数时执行 语法:函数名()
fun();
fun();
使用声明方式创建函数
function fun(a, b) {
return a > b ? a : b;
}
console.log(fun(2, 4));
使用函数表达式来创建函数
var fun = function (a, b) {
return a > b ? a : b;
}
参数
-
调用函数时解析器不会检查实参的类型,所以要注意,可能会接受到非法的参数
-
调用函数时解析器不会检查实参的数量,多余的实参不会被赋值
var fun = function (a, b) {
console.log(a + b);
}
// 不会检查实参类型
fun(123, 456); // 579
fun("123", 456); // 123456
fun(true, false); // 1
// 不会检查实参的数量
fun(123, 456, "789", true); // 579
fun(123); // NaN 如果实参数量少于形参的数量,那么没有对应实参的形参数据类型为undefined
-
对象和函数都可以作为实参传入
function info(obj) {
console.log("My Name is " + obj.name +
".Tody,i am " + obj.age + " years old");
}
var obj = {
name : "ccy",
age : 22
};
info(obj);
function outer(a) {
console.log("我是outer " + a);
};
function inner(a) {
console.log("我是inner " + a);
return "zfs";
};
/**
* inner 属于函数对象,相当于直接使用函数对象
* inner() 属于调用函数,相当于使用函数的返回值
*/
outer(inner);
outer(inner("ccy"));
// 控制台
我是outer function inner(a) {
console.log("我是inner " + a);
return "zfs";
}
我是inner ccy
我是outer zfs
立即执行函数
声明匿名函数是不被允许的因为毫无意义,所以需要将匿名函数用()包裹起来看做整体随后调用
/**
* 立即执行函数:
* 1. 函数定义完就可以立即执行
* 2. 立即执行函数只能执行一次
*/
(function (a, b) {
console.log("a = " + a);
console.log("b = " + b);
})(2, 3);
作用域
作用域是指变量作用的范围
在JS中一共有两种作用域:全局作用域,函数作用域
在函数作用域中有声明前提的特征:
-
使用var关键字声明的变量,会在函数中所有代码执行之前被声明
console.log(a);
var a = 10;
// 控制台
undefined
console.log(a);
a = 10;
// 控制台
Uncaught ReferenceError: a is not defined
-
函数声明也会在代码执行之前执行,函数表达式则不会
fun1();
fun2();
function fun1() {
console.log("fun1");
};
var fun2 = function () {
console.log("fun2");
};
// 控制台
fun1
Uncaught TypeError: fun2 is not a function
全局作用域
-
直接编写在<script>标签中的JS代码,都是在全局作用域中
-
全局作用域在页面打开时创建,在页面关闭时销毁
-
在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口
-
在全局作用域中,创建的变量都会作为window对象的属性保存,创建的函数都会作为方法保存
函数作用域
-
调用函数时创建函数作用域,函数执行完毕后函数作用域销毁
-
每调用一次函数就会创建一个新的函数作用域,函数作用域之间相互独立
-
在函数作用域中可以访问到全局作用域
-
当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果自身作用域找不到会到上一级寻找。在函数中不使用var声明的变量都会成为全局变量
var a = 123;
function fun() {
var a = 567;
console.log(a);
}
window.fun();
this
/**
* 解析器在调用函数每次都会向函数内部传递一个隐含参数
* 这个隐含的参数就是this,this指向的是一个对象
* 这个对象我们称为函数执行的上下文对象,根据函数调用方式的不同,this会指向不同的对象
* 1. 以函数的形式调用时,this为window
* 2. 以方法的形式调用时,this为调用方法的Object
* 3. 以构造函数调用时,this为实例
* 4. 使用call()和apply调用时,this是传入对象
*/
function fun() {
console.log(this);
};
fun();
// 创建对象
var obj = {
name: "ccy",
age: 22,
sayThis: fun
};
obj.sayThis();
call()和apply()
function fun(a, b) {
console.log(this);
console.log(this.name);
console.log("a = " + a);
console.log("b = " + b);
};
var obj1 = {
name: "ccy"
};
var obj12 = {
name: "zfs"
};
/**
* 当函数调用call()和apply()都会执行函数
* 在调用这两个方法时可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时this
* call()方法可以将实参在对象之后传递
* apply()方法需要将实参封装到一个数组中统一传递
*/
fun.call(obj1, 2, 3);
fun.apply(obj12, [2, 3]);
arguments
/**
* 在调用函数时,浏览器每次都会传递两个隐含的参数
* 1. 函数上下文对象 this
* 2. 封装实参的对象 arguments
* - arguments是"类数组"对象,可以通过索引操作数据也可以获取长度(arguments.length)
* - 传入函数的实参都会保留在arguments
* - 即使不定义形参,也可以通过arguments使用传入实参(不推荐使用)
* - arguments.callee对应函数对象本身
*/
function fun() {
console.log(arguments.length);
console.log("a = " + arguments[0]);
console.log("b = " + arguments[1]);
console.log(arguments.callee); // fun
};
fun(1, 2);
构造函数
/**
* 因为所有的对象的数据类型都是Object所以为了区分创建构造函数
* 构造函数就是普通函数,创建方式和普通函数没有区别,唯一的不同在于构造函数的函数名习惯上首字母大写
*
* 构造函数和普通函数的区别就是调用方式不能,普通函数是直接调用,而构造函数需要使用new关键字来调用
*
* 构造函数的执行流程
* 1. 立刻创建一个新对象
* 2. 将新建对象设置为函数中的this
* 3. 逐行执行函数代码
* 4. 将新建对象作为返回值返回
*/
function Person() {
this.name = "ccy";
this.age = 22;
this.address = "山西省";
};
function Dog() {
this.name = "柯基";
this.age = 4;
this.operation = "吃骨头";
};
var person = new Person();
var dog = new Dog();
console.log(person);
console.log(dog);
/**
* instanceof检查一个对象是否是一个类的实例
* 语法: 对象 instanceof 构造函数
* 如果是则返回true否则返回false
*/
console.log(person instanceof Person);
console.log(dog instanceof Dog);
// 控制台
true
true
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function () {
console.log("this.name = " + this.name);
}
};
var person1 = new Person("ccy", 22);
var person2 = new Person("zfs", 18);
/**
* 构造函数内部创建方法,每调用一次构造函数就会创建一个新的sayName方法,也就是说所有实例的sayName方法都是唯一的
* 但是这完全没必要,完全可以使所有对象共享一个方法
*/
console.log(person1.sayName == person2.sayName); // false
为了使得实例方法不必要的创建,对构造方法做出改良。但此方法的弊端就是将函数定义在全局作用域中,污染了全局作用域的命名空间。而且定义在全局作用域中不安全。
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = fun
};
function fun() {
console.log("this.name = " + this.name);
};
var person1 = new Person("ccy", 22);
var person2 = new Person("zfs", 18);
console.log(person1.sayName == person2.sayName); // true
原型对象
以后创建构造函数时,可以将这些对象共有的属性和方法统一添加到构造函数的原型对象中
/**
* 我们所创建的每一个函数,解析器都会向解析其中添加一个属性:prototype(原型对象)
* 当函数作为普通函数调用prototype没有任何作用
* 当函数作为构造函数调用,它所创建的对象中都会含有一个属性指向该构造函数的原型对象,我们可以通过__proto__来访问
*/
function Person() {
};
console.log("prototype" in Person); // true
var person = new Person();
console.log(Person.prototype);
console.log(person.__proto__);
/**
* 原型对象就相当于一个公共区域,所有同类的实例都可以访问到这个原型对象,可以将对象中共有的内容统一设置到原型对象中
*/
Person.prototype.a = "ccy";
console.log(person.a);
function Person() {
};
Person.prototype.name = "ccy";
var person = new Person();
// 使用in检查对象中是否含有某个属性时,如果对象中没有但是原型对象中有则也会返回true
console.log("name" in person); // true
// 使用hasOwnProperty()检查对象自身是否含有该属性
console.log(person.hasOwnProperty("name")); // false
原型对象也是对象,所以它也有原型对象,当我们使用一个对象的属性或方法时会先在自身中寻找。
自身中如果有则直接使用。
如果自身中没有则回去原型对象中寻找,如果原型对象中也没有则会去原型对象的原型对象中寻找,此时若还没有找到则返回undefined
toString()
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.age = gender;
};
var person = new Person("ccy", 22, "男");
console.log(person.toString()); // [object Object]
console.log(person.__proto__.__proto__.hasOwnProperty("toString")); // true
数组
构造数组一共有三种方法
// 1. 构造函数数组
var array1 = new Array();
// 2. 构造函数数组,构造数组长度为10的数组
var array2 = new Array(10);
// 3. 声明数组
var array3 = [1, 2, 3, 4, "ccy", 6];
创建数组的方式
// 构造方法创建数组对象
var array = new Array();
// 向数组中添加元素 语法:数组[索引] = 值
array[0] = 10;
array[1] = 20;
array[2] = 20;
// 非连续数组
array[5] = 50;
// 读取数组中元素 语法:数组[索引]
console.log(array[1]); // 20
/**
* 对于连续的数组,使用length设置或返回数组中元素的数量
* 对于非连续的数组,使用length返回数组最大索引值+1
*/
console.log(array.length); // 6
如果修改length大于原长度,多余的索引位置会空出
如果修改length小于原长度,多余的索引位置会删除
var array = new Array();
array[0] = 10;
array[1] = 20;
array[2] = 20;
array.length = 10;
console.log(array);
array.length = 1;
console.log(array);
数组的增删方法
push()
该方法向数组的末尾添加一个或多个元素,并返回数组的新长度
var array = new Array();
console.log(array.push(1, 2, 3, 4, 5, 6, 7)); // 7
console.log(array); // [1, 2, 3, 4, 5, 6, 7]
pop()
该方法可以删除数组的末尾元素,并将删除元素返回
var array = [1, 2, 3, 4, 5, 6];
console.log(array);
console.log(array.pop());
console.log(array);
unshift()
该方法向数组的开头添加一个或多个元素,并返回数组的新长度
var array = new Array();
array.unshift(1, 2, 3);
array.unshift(4, 5, 6);
console.log(array); // [4, 5, 6, 1, 2, 3]
shift()
该方法可以删除数组的开头元素,并将删除元素返回
var array = [1, 2, 3, 4, 5];
console.log(array.shift()); // 1
console.log(array); // [2, 3, 4, 5]
遍历数组
一般我们都是使用for循环遍历数组,JS中还为我们提供了一个方法用来遍历数组
foreach()
var array = [1, 2, 3, 4, 5];
/**
*
* @param value 当前遍历元素
* @param index 当前遍历元素索引
* @param array1 数组
*/
array.forEach(function (value, index, array1) {
})
数组其它方法
slice()
从某数组中返回选定的元素并以数组的形式返回,可以用于得到指定范围的数组元素
var array = [1, 2, 3, 4, 5];
/**
* 该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回和java中的split相似
* @param 起始位置
* @param 结束位置
*/
var result = array.slice(0, 2);
console.log(array); // [1, 2, 3, 4, 5]
console.log(result); // [1, 2]
splice()
不同于slice()的是该方法会改变原数组,可以用于删除指定范围数组中元素,还可以替换被删除元素
var array = [1, 2, 3, 4, 5];
/**
* 该方法会改变元素数组,而是将截取到的元素封装到一个新数组中返回
* @param 起始位置
* @param 删除数量
* @param 替换元素们!
*/
var result = array.splice(1, 1, 0, 0, 0);
console.log(array); // [1, 0, 0, 0, 3, 4, 5]
console.log(result); // [2]
concat()
可以连接两个或多个数组,并将新的数组返回,该方法不会对原数组产生影响
var array1 = [1, 2, 3, 4, 5];
var array2 = [6, 7, 8, 9, 10];
var array3 = [11, 12, 13, 14, 15];
var numbers = array1.concat(array2, array3, 16, 17);
console.log(numbers) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
join()
将数组中所有元素放入放入一个字符串。元素通过指定的分隔符进行分割,默认分隔符为”,”
var array1 = [1, 2, 3, 4, 5];
var s = array1.join(",");
console.log(s); // 1,2,3,4,5
reverse()
改变原数组,反转数组
var array1 = [1, 2, 3, 4, 5];
var array2 = array1.reverse();
console.log(array1); // [5, 4, 3, 2, 1]
console.log(array2); // [5, 4, 3, 2, 1]
sort()
改变原数组,默认按升序排序,可以自定义排序规则
var array1 = [1, 4, 2, 3, 7, 6, 5];
var array2 = array1.sort();
console.log(array1); // [1, 2, 3, 4, 5, 6, 7]
console.log(array2); // [1, 2, 3, 4, 5, 6, 7]
var array1 = [1, 4, 2, 3, 7, 6, 5];
/**
* 添加回调函数,自定义排序规则
* 浏览器会根据回调函数的返回值来决定元素的顺序,如果返回一个大于0的值,元素会交换位置
* @param 索引值较大元素
* @param 索引值较小元素
*/
array1.sort(function (a, b) {
return b - a;
});
console.log(array1); // [7, 6, 5, 4, 3, 2, 1]
Date
// 使用构造函数创建Date对象,则表示执行这行代码的时间
var date1 = new Date();
console.log(date1);
// 使用构造函数传递参数创建指定时间
// 日期格式:月/日/年 时:分:秒
var date2 = new Date("3/25/2001 22:30:18");
console.log(date2);
// getDate():获得一个月中的某一天
var date = date1.getDate();
console.log(date);
// getDay():获得一周中的某一天 (星期日-星期六):(0-6)
var day = date1.getDay();
console.log(day);
// getMonth():获取月份 (一月-十二月):(0-11)
var month = date1.getMonth();
console.log(month);
// getTime():获取格林威治时间(我们位于东八区和此有8小时时差)1970年1月1日 0时0分0秒到当前日期所花费的毫秒数
var time = date1.getTime();
console.log(time);
// 获取当前时间戳
console.log(Date.now());
Math
// Math:Math和其他对象不同,他不是一个构造函数
console.log(typeof Math); // object
// abs() 绝对值
console.log(Math.abs(-1)) // 1
// ceil() 向上取整
console.log(Math.ceil(1.5)) // 2
// floor() 向下取整
console.log(Math.floor(1.5)) // 1
// round() 四舍五入
console.log(Math.round(1.4)) // 1
// random() 获取(0,1)之间的随机数
console.log(Math.random())
// 获取[1,10]之间的随机数
console.log(Math.ceil(Math.random() * 9) + 1);
包装类
基本数据类型 String Number Boolean Null Undefined不是对象功能没有那么强大,我们知道基本数据类型不能够像对象一样拥有属性和方法但是在调用基本数据类型时为什么会有原生属性和方法呢?
var str = "zfs ccy";
str.name = "ss"
console.log(str.name); // undefined
重点讲解String
var str = "ccy zfs";
// charAt() 返回索引位置的字符
var char = str.charAt(2);
console.log(char);
// charCodeAt() 返回索引位置的字符的Unicode编码
var code = str.charCodeAt(2);
console.log(code);
// fromCharCode() 返回Unicode编码的字符
char = String.fromCharCode(65);
console.log(char);
// indexOf() 返回检索字符首次(默认第二个参数为0,可以选择)出现的索引值,如果没有检索到指定字符那么就返回-1
var flag = str.indexOf("c", 1); // 1
console.log(flag);
// split() 将字符串拆分为数组
var array = str.split(" ");
array.forEach(function (value) {
console.log(value);
});
正则表达式
创建正则表达式
/**
* 构造方法创建正则表达式 new RegExp("正则表达式","匹配模式");
* 匹配模式:i 忽略大小写 g 全局匹配
*/
var reg = new RegExp("a");
var str = "a";
var flag = reg.test(str);
console.log(flag); // true
/**
* 使用字面量来创建正则表达式 /正则表达式/匹配模式
*/
var reg = /a/;
原创文章,作者:wdmbts,如若转载,请注明出处:https://blog.ytso.com/273091.html