什么是javascript
JavaScript是一种运行在客户端的脚本语言(最开始,后来也可以运行在服务器端);不需要编译,运行过程中由js解释器逐个进行解释并执行。浏览器是JavaScript的前端运行环境,DOM及BOM是浏览器提供的api模块。
浏览器执行javascript的方式
浏览器分为两部分:渲染引擎和js引擎
- 渲染引擎:用来解析Html和css,即为内核,比如:chrome浏览器的blink,老版本的webkit
- js引擎:js解释器,用来读取网页中的js代码,对其处理后运行,比如:chrome V8引擎。引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以js语言归为脚本语言,会逐行解释执行
什么是ECMAScript
ECMAScript:JavaScript的语法
- Javascript(网景公司)和jscript(微软公司)是ecmascript的实现和扩展
- 规定了js的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套js语法工业标准
什么是node.js
node.js是一个基于Chrome V8引擎的JavaScript的后端运行环境,使用了一个事件驱动、非阻塞式I/O模型,让JavaScript 运行在服务端的开发平台
变量&常量及其声明
- var:JavaScript早期使用的声明变量的关键字,不建议使用
- let: es6用于声明变量的关键字
- const:es6用于声明常量
//常量改数值
const a = [100,39];
a[0] = 50; //OK
a = [50,39]; //error
// var的变量提升
if(false){
var name='bonnie';
}
console.log(name)
//undefined, name在block作用域有变量提升,所以name已经声明了,但是未赋值
console.log(a); //undefined,变量提升
var a = 2;
//var在block块中不受限,是全局变量
if(true){
var b = 20;
}
console.log(b); //20,true则b=20已赋值成全局变量
Scope作用域
- var在function函数体内有效,外部无法访问到
function hello(){
var a = 10;
}
console.log(a); //a is not defined. function内无法变量提升
- let/const 在block块级作用域内有效,块级局部变量
if(true){
let b = 20;
}
console.log(b); //b is not defined.
var/let和const对比
| var/let | const | |
|---|---|---|
| 声明时是否需要赋值 | 不一定 | 必须,且只能赋值一次 |
| 声明后是否可以修改 | 可以 | 可以改值,不可改地址 |
var和let/const对比
| var | let/const | |
|---|---|---|
| Scope | Function Scope | Block Scope |
| 重复声明 | 可以 | 不可以(一个block内,一个变量不可以多次声明) |
| 会造成全局属性(全局污染) | 会 | 不会 |
| 变量提升 | 有 | 有(TDZ) |
物件导向
把一个函数赋给一个常量,箭头函数即是一个简单的物件导向:
const add = (a,b) => a+b
函数
列印function名称得到的是函数体本身,加()才是执行function
function a(){}
console.log(a) //打印a函数本身:function a(){}
console.log(a()) //打印a函数的执行结果
高阶函数:higher order function
- 可以接受别的function当参数
- 可以返回function
setTimeout(()=>{},2000) //高阶函数
对象简写(es6写法)
const age = 25;
const person = {
name:'bonnie',
age, //此为age:age,的简写
}
JavaScript中的每种类型都有一个布尔等效项
0为false,其余都为true
0 == false //true
-1 == true //true
0 === false //false
解构
赋别名及默认初始值
const age = 25;
const person = {
name:'bonnie',
age,
}
const { name:name1 = 'test', age} = person; //name1即别名,test默认值
function参数的解构:
function print({name,age}){
}
print(person)
剩余参数/扩展运算符(...)
function参数中的剩余参数:
function hello(a,b,...args){}
hello(1,2,4,5,6); //...args即4,5,6
解构中的剩余参数:
const list = [1,2,3,5,64,3]
const [a,b,...args] = list;
用扩展运算符合并对象数组:
//1. 合并对象
const a = {name:'bb',age:12}
const b = {name:'cc',height:155}
const c = {...a,...b} //自动去重,key相同的保留后面的一个。{"name":"cc","age":12,"height":155}
//使用Object.assign,效果等同
const a = {name:'bb',age:12}
const b = {name:'cc',height:155}
console.log(Object.assign(a,b))
//2. 合并数组
const a = [1,2,3]
const b = [4,3,5]
console.log([...a,...b]) //不会去重,只做合并.[1,2,3,4,3,5]
面向对象(class)
- ES5的构造函数写法:
// 每个实例化对象都有__proto__
// 每个function都有prototype,默认是空,()=>{}
const actions = {
attack:function() {
console.log("attack");
},
eat:function() {
console.log("eat");
}
}
function heroCreator(name,age) {
this.name = name;
this.age =age;
// return this; //new实例化时,默认return this
}
heroCreator.prototype = actions; //每个function都有prototype
//实例化.不加new,则没有return,hero即undefined
const hero = new heroCreator('bonnie',25);//hero.__proto__ === heroCreator.prototype
console.log(hero.__proto__===heroCreator.prototype)
hero.attack(); //attack
- ES6的构造函数写法:(语法糖,最终都会转成ES5写法)
class Actions {
attack:function() {
console.log("attack");
},
eat:function() {
console.log("eat");
}
}
class heroCreator extends Actions {
constructor(name,age){
super(); //通过super调用父类方法,不写会报错
this.name = name;
this.age =age;
}
}
//实例化
const hero = new heroCreator('bonnie',25);
hero.attack(); //attack
console.log(heroCreator.prototype);
Array常用方法(forEach/map/filter/reduce:均不对原有数组做改动)
- filter只做筛选,不对原数组做处理(加减乘除等),返回的新数组还是原数组的数值,只是个数不一样。回调函数中写的是一个判断表达式,返回一个新数组;
arr=['snow','bran','king','nightking'];
var newarr=arr.filter(function(i){
return i == "bran"
});
console.log(newarr)
- forEach:可以不知道数组长度,没有返回值;
arr.forEach((ele,index)=>{
console.log(index);
console.log(ele);
})
- map:返回的新数组个数一定跟原有的一样,可以对原数组做操作后,返回一个新数组;
const a=[1,2,3,4]
const b = a.map((e)=>{
if(e>2){
return e*2;
}
})
console.log(b) //[undefined,undefined,6,8]
- some:遍历数组中是否有符合条件的函数,返回布尔值;
var yy=arr.some(function(i){
return i.length>4
});
console.log(yy) //true
- every:遍历数组是否每个元素都符合条件,返回布尔值;
var xx=arr.every(function(i){
return i.length>4
});
console.log(xx) //false
- reduce:为数组中的每一个元素依次执行回调函数;
[0,1,2,3,4].reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue;
},0);
previousValue:上一次调用回调返回的值,或者是提供的初始值(initialValue);
currentValue:当前被处理的值;
index:当前元素在数组中的索引;
array:调用reduce的数组;
initialValue:作为第一次调用callback的第一个参数;
Array的扩展方法
- find:返回第一个找到的符合条件的数组成员(类似filter,但filter返回的是数组,且匹配所有符合条件的)
- findIndex:返回第一个找到的符合条件的数组成员的index值
//
const arr = [1,2,3,4];
arr.find((e,i)=> e == 2)
- includes:判断数组或字符串是否包含,返回布尔值
[1,2].includes(2); //true
- flat:把数组中的数组打开
[1,2,[3,4]].flat(Infinity); //[ 1, 2, 3, 4 ]
[1,2].flatMap(a => [a*3] ); //[ 3, 6 ]
- Object.entries(): 将obj转array,可以列出的所有[key,value]对
const obj ={ name: '小明', age: 20, sex: '男' };
console.log(Object.entries(obj)); //[ [ 'name', '小明' ], [ 'age', 20 ], [ 'sex', '男' ] ]
-
Object.fromEntries(): 与上相反,将map数组转obj
-
Object.values():将对象的value项转换数组
const obj = {
0: 'hellow world',
1: 'xiaoming',
2: 'xiaohong',
'length': 3
}
console.log(Object.values(obj)); //[ 'hellow world', 'xiaoming', 'xiaohong', 3 ]
-
Object.keys():将对象的key值转换为数组
-
Array.from():将对象的value转换数组,或将对象转数组
let obj = {
0: 'hellow world',
1: 'xiaoming',
2: 'xiaohong',
'length': 3
}
let arr = Array.from(obj)
console.log(arr); //[ 'hellow world', 'xiaoming', 'xiaohong' ]
const arr1 = Array.from(obj, x => x + ' mic');
console.log(arr1); //[ 'hellow world mic', 'xiaoming mic', 'xiaohong mic' ]
console.log(Array.from('foo')); //["f", "o", "o"]
注意:
- object中必须有length属性,返回的数组长度取决于length长度
- key必须是数值
// 不同方法实现数组的处理
const arr = [1, 2, 3, 4]
console.log(arr.map(e => e ** 2));
console.log(arr.flatMap(e => [e ** 2]));
console.log(Array.from(arr, e => e ** 2)); //[ 1, 4, 9, 16 ]
- Set():ES6中新的数据结构,是类似数组,但成员的值是唯一的,没有重复的值,可以将数组转对象{}
let list = new Set()
//add()
list.add("1")
list.add(1)
console(list) // Set(2) {1, "1"}
//size
console(list.size) // 2
//delete()
list.delete("1")
console(list) // Set(1) {1}
//has()
list.has(1) // true
list.has(3) // false
//clear()
list.clear()
console(list) // Set(0) {}
let arr = [{id: 1}, {id: 2}, {id: 3}]
let list = new Set(arr)
// 数组去重
let arr = [1, 1, 'true', 'true', true, true, undefined, undefined];
console.log([...new Set(arr)])
//或
console.log(Array.from(new Set(arr))) //[ 1, 'true', true, undefined ]
各Array循环方法对比
| For循环对比 | for in | for of | forEach | 传统for |
|---|---|---|---|---|
| 是否支持continue | Y | Y | N | Y |
| 是否支持break | Y | Y | N | Y |
| 是否支持return | Y | Y | N | Y |
| 是否支持遍历对象 | Y | N | N | Y |
- 只有传统for及for in支持遍历对象,其他循环只能遍历array
- for of:遍历array的value
- for in:遍历array及obj的index(key),在遍历对象时,有些浏览器会遍历
对象原型自带的属性,排除需要用!obj.hasOwnProperty(key),或者通过es5新方法遍历obj,Object.values(obj)将其值转成数组遍历。
for in中的break/continue使用:
var names = {name1: "第一", name2: "第二", name3: "第三", name4: "第四"}
for(var key in names) {
if (names[key] === "第三") {
break; //continue:不显示第三
}
console.log(names[key])
}
console.log("下面代码");//break:第三第四都不显示
传统for中的return使用:
for (let i = 0; i <=4; i++) {
if (i === 3) return;
console.log(123);
}
console.log('234'); //只显示三次123,return使用后退出整个程式,后面的234也不会显示
- break:是立即结束语句,并跳出当前循环,进行下个语句执行。
- continue:是停止当前循环,并继续开始洗一个循环。
- return:停止当前程式,后面所有语句都不执行了。
正则表达式
const str = 'abc Bonnie';
const re = new RegExp('bonn','i'); //加上i代表不区分大小写
re.test(str); //true,包含'bonn'则返回true,否则false
re.exec(str); //存在则返回'bonn',否则返回null
//简写方式:
const patt = /bonn/ig; //不区分大小写,全文搜索
patt.test(str); //true
str.match(patt); //存在则返回'bonn',否则返回null
str.search('bonn') //返回bonn所在的index值
const newStr = str.replace(patt,'') //用空替代bonn,对原数组无影响
console.log(newStr)
Example:匹配电话号码邮箱等
// 匹配手机号, 必须一1开始,且第二位只能是3-9,后9位是0-9,且以数字结尾$
var res = /^[1][3-9][0-9]{9}$/;
let num = 18045216903
console.log(res.test(num))
// 匹配身份证号码
var res = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
var n='52032119890615548X'
console.log(res.test(n));
// 匹配用户名6-8位(纯数字)
var res = /^[^0]\d{5,7}$/
var user=12345678
console.log(res.test(user));
// 匹配密码6-8位(数字加字符)
var res=/^\w{5,7}$/
var pwd='12345d_'
console.log(res.test(pwd));
// 匹配QQ号码
var res = /^[^0]\d{4,9}$/ // /^[1-9][0-9]{4,9}$/
var q = '0848514604'
console.log(res.test(q));
// 取掉前后空格
var res =/(^\s*)|(\s*$)/g
let str = ' dsf sdfs fsdf 第三方 '
console.log(str.replace(res,""))
// 取掉所有空格
var res =/\s/g
let str = ' dsf sdfs fsdf 第三方 '
console.log(str.replace(res,""))
// 匹配邮箱
var res = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
var email='2384591034@gamil.com'
console.log(res.test(email));
细则参考网址:JS 正则匹配(RegExp), 正则测试网址:regex101.com/
以上全部,完结!