一文读懂会用Javascript&ES6

446 阅读9分钟

什么是javascript

JavaScript是一种运行在客户端的脚本语言(最开始,后来也可以运行在服务器端);不需要编译,运行过程中由js解释器逐个进行解释并执行。浏览器是JavaScript的前端运行环境,DOM及BOM是浏览器提供的api模块。 Javascript.png

浏览器执行javascript的方式

浏览器分为两部分:渲染引擎和js引擎

  1. 渲染引擎:用来解析Html和css,即为内核,比如:chrome浏览器的blink,老版本的webkit
  2. js引擎:js解释器,用来读取网页中的js代码,对其处理后运行,比如:chrome V8引擎。引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以js语言归为脚本语言,会逐行解释执行

什么是ECMAScript

ECMAScript:JavaScript的语法

  • Javascript(网景公司)和jscript(微软公司)是ecmascript的实现和扩展
  • 规定了js的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套js语法工业标准

什么是node.js

node.js是一个基于Chrome V8引擎的JavaScript的后端运行环境,使用了一个事件驱动、非阻塞式I/O模型,让JavaScript 运行在服务端的开发平台

Node.js.png

变量&常量及其声明

  1. var:JavaScript早期使用的声明变量的关键字,不建议使用
  2. let: es6用于声明变量的关键字
  3. 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作用域

  1. var在function函数体内有效,外部无法访问到
function hello(){
    var a = 10;
}
console.log(a); //a is not defined. function内无法变量提升
  1. let/const 在block块级作用域内有效,块级局部变量
if(true){
    let b = 20;
}
console.log(b); //b is not defined.

var/let和const对比

var/letconst
声明时是否需要赋值不一定必须,且只能赋值一次
声明后是否可以修改可以可以改值,不可改地址

var和let/const对比

varlet/const
ScopeFunction ScopeBlock 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

  1. 可以接受别的function当参数
  2. 可以返回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)

  1. 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
  1. 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:均不对原有数组做改动)

  1. filter只做筛选,不对原数组做处理(加减乘除等),返回的新数组还是原数组的数值,只是个数不一样。回调函数中写的是一个判断表达式,返回一个新数组;
arr=['snow','bran','king','nightking'];
var newarr=arr.filter(function(i){
  return i == "bran"
});
console.log(newarr)
  1. forEach:可以不知道数组长度,没有返回值;
arr.forEach((ele,index)=>{
    console.log(index);
    console.log(ele);
})
  1. 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]
  1. some:遍历数组中是否有符合条件的函数,返回布尔值;
var yy=arr.some(function(i){
  return i.length>4
});
console.log(yy)       //true
  1. every:遍历数组是否每个元素都符合条件,返回布尔值;
var xx=arr.every(function(i){
  return i.length>4
});
console.log(xx)       //false
  1. 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的扩展方法

  1. find:返回第一个找到的符合条件的数组成员(类似filter,但filter返回的是数组,且匹配所有符合条件的)
  2. findIndex:返回第一个找到的符合条件的数组成员的index值
// 
const arr = [1,2,3,4];
arr.find((e,i)=> e == 2)
  1. includes:判断数组或字符串是否包含,返回布尔值
[1,2].includes(2);  //true
  1. flat:把数组中的数组打开
[1,2,[3,4]].flat(Infinity); //[ 1, 2, 3, 4 ]
[1,2].flatMap(a => [a*3] );  //[ 3, 6 ]
  1. Object.entries(): 将obj转array,可以列出的所有[key,value]对
const obj ={ name: '小明', age: 20, sex: '男' };
console.log(Object.entries(obj)); //[ [ 'name', '小明' ], [ 'age', 20 ], [ 'sex', '男' ] ]
  1. Object.fromEntries(): 与上相反,将map数组转obj

  2. Object.values():将对象的value项转换数组

 const obj = {
  0: 'hellow world',
  1: 'xiaoming',
  2: 'xiaohong',
  'length': 3
} 
console.log(Object.values(obj));   //[ 'hellow world', 'xiaoming', 'xiaohong', 3 ]
  1. Object.keys():将对象的key值转换为数组

  2. 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"]

注意:

  1. object中必须有length属性,返回的数组长度取决于length长度
  2. 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 ]
  1. 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 infor offorEach传统for
是否支持continueYYNY
是否支持breakYYNY
是否支持returnYYNY
是否支持遍历对象YNNY
  1. 只有传统for及for in支持遍历对象,其他循环只能遍历array
  2. for of:遍历array的value
  3. 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也不会显示
  1. break:是立即结束语句,并跳出当前循环,进行下个语句执行。
  2. continue:是停止当前循环,并继续开始洗一个循环。
  3. 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/

以上全部,完结!