前言
-
es6不兼容问题(在低版本浏览器里面怎么用)
-
ES6较之于ES6之前的修改
- 变量
- 函数
-
数组
-
字符串
-
面向对象
es6面向对象的使用:
- 变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="wrap"></div>
<script type="text/babel">
// 面向对象应用 —————— React(依赖于es6的面向对象)
/*
React的特点:
1. 组件化 —————— 模块化(一个组件就是一个模块)
2. JSX(是js的扩展版本) —————— babel —————— browser.js
*/
// 渲染数据
/*
class Test extends React.Component {
constructor(...args) {
super(...args);
}
}
window.onload = function() {
let wrap = document.getElementById("wrap");
ReactDOM.render(
<span>123</span>,
wrap
)
}
*/
// 组件化
/*
class Test extends React.Component {
constructor(...args) {
super(...args);
}
render() {
return <span>123</span>;
}
}
window.onload = function() {
let wrap = document.getElementById("wrap");
ReactDOM.render(
<Test></Test>,
wrap
)
}
*/
// 数据的渲染
class Item extends React.Component {
constructor(...args) {
super(...args);
}
render() {
return <li>{ this.props.str }</li>;
}
}
window.onload = function() {
let wrap = document.getElementById("wrap");
ReactDOM.render(
<ul>
<Item str="abc"></Item>
<Item str="def"></Item>
</ul>,
wrap
)
}
</script>
</body>
</html>
6. Promise(把异步操作拆分成同步操作)
Promise的两种用法:
- Promise.all()
- Promise.race()
-
generator(把异步操作拆分成同步操作)
-
模块化(es6自带模块化)
-
面向对象编程介绍
两大编程思想
面向过程编程 POP(process-oriented programming)
- 面向过程就是分析解决问题所需要的步骤,然后用函数把这些步骤一步步的实现,使用的时候在一个个的依次调用就可以了。
- 例子:把大象装进冰箱
- 打开冰箱门
- 把大象放进冰箱
- 关上冰箱门
- 面向对象的特性:
- 封装性(盒子)
- 继承性(子承父业)
- 多态性(同一个对象在不同的时刻可以体现出不同的状态)
- 优点:
- 面向对象编程具有灵活,代码可复用,容易维护和开发的优点,更适合多人合作的大型软件项目
面向对象 OOP(Object Oriented Programming)
-
面向对象是把事务分解成为一个个对象,然后由对象之间分工合作。
-
例子:把大象装进冰箱
- 找出对象,并写出这些对象的功能(大象,冰箱)
- 使用大象和冰箱的功能
- 面向对象是以对象的功能来划分问题,而不是步骤
-
区别
- 面向过程
- 优点:性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机就采用面向过程编程
- 缺点:没有面向对象容易维护,易复用,易拓展
- 面向对象
- 优点:易维护,易复用,由于面向对象有封装,继承,多态的特性,可以设计出低耦合的系统,使系统更加灵活,更加易于维护
内聚就是指程序内的各个模块之间的关系紧密程度,耦合就是各个外部程序(子程序)之间的关系紧密程度.
- 缺点:性能比面向过程低
- 优点:易维护,易复用,由于面向对象有封装,继承,多态的特性,可以设计出低耦合的系统,使系统更加灵活,更加易于维护
- 面向过程制作出来的程序就是一份蛋炒饭,面向对象写出来的程序就是一份盖浇饭
- 面向过程
Es6的类和对象
面向对象的思维特点:
- 抽取(抽象)对象公共的属性和行为组织(封装)成一个类(模板)
- 对类进行实例化,获取类的对象
对象:
-
对象是一个具体的事物。在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象。
-
对象是由属性和方法组成的
-
属性:事物的特征,在对象中用属性来表示
-
方法:事物的行为,在对象中用方法来表示
类:在es6中增加了类的概念,可以使用class关键字声明一个类。
- 类抽象了对象的公共部分,它泛指一个大类
- 对象特指某一个,通过类来实例化一个具体的对象
创建一个类和对象:
- 类
class gender{
}
- 对象
new gender();
类中constructor构造函数
constructor()方法是类的构造函数(默认方法),用于传递参数,返回实例对象,通过new命令生成对象时,窗体加载时自动调用该方法,如果没有显式定义,类内部会自动给我们创建一个constructor()
//创建类
class Start{
//构造函数
constructor(name){
// this就是创建的实例
this.name = name;
}
}
// 利用类创建对象
var people = new Start('卑微小陈'); //调用类时,只要加了参数,将自动调用构造函数方法
//使用
console.log(people.name); //在浏览器中打印输出 卑微小陈
注意:
- 通过class挂机案子创建类。类名首字母大写
- 类里面的构造函数,可以接受传递过来的参数,同时返回实例对象
- 构造函数 只要 new 生成实例时,就会自动调用这个函数,如果不写这个函数,类也会自动生成这个函数
- 生成实例 new 关键字不能省略
- 创建类后面不要加小括号,生成实例,类名后面加小括号,构造函数不需要加function
类中添加方法
//创建类
class Start{
//构造函数
constructor(name){
// this就是创建的实例
this.name = name;
}
//方法
// 类里面的所有的函数不需要写关键字function
// 多个函数方法之间不需要添加逗号分隔
taking(content){
console.log(this.name + content);
}
}
// 利用类创建对象
var people = new Start('卑微小陈说:');
people.taking('上帝撒了一把智慧,而我却打了一把伞~')
console.log(people);
类的继承
子类可以继承父类的方法和属性:
// 父类
class Father{
money(){
console.log(10000000)
}
}
// 子类 继承(extend) 父类
class Son extend Father{
}
var son = new Son();
son.money(); //打印输出10000000
super关键字
super关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数。
calss Father{
constructor(x,y){
this.x = x;
this.y = y;
}
sum(){
console.log(this.x + this.y)
}
}
class Son extends Father{
constructor(x,y){
super(x,y);//调用父类中的构造函数
}
}
var son = new Son(2,4);
son.sum(); //打印输出6
注意:
- 继承中,如果实例化字类输出一个方法,先看子类有没有这个方法,如果有就执行字类的
- 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
- 继承中的属性和方法的查找原则:就近原则
字类类可以调用父类的方法:
class Father{
say(){
return '我是爸爸';
}
}
class Son extends Father{
say(){
// 打印输出 字类 的say方法
// console.log('我是儿子');
//子类调用父类里面的方法
// super.say()就是调用父类中的普通函数say这个函数
console.log(super.say() + '的儿子');
}
}
var son = new Son();
son.say();
子类继承父类加法方法 同时 扩展减法方法
class Father(){
constructor(x,y){
this.x = x;
this.y = y;
}
sum(){
console.log(this.x + this.y);
}
}
class Son extends Father{
constructor(x,y){
// 调用父类中的构造函数
// 注意:要使用父类中的方法,必须先调用才能使用,也就是super必须在子类this之前调用
super(x,y);
this.x = x;
this.y = y;
}
substract(){
console.log(this.x - this.y);
}
}
var son = new Son(5,2);
//调用子类中的substract方法
son.substract(); //打印输出3
//调用子类从父类中继承的sum方法
son.sum(); //打印输出7
注意
- 在Es6中类没有变量提升,所以必须先定义类,才能通过类实例化对象
- 类里面的共有的属性和方法一定要加this使用
- 类里面的this的指向的问题
- constructor里面的this指向实例对象,方法里面的this指向这个方法的调用者
<body>
<button>点我</button>
<script>
var that;
var _that;
class Strat{
// construcror 里面的this指向的是创建的实例对象
constructor(name,age){
that = this;
console.log(that); //打印输出实例对象 ‘华晨宇’
this.name = name;
this.age = age;
//调用Sing方法
//this.sing();
//通过按钮点击事件来调用sing方法
this.btn = document.queryString('button'); //通过标签选择器选中按钮
this.btn.onclick = sing; //注意sing方法后面不要加小括号哟,加小括号后立马调用sing方法
}
sing(){
//sing方法里面的this指向的是btn这个按钮,因为btn调用了sing这个方法
//console.log(this.name); //输出undefined
console.log(that.name); //输出华晨宇
}
dance(){
//这个dance里面的this指向的是实例对象 people,因为people调用了这个函数
_that = this;
console.log(_that); //打印输出华晨宇
}
}
// 实例化Strat方法
var people = new Strat('华晨宇');
people.dance();
</script>
</body>
构造函数和原型
在典型的OOP(面向对象)的语言中(如java),都存在类的概念,类就是对象的模板,对象就是类的实例,但是在ES6之前,js并没有引入类的概念。
在ES6之前,对象不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和他们的特征。
创建对象的方式:
- 对象字面量
- new Object()
- 自定义构造函数
// 对象字面量
var obj1 = {};
// new Object()
var onj2 = new Object();
//自定义构造函数
function Start(name,age){
this.name = name;
this.age = age;
}
//通过构造函数生成不同的对象
var sin = new Start('易烊千玺',20);
构造函数
构造函数是一种特殊的函数,主要用来出啊实话对象,即对象成员变量赋初始值,它总是与new一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在js中,使用构造函数时要注意以下两点:
- 构造含糊用于创建某一类对象,其首字母大写
- 构造函数要和new一起使用才有意义。
new在执行时会做的四件事情:
- 在内存中创建一个空对象
- 让this指向这个新的对象
- 执行构造函数里面的代码,给这个新对象添加属性和方法
- 返回这个新对象(所以构造函数里面需要return)。
构造函数中的属性和方法我们成为成员,成员可以添加
成员可以分为:实例成员和静态成员
-
实例成员
- 就是构造函数内部通过this添加的成员
- 实例成员只能通过实例化对象来访问(sin.name)
-
静态成员
- 在构造函数本身添加的成员(Start.sex = ‘女’)
- sex就是静态成员
- 静态成员只能通过构造函数来访问(console.log(Start.sex))
构造函数的问题
构造函数的方法很好用,但是存在浪费内存的问题。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qymgR9lF-1585145600549)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200321115420071.png)]
构造函数原型 prototype
构造函数通过原型分配的函数是所有对象所共享的。
JavaScript规定,每一个构造函数都有一个prototype属性,指向另外一个对象,注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在prototype对象上面,这样所有的对象都可以共享这些方法。
- 原型是什么?
- 一个对象,我们也称为prototype为原型对象
- 原型的主要作用是什么?
- 共享方法
- 一般情况下。我们的公共属性定义到构造(constructor)函数里面,公共的方法我们放到原型(prototype )对象上面
对象原型__proto__
对象都会有一个__proto__
指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__
原型存在。
__proto__
对象原型和原型对象prototype
是等价的
constructor构造函数
对象原型(proto)和构造函数(prototype)原型对象里面都有一个属性constructor属性,constructor我们称为构造函数,因为它只会构造函数本身。
constructor主要用于记录对象引用于那个构造函数,它可以让原型对象重新指向原来的构造函数。
function Start(name,age){
this.name = name;
this.age = age;
}
//Start.prototype.sing = function(){
// console.log('唱歌');
//}
//很多情况下,我们需要手动的利用constructor这个属性 指回 原来的构造函数
Start.prototype = {
//让构造函数指回原来的构造函数
//如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
constructor:Start,
sing:function(){
}
movie:function(){
}
}
var l = new Start('卑微小陈',20);
构造函数,实例,原型对象三者之间的关系
原型链
JavaScript的成员查找机制(规则)
- 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
- 如果没有就查找它的原型(也就是
__proto__
)。 - 如果还没有查找原型对象的原型(Object的原型对象)。
- 依次类推–查找到Object为止(null)。
__proto_
对象原型的意义就在于为对象成员查找机制提供一个方向,或者说提供一条路线。
原型对象this指向
- 在构造函数中,里面的this指向的是对象实例
- 原型对象函数里面的this指向的是 实例对象
扩展内置对象
可以通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组添加自定义求偶书和的功能。
数组的原型对象:
注意:数组和字符串内置对象不能给原型对象覆盖操作Array.prototype = {},只能是Array.prototype.xx = function(){}的方式
console.log(Array.prototype);
// 原型对象的应用 扩展内置对象方法
// 在原来的方法里面追加一个方法
Array.prototype.sum = function() {
var sum = 0;
for(var i = 0; i < this.length; i++){
sum += this[i];
}
return sum;
}
// 错误
// 数组和字符串内置对象不能给原型对象覆盖操作Array.prototype = {}
// Array.prototype = {
// sum: function() {
// var sum = 0;
// for (var i = 0; i < this.length; i++) {
// sum += this[i];
// }
// return sum;
// }
// }
var arr = [1, 2, 3];
console.log(arr.sum());
console.log(Array.prototype);
继承
Es6之前并没有给我们提供extends继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。
call()
调用这个函数,并且修改函数运行时的this指向。
fun.call(thisArg,arg1,arg2,...)
- thisArg:当前调用函数this的指向对象
- arg1,arg2:传递的其他参数
function like(x, y) {
console.log('想要自由');
console.log(this); //当前this指向window
console.log(x + y);
}
var o = {
name: 'Harty'
};
//调用函数
// like();
// 1 call()可以调用函数
like.call();
// 2 call()可以修改like方法里面的this指向
like.call(o,1,2); // 此时函数的对象就指向了o这个对象 打印输出3
借用构造函数继承父类型属性
核心原理:通过call()把父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性。
// 1 父构造函数
function Father(name,age){
// this指向父构造函数的对象实例
this.name = name;
this.age = age;
}
// 2 子构造函数
function Son(name, age, score){
// this指向子构造函数的对象实例
Father.call(this,name,age); //调用父构造函数,将父构造函数的this指向变成子构造函数的this指向
// 添加子构造函数自身的数据
this.score = score; //score既继承了父构造函数的数据,也有自身的数据
}
var son = new Son('卑微小陈', 20, 59);
console.log(son);
借用原型对象继承父类型方法
// 1 父构造函数
function Father(name,age){
// this指向父构造函数的对象实例
this.name = name;
this.age = age;
}
// 给父构造函数添加方法
Father.prototype.money = function(){
console.log(100000);
}
// 2 子构造函数
function Son(name, age, score){
// this指向子构造函数的对象实例
Father.call(this,name,age); //调用父构造函数,将父构造函数的this指向变成子构造函数的this指向
// 添加子构造函数自身的数据
this.score = score; //score既继承了父构造函数的数据,也有自身的数据
}
// 使用添加的父构造函数的方法
// 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起修改
// Son.prototype = Father.prototype;
Son.prototype = new Father(); //实例父原型对象,然后给子原型对象
//如果利用对象的形式修改了原型对象,别忘了利用constructor指回原来的构造函数
Son.prototype.constructor = Son;
// 给子构造函数添加方法(子构造函数专门的方法)
Son.prototype.worker = function(){
console.log('程序媛');
}
var son = new Son('卑微小陈', 20, 59);
console.log(son);
类(es6通过类实现面向对象编程)
类的本质
类的本质还是一个函数,我们也可以简单的认为类就是构造函数的另外一种写法。
构造函数的特点:
-
构造函数有原型对象prototype
-
构造函数原型对象prototype里面有constructor指向构造函数本身
-
构造函数可以通过原型对象添加方法
-
构造函数创建的实例对象有
__proto__
原型指向构造函数的原型对象
class Start{
}
console.log(typeof Start); //function
// 1)构造函数有原型对象prototype
console.log(Start.prototype);
// 2)构造函数原型对象prototype里面有constructor指向构造函数本身
console.log(Start.prototype.constructor);
// 3)构造函数可以通过原型对象添加方法
Start.prototype.sing = function(){
console.log('唱歌');
}
// 4)构造函数创建的实例对象有`__proto__`原型指向构造函数的原型对象
var lyf = new Start();
console.dir(lyf);
console.log(lyf.__proto__ === Start.prototype);
类的所有方法都定义在类的prototype属性上
所以es6的类它的绝大部分功能,es5都能做到,新的class写法只是让对象原型的写法更加清晰,更像面型对象的语言
所以es6的类就是语法糖
语法糖:语法糖就是一种便捷的写法,简单的理解,有两种方法可以实现同样的功能,但是一种写法更加清晰,方便,那么这个方法就是语法糖。
es5新增的方法
-
数组方法
-
迭代(遍历)方法:forEach(),map(),filter(),some(),every()
-
forEach()
array.forEach(function(currentValue,index,arr));
currentVaule:数组当前项的值
index:数组当前项的索引
arr:数组对象本身[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xBpYnt9i-1585145600550)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200322135502793.png)]
-
filter()—过滤器
array.filter(function(currentValue,index,arr))
filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组。
注意它直接返回一个新数组。
currentValue:数组当前项的值
index:数组当前项的索引
arr:数组对象本身[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zpNS9dCT-1585145600551)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200322140323797.png)]
-
some()
array.some(function(currentValue,index,arr))
some()方法用于检测数组中的元素是否满足指定条件,通俗的讲就是数组中是否有满足条件的元素
注意它的返回值是布尔值,如果查找到这个元素,就返回true,如果查找不到,就返回false
如果找到第一个满足条件的元素,则终止循环,不再继续查找
currentValue:数组当前项的值
index:数组当前项的索引
arr:数组对象本身[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gqfWggoF-1585145600552)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200322141030520.png)]
-
-
字符串方法
-
trim()方法
-
trim()方法会从一个字符喜欢的两端删除空白字符
str.trim()
trim()方法本身并不影响原字符串本身,它返回的是一个新的字符串
var str = ' 卑微小陈 在线找工作 '; console.log(str); console.log(str.trim());
-
-
-
对象方法
-
Object.defineProperty()定义对象中新属性或修改原有的属性
Object.defineProperty(obj,prop,descriptor)
obj:必需。目标对象
prop:必需。需定义或修改的属性的名字
descriptor:必需。目标属性所拥有的特性,以对象{}的形式书写
value:设置属性的值。默认undefined
writeable:值是否可以重写。true|false,默认为false
enumerable:目标属性是否可以被枚举。true|false,默认false
configurable:目标属性是否可以被删除或是否可以再次修改特性true|false,默认false
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title></title> </head> <body> <script type="text/javascript"> var obj = { id: 1, name: '小陈', hobby: '代码编程' }; // 1 以前的调价和修改属性的方式 // obj.age = 20; // console.log(obj); // 2 Object.defineProperty()定义新属性或修改原有的属性 Object.defineProperty(obj, 'age', { // 如果里面有age属性就修改操作,没有就做添加操作 value: 20 //给obj数组里面,添加一个age属性,并且age属性的属性值为20 }); console.log(obj); Object.defineProperty(obj, 'id', { writable: false,//值为false,不允许修改这个属性值,默认为false }); obj.id = 2; console.log(obj); Object.defineProperty(obj, 'address', { value: '湖南长沙', // enumberable如果为false,则不允许遍历 enumberable: false, // configurable如果为false,则不允许被删除和再次修改这个特性,默认为false configurable: false }); console.log(obj); console.log(Object.keys(obj)); delete obj.address; //删除address信息 console.log(obj); delete obj.hobby; //删除hobby信息 console.log(obj); </script> </body> </html>
-
小试牛刀之数组方法
根据数组方法来查询数据:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
.content {
width: 800px;
height: auto;
margin: 50px auto;
}
.search input{
margin-left: 10px;
}
input[type = 'text']{
width: 50px;
}
table{
margin-top:30px;
}
tbody{
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div class="search">
按照条件查询:<input type="text" class="start"/> - <input type="text" class="end"/> <input type="button" class="search_price" value="搜索" />
按照商品名称查询:<input type="text" class="select_name"/><input type="button" class="select_btn" value="查询" />
</div>
<table border="1px" cellspacing="0" cellpadding="0" width="500px">
<thead>
<tr>
<th>id</th>
<th>产品名称</th>
<th>价格</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script type="text/javascript">
var data = [{
id: 1,
name: '华为',
pice: 10000
},{
id: 2,
name: 'opp',
pice: 7000
},
{
id: 3,
name: 'vivo',
pice: 6666
},
{
id: 4,
name: 'iPhone',
pice: 15000
},
{
id: 5,
name: '小米',
pice: 7000
},
{
id: 6,
name: '三星',
pice: 6500
}];
// 获取相应的元素
var tbody = document.querySelector('tbody');
// 根据价格查询按钮
var search_price = document.querySelector('.search_price');
// 起始价
var start = document.querySelector('.start');
// 结束价格
var end = document.querySelector('.end');
// 商品名称
var select_name = document.querySelector('.select_name');
var select_btn = document.querySelector('.select_btn');
// 页面加载将所有的数据渲染到页面上面
setData(data);
// 渲染页面的方法
function setData(mydata){
// 先清空原来tbody的数据
tbody.innerHTML = '';
// 把数据渲染到页面中
mydata.forEach(function(value){
// console.log(value); value的值是一个Object
// 创建一个行
var tr = document.createElement('tr');
// 创建单元格
tr.innerHTML = '<td>' + value.id + '</td><td>' + value.name + '</td><td>' + value.pice + '</td>';
// 将创建的单元格放到tbody中
tbody.appendChild(tr);
});
}
// 根据价格查询商品
// 当我们点击了按钮,就可以更具我们的商品价格去筛选数组里面的对象
search_price.addEventListener('click',function(){
// alert(11)
var newData = data.filter(function(value){
// value指的是每个数组元素
return value.pice >= start.value && value.pice <= end.value;
})
// console.log(newData);
// 将筛选完成之后的数据渲染到页面上面
setData(newData);
});
// 根据商品名称来查找数据
select_btn.addEventListener('click',function(){
// 因为拿到的数据是一个对象,所以我们要声明一个数组来接收
var arr = [];
// 如果查询数组中唯一的元素,用some方法,因为它找到这个元素,就不再进行循环,效率更高
data.some(function(value){
if(value.name === select_name.value){
// console.log(value);
// 找到对象之后,就将对象添加到数组里面去
arr.push(value);
// 如果返回的是true,则证明找到了这个对象
return true; // 注意return后面必须写 true,some方法返回的是一个布尔类型
}
});
// 把拿到的数据渲染到页面上面
setData(arr);
});
</script>
</body>
</html>
forEach,filter和some的区别
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<script type="text/javascript">
var arr = ['red','yellow','blue','pink'];
<!-- 1.forEach迭代遍历 -->
// forEach去遍历所有的元素
arr.forEach(function(value){
if(value === 'pink'){
console.log('找到了该元素');
return true; //forEach里面的return不会终止迭代
}
console.log('啦啦啦');
});
// 2.some遍历
// 如果查询数组中唯一的元素,用some方法更合适
arr.some(function(value){
if(value === 'yellow'){
console.log('找到了该元素yellow');
return true; //在some里面遇到return true就是终止遍历,迭代效率更高
}
console.log(11);
});
// 3.filter遍历
arr.filter(function(value){
if(value === 'blue'){
console.log('找到了该元素blue');
return true; //filter里面的return不会终止迭代
}
console.log(11);
});
</script>
</body>
</html>
函数的进阶(重点,面试必问)
函数的定义和调用
函数的定义
-
函数声明的方式function关键字(命名函数)
function fn(){};
-
函数表达式(匿名函数)
var fn = function(){};
-
利用new Function(‘参数1’,‘参数2’,‘函数体’)
var f = new Function('a','b','console.log(a + b)'); fn(1,2);
注意:
Function里面参数都必须是字符串格式
这种方式执行效率低,也不方便书写,因此比较少使用
所有的函数都是Function的实例(对象)
函数也属于对象
// 1 自定义函数(命名函数) function fnn() {}; // 2 函数表达式(匿名函数) var fnn = function(){}; // 3 利用new Function('参数1','参数2','函数体') var fn = new Function('a','b','console.log(a + b)'); fn(1,2); // 4 所有的函数都是Function的实例对象 console.dir(fn); console.log(fn instanceof Object); //判断fn函数是否是Object类型,返回的是布尔类型的值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yvU8E8Bk-1585145600553)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200323133814635.png)]
函数的调用
// 函数的调用方式
// 1 普通函数
function fn(){
console.log('卑微小陈在线学习');
}
fn(); //或者fn.call();
// 2 对象的方法
var o = {
sayHi: function(){
console.log('加油~');
}
}
o.sayHi();
// 3 构造函数
function dream(){};
new dream();
// 4 绑定事件函数
btn.onclick = function(){}; //点击按钮就可以调用这个函数
// 5 定时器函数
setInterval(function(){},1000); //这个函数是定时器自动1秒调用一次
// 6 立即执行函数
(function(){
console.log('学习');
})(); // 立即执行函数是自动调用函数
this
函数内的this指向
这些this的指向,是当我们调用函数的时候确定的。调用的方式的不同决定了this的指向不同
一般指向我们的调用者
调用方式 | this指向 |
---|---|
普通函数的调用 | window |
构造函数的调用 | 实例对象 原型对象里面的方法也指向实例对象 |
对象方法的调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器函数 | window |
立即执行函数 | window |
改变函数内的this指向
JavaScript为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部的this的只想问题,常用的有bind(),call(),apply()方法。
-
call方法
call()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this的指向。
fun.call(thisArg,arg1,arg2,...)
var o = { name: 'Heart' }; function fn(){ console.log(this) } fn.call(o); //将fn函数this指向o
call的主要作用可以实现继承
function Father(name,age,sex){ this.name = name; this.age = age; this.sex = sex; } function Son(name,age,sex){ // 调用Father函数,然后将this指向为Son函数,并使用Father里面的内容 Father.call(this,name,age,sex); } var son = new Son('千玺',19,'男'); console.log(son);
-
apply方法
apply()方法调用一个函数,简单理解为调用函数的方法,但是它可以改变函数的this指向。
fun.apply(thisArg,[argsArray])
thisArg:在fn函数运行时指定的this值
argsArray:传递的值,必须包含在数组里面
返回值就是函数的返回值,因为它就是调用函数
var o = { name: 'Heart' }; function fn(arr){ // 也是调用函数 第二个可以改变函数内部的this指向 console.log(this); // 但是她的参数必须是数组(伪数组) console.log(arr); //打印出来的不是数组,是一个字符串 } fn.apply(o,['smHeart']); // apply 的主要应用 比如说我们可以利用apply借助数学内置对象求最大值 var arr = [1,16,9,4,8]; // 存储的就是数组中的最大值 //var max = Math.max.apply(null,arr); var max = Math.max.apply(Math,arr); // 打印输出数组中的最大值 console.log(max);
-
bind()方法不会调用函数,但能改变函数内部的this指向
fun.bind(thisArg,arg1,arg2...)
thisArg:在fn函数运行时指定的this值
arg1,arg2:传递其他参数
返回由指定的this值和初始化参数改造的原函数拷贝
var o = { name: 'Heart' }; function fn(arr){ console.log(this); }; var f = fn.bind(o); f(); //调用新函数f() // 1 不会调用原来的函数 可以改变原来的函数内部的this指向 // 2 返回的是原函数改变this之后产生的新函数 // 3 如果有的函数不需要立即调用,但是又不想改变这个函数内部的this指向此时用bind
// 当我们有一个按钮,我们点击之后就禁用这个按钮,3秒钟之后开启这个按钮 <button type="button" class="btn">点我</button> <script type="text/javascript"> var btn = document.querySelector('.btn'); btn.onclick = function(){ this.disabled = true; //这个this指向的是btn这个按钮 // var that = this; setTimeout(function(){ // 1 给this赋值在使用改变this指向 // that.disabled = false; // 定时器里面的函数this指向的是window // 2 bind this.disabled = false;//这个this也是指向的btn对象 }.bind(this),3000) //这个this也是指向的btn对象 } </script>
-
call,apply,bind总结
- 相同点:
- 都可以改变函数内部的this指向
- 异同点
- call和apply会调用函数,并且改变函数内部的this指向
- call和apply传递的参数不一样,call传递参数aru1,aru2…形式,apply必须以数组形式传递[arg]
- bind不会调用函数,可以改变函数内部的this指向
- 主要应用场景
- call主要应用于继承
- apply经常跟数组有关系,比如借助于数学对象实现数组最大值最小值
- bind不调用函数,但是还想改变this指向,比如改变定时器内部的this指向
- 相同点:
严格模式
JavaScript除了提供正常模式外,还提供了严格模式(strict mode)。Es5的严格模式是采用具有限制性JavaScript变体的一种方式,即在严格的条件下运行js代码。
严格模式在IE10以上版本的浏览器中才会被支持,旧版本浏览器会被忽略。
严格模式对正常的JavaScript语义做了一些更改:
- 消除了JavaScript语法的不合理,不严谨之处,减少了一些怪异的行为。
- 消除代码运行的一些不安全之处,保证代码运行的安全。
- 提高编译效率,增加运行速度。
- 禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的JavaScript做好铺垫。比如一些保留字,如class,enum,extends,import,super不能做变量名。
开启严格模式
严格模式可以应用到整个脚本或个别函数中。因此在使用时,我们可以将严格模式分为脚本开启严格模式和**为函数开启严格模式****两种情况。
为脚本开启严格模式
为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句“use strict”;(或‘use strict’😉。
<script>
'use strict';
// 下面的js代码就会按照严格模式执行代码
</script>
<script>
(function(){
'use strict';
})();
</script>
为函数开启严格模式
<script>
function fn(){
// 给fn函数开启严格模式
'use strict';
// fn函数内部的下面的代码按照严格模式执行
}
</script>
严格模式中的变化
严格模式对javascript的语法和行为,都做了一些改变。
-
变量规定
-
在严格模式下,如果一个变量没有声明就赋值,默认是全局变量,严格模式禁止这种用法,变量都必须先用var声明,然后再使用。
-
严禁删除已声明的变量。例如,delete x;语法是错误的。
-
-
this的指向问题
-
以前在全局作用域函数中this指向window对象
-
严格模式下全局作用域中函数的this是undefined
-
以前构造函数时不加new也是可以调用函数,当普通函数,this指向全局对象
-
严格模式下,如果构造函数不加new调用,this会报错
-
new实例化的构造函数指向创建的对象实例
-
定时器this指向的还是window对象
-
事件,对象还是指向调用者
-
-
函数变化
- 函数不能有重名的参数
- 函数必须声明在顶层新版本的JavaScript会引入“块级作用域”(ES6中已经引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数。
高阶函数
高阶函数是对其他函数进行操作的函数,它 接收函数作为参数或 将函数作为返回值输出。
把一个函数作为参数进行传递:
<script>
function fn(callback){
callback&& callback();
}
fn(function(){alert('hi')})
</script>
把一个函数作为返回值传递:
<script>
function fn(){
return function(){}
}
fn();
</script>
此时fn就是一个高阶函数
函数也是一种数据类型,同样可以作为参数,传递给另外一个参数使用。最典型的就是作为回调函数。
//高阶函数 - 函数可以作为参数传递
function fn(a,b,callback){
console.log(a + b);
callback&& callback();
}
fn(1,2,function(){
console.log('我是最后调用的');
});
闭包
变量的作用域
变量根据作用域的不同分为两种:全局变量和局部变量。
- 函数内部可以使用全局变量
- 函数外部不可以使用全局变量
- 当函数执行完毕,本作用域内的局部变量会销毁
什么是闭包
闭包(closure)指有权访问另一个函数作用域中变量的函数。 —JavaScript高级程序设计
简单的理解就是,一个作用域可以访问另外一个函数内部的局部变量。
function fn(){
var num = 10;
// 闭包:我们fun 这个函数作用域 访问了另外一个函数 fn 里面的局部变量 num
function fun(){
//只要是函数就会创建一个函数的作用域
console.log(num);
}
fun();
}
fn();
闭包的作用
闭包的作用:延伸了变量的作用范围
// 我们fn外面的作用域可以访问fn内部的局部变量
function fn(){
var num = 10;
//function fun(){
//只要是函数就会创建一个函数的作用域
// console.log(num);
//}
//return fun;
return function(){
console.log(num);
}
}
var f = fn();
// 类似于
//var f = function fun(){
//只要是函数就会创建一个函数的作用域
// console.log(num);
// }
// 调用f
f();
闭包案例
-
闭包应用—点击li输出当前li的索引号
-
利用动态添加属性的方式
<ul class="nav"> <li>榴莲</li> <li>臭豆腐</li> <li>鲱鱼罐头</li> <li>蛇果</li> </ul> <script type="text/javascript"> var lis = document.querySelector('.nav').querySelectorAll('li'); for (var i = 0; i < lis.length; i++) { // 动态的给li添加索引 lis[i].index = i; lis[i].onclick = function() { // 拿到当前索引 console.log(this.index); } } </script>
-
利用闭包的方式得到当前小li的索引号
for (var i = 0; i < lis.length; i++) { // 利用for循环创建了4个立即执行函数 // 立即执行函数也称为小闭包,因为立即执行函数里面的任意一个函数副都可以使用它的i变量 (function(i) { lis[i].onclick = function() { // 拿到当前索引 console.log(i); } })(i); }
-
循环中的setTimeout()–3秒钟hi后,打印所有li元素的内容
<ul class="nav"> <li>榴莲</li> <li>臭豆腐</li> <li>鲱鱼罐头</li> <li>蛇果</li> </ul> <script type="text/javascript"> var lis = document.querySelector('.nav').querySelectorAll('li'); for(var i = 0; i < lis.length; i++){ (function(i){ setTimeout(function(){ console.log(lis[i].innerHTML); },3000) })(i); } </script>
-
计算打车的价格
-
打车起步价13(3公里内),之后没多一公里加5块钱,用户输入公里数就可以计算打车价格
如果有拥堵情况,总价格多收取10块钱
<script type="text/javascript"> var car = (function(){ // 起步价 var start = 13; // 总价 var total = 0; return { // 正常的总价 price: function(n) { if(n <= 3){ total = start; } else{ total = (n - 3) * 5 + start; } return total; }, // 拥堵之后的价格 yd: function(flag) { return flag ? total + 10 : total; } } })(); console.log(car.price(5)); // 23 console.log(car.yd(true)); // 33 </script>
-
闭包总结
- 什么是闭包?
- 闭包是一个函数(一个作用域可以访问另外一个作用域的局部变量)
- 闭包的作用
- 延伸了我们变量的作用范围
递归
如果 一个函数在内部可以调用其本身,那么这个函数就是 递归函数。
简单理解:函数内部自己调用自己。这个函数就是递归函数。
递归函数的作用和循环的效果一样。
由于递归很容易发生 “栈溢出” 错误(strack overflow),所以 必须要加退出条件 return。
function fn() {
fn();
// 不加退出条件就是死递归
}
fn();
var num = 1;
function fn(){
console.log('2');
if (num == 6) {
return; // 递归里面必须加退出条件
}
num++;
fn();
}
fn();
利用递归求数学题
- 求
1*2*3...*n
的阶乘。
function fn(n){
if(n == 1){
return 1;
}
return n * fn(n - 1);
}
console.log(fn(3));
详细思路:
return 3 * f(2)
return 3 * (2 * f(1))
retutn 3 * (2 * 1)
retutn 3 * (2 )
retutn 6
-
求斐波那契数列(兔子序列) 1,1,2,3,5,8,13,21…
用户输入一个数字n可以求出 这个数字对应的兔子序列值
我们只需要知道用户输入的n的前面两项【(n-1)(n-2)】就可以计算出n对应序列值
function fn(n){ if(n === 1 || n === 2){ return 1; } return fn(n-1) + f(n-2); }
-
根据用户输入的id号,就可以返回数据的对象
var data = [{ id: 1, name: '小陈', hobby: [{ id: 11, name: '弹钢琴' },{ id: 12, name: '指弹' }] },{ id: 2, name: '美美', hobby: [{ id: 21, name: '看小说' },{ id: 22, name: '海贼控' }] },{ id: 3, name: '娟娟', hobby: [{ id: 13, name: '看小说' },{ id: 14, name: '海贼控' }] },{ id: 4, name: '胖虎', hobby: [{ id: 15, name: '王者荣耀' },{ id: 16, name: '撩哥能妹' }] },{ id: 5, name: '漫漫', hobby: [{ id: 17, name: '蹦迪一枝花' },{ id: 18, name: '桃花满怀' }] },{ id: 6, name: '一菲', hobby: [{ id: 19, name: 'LOL控' },{ id: 20, name: '湖科一姐' }] }]; //我们想要输入id号,就可以返回数组对象 // 1 利用 forEach 去遍历里面的每一个对象 function getId(json,id){ var o = {}; json.forEach(function(item){ // console.log(item); 打印输出每个对象 // 得到数组外层的数据 if(item.id == id){ o = item; // console.log(item); // 得到数组里层的数据 11 12可以利用递归执行函数 // 里面应该有hobby这个数组并且数组的长度不为0 }else if(item.hobby && item.hobby.length > 0){ o = getId(item.hobby,id); } }); return o; } console.log(getId(data,21));
浅拷贝和深拷贝
-
浅拷贝只是拷贝一层,更深层次的对象级别的只拷贝引用(修改浅拷贝后的值,拷贝前的值也会改变)
通过js中的for循环实现浅拷贝:
var obj = { id: 1, name: 'herat', msg: { age: 20, hobby: '指弹' } }; var o = {}; // 通过for循环实现浅拷贝 for(var k in obj){ // k 是属性名 obj[k] 属性值 o[k] = obj[k]; } console.log(o);
通过es6新增的方法实现浅拷贝:
Object.assign(target,…sources) es6新增的实现浅拷贝的方法
var obj = { id: 1, name: 'herat', msg: { age: 20, hobby: '指弹' } }; var o = {}; Object.assign(o,obj); //把obj拷贝给o console.log(o);
-
深拷贝拷贝多层,每一级别的数据都会拷贝(修改浅拷贝后的值,拷贝前的值也不会改变)
通过函数递归实现深拷贝数据:
var obj = { id: 1, name: 'herat', msg: { age: 20, hobby: '指弹' } }; var o = {}; // 封装函数 function deepCopy(newobj,oldobj){ for(var k in obj){ // 判断我们的属性值属于那种数据类型 // 1 获取属性值 obj[k] var item = obj[k]; // 2 判断这个值是否是数组(数组也属于对象类型) if(item instanceof Array){ newobj[k] = []; // 递归函数是把值(item)给属性(newobj[k]) deepCopy(newobj[k],item); } // 3 判断这个值是否是对象 else if (item instanceof Object){ newobj[k] = {}; deepCopy(newobj[k],item); } // 4 属于简单数据类型 else{ newobj[k] = item; } } }; deepCopy(o,obj); console.log(o);
正则表达式
正则表达式的概述
什么是正则表达式?
**正则表达式(Regular Expression)**是用于匹配字符串中字符组合的模式。在Javascript中,正则表达式也是对象。
正则表达式通常被用来检索,替换那些符合某个模式(规则)的文本。例如表单验证(匹配,替换,提取)
正则表达式的特点:
- 灵活性,逻辑性和功能性非常的强。
- 可以迅速地用简单的方式达到字符串的复杂控制。
正则表达式在JavaScript中的使用
创建正则表达式
在JavaScript中,可以通过两种方式创建一个正则表达式。
-
通过RegExp对象的构造函数来创建
var 变量名 = new RegExp(/表达式/);
var regexp = new RegExp(/123/);
-
利用字面量创建
var 变量名 = /表达式/;
var rg = /123/;
检测正则表达式test
test()正则对象方法,用于检测字符串是否符合该规则,该对象会返回true和false,其参数是测试字符串。
regexObj.test(str);
regexObj 是写的正则表达式
str 我们要检测的文本
就是检测str文本是否符合我们写的正则表达式规范
正则表达式中的特殊字符
一个正则表达式 可以由简单的字符构成,比如/abc/,也可以是简单和特殊字符的组合,比如/ab*c/。其中特殊字符也被称为 元字符,在正则表达式中是具有 特殊意义的专用 符号,如^,$,+等。
-
边界符 ^ $
// 只要包含abc这个字符串都会返回true var reg = /abc/; //正则表达式里面不需要加引号 不管是数字型还是字符型 var reg = /^abc/; //匹配以abc开头的字符 var reg = /^abc$/; //匹配以abc开头,以abc结尾的字符
边界符 | 说明 |
---|---|
^ | 表示匹配行首的文本(以谁开始) |
$ | 表示匹配行尾的文本(以谁结束) |
如果^和$在一起,表示必须是精确匹配。 |
-
字符类:[] 表示有一系列字符可供选择,只要匹配其中一个就可以了
var reg = /[abc]/; //只要包含有a 或者 包含有b 或者 包含有c的字符,都返回为true var reg = /^[abc]$/; //三选一,只有是a或者b或者c,就返回true var reg = /^[a-z]$/; //26个英文字母任何一个字母都返回true var reg = /^[a-zA-Z0-9_-]{3,16}$/ //3到16位(用户名) var reg = /^[a-zA-Z0-9_-]{6,18}$/ //密码 var reg = /^[^a-zA-Z0-9_-]{6,18}$/ //如果中括号里面有^,表示取反的意思
-
量词符
量词符用来 设定某个模式出现的次数。
量词 说明 * 重复零次或更多次(>=0) + 重复一次或更多次(>=1) ? 重复零次或一次 [0,1] {n} 重复n次 (=n) {n,} 重复n次或更多次 (>=n) {n,m} 重复n到m次 [n,m] -
预定义类
预定义类指的是 某些常见模式的简写方式。
预定义类 说明 \d 匹配0-9之间的任意数字,相当于[0-9] \D 匹配所有0-9之外的字符,相当于 [^0-9]
\w 匹配任意的字母,数字和下划线,相当于[A-Za-z0-9_] \W 匹配除字母,数字和下划线,相当于 [^A-Za-z0-9_]
\s 匹配空格(包括换行符,制表符,空格符等等),相当于[\t\r\n\v\f] \S 匹配非空格的字符,相当于 [^\t\r\n\v\f]
案例
- 验证用户名
功能需求:
- 如果用户输入合法,则后面提示信息为:用户名合法,并且颜色为绿色
- 如果用户输入不合法,则后面提示信息为:用户名不符合规范,并且颜色为红色
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
span {
color: gray;
font-size: 14px;
}
.right {
color: green;
}
.wrong {
color: red;
}
</style>
</head>
<body>
<input type="text" class="username"><span>请输入用户名</span>
<script type="text/javascript">
var reg = /^[a-zA-Z0-9_-]{6,16}$/;
var username = document.querySelector('.username');
var span = document.querySelector('span');
// 失去焦点事件
username.onblur = function() {
if (reg.test(this.value)) {
// 输入的值符合正则规范
// console.log('输入正确');
// 给提示的span添加样式
span.className = 'right';
span.innerHTML = '用户名输入格式正确';
} else {
// console.log('输入错误');
// 给提示的span添加样式
span.className = 'wrong';
span.innerHTML = '用户名输入格式错误';
}
}
</script>
</body>
</html>
-
验证座机号码
座机号码验证:全国座机号码 两种格式:010-12345678 或者 0530-1234567
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title></title> </head> <body> <script type="text/javascript"> // 注意: // 正则里面的 或者 用 | 表示 // 正则表达式里面不能存在空格 var reg = /^\d{3}-\d{8}|^\d{4}-\d{7}$/; // 简写 var reg = /^\d{3,4}-\d{8,7}$/; </script> </body> </html>
括号总结
// 中括号 字符集合,匹配方括号中的任意字符
var reg = /^[abc]$/; //类似于 a || b || c
//大括号 量词符,里面表示重复数
var reg = /^a{3}$/; //a重复了3次
var reg = /^abc{3}$/; //abccc c重复了3次
//小括号 表示优先级
var reg = /^(abc){3}$/; //abcabcabc abc重复3次
正则表达式中的替换
replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。
stringObject.replace(regxp/substr,replacement);
-
第一个参数:被替换的字符 或者 正则表达式
-
第二个参数:替换的字符串
-
返回的是一个替换完毕的新字符串
var str = 'amy and mike'; //通过字符串替换 var newStr = str.replece('amy','joo'); //通过正则表达式替换 var newStr = str.replece(/amy/,'joo');
console.log(str); // 打印输出的str为 joo and mike
```javascript
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<textarea id="message"></textarea><button type="button">替换</button>
<div></div>
<script type="text/javascript">
// 获取多行文本框的值
var text = document.querySelector('textarea');
// 替换 按钮点击事件
var btn = document.querySelector('button');
var div = document.querySelector('div');
btn.onclick = function(){
// 在正则表达式后面加g,证明全局匹配,不加g,就只匹配替换第一个
div.innerHTML = text.value.replace(/激情|gay/g,'**');
}
</script>
</body>
</html>
正则表达式参数
/表达式/[switch]
switch(也称为修饰符),按照什么样的模式来匹配,有三种值:
- g:全局匹配
- i:忽略大小写
- gi:全局匹配 + 忽略大小写
ES6
什么是ES6?
ES的全称是ECMAScript,它是由ECMA国际标准化组织,指定的 一项脚本语言的标准化规范。
年份 | 版本 |
---|---|
2015年6月 | ES2015 |
2016年6月 | ES2016 |
2017年6月 | ES2017 |
2018年6月 | ES2018 |
…… | …… |
ES6实际上是一个泛指,泛指2015及后续版本。
为什么要使用ES6?
每次标准的诞生都意味着语言的完善,功能的强大。JavaScript语言本身也有一些令人不满意的地方。
- 变量提升特性增加了程序运行时的不可预测性
- 语法过于松散,实现相同的功能,不同的人可能会写出不同的代码
let(变量)
ES6中新增的用于声明变量的关键字。
-
let声明的变量只在所处于的块级有效
使用let关键字声明的变量具有块级作用域(就是一队大括号产生的作用域)
if (true) { let a = 10; } console.log(a); //a is not defined
块级作用域的好处是:在业务逻辑比较复杂的时候,避免内层变量覆盖外层变量,防止了循环变量,变成全局变量。
注意:使用let关键字声明的变量才具有块级作用域,使用var声明的变量不具有块级作用域。
-
不存在变量的提升
console.log(a); // a is not defined let a = 10;
-
暂时性死区
var tmp = 123; if (true) { console.log(tmp); //tmp is not defined let tmp = 456; }
const(常量)
作用:声明常量,常量就是值(内存地址)不能变化的量。
-
具有块级作用域
if (true) { const a = 10; } console.log(a); // a is not defined
-
使用const关键字声明常量时必须赋值
const PI; //Missing initializer in const declaration
-
常量赋值后,值不能修改
基本数据类型:值不能更改
const PI; PI = 3.14; //Assignment to constant variable.
复杂数据类型:数据结构内部的值可以更改,但是数据本身不能被更改
const ary = [100,200]; ary[0] = 20; // 对于复杂类型来说 里面的值是可以更改的 console.log(ary); //打印输出[20,200] ary = [1,3]; // 但是不能 重新赋值(更改了常量值的内存地址) console.log(ary); // Assignment to constant variable.
let,const的优点
优点:防止重复声明,限制修改
let:不能重复声明,变量,块级
const:不能重复声明,常量,块级
let,const,var的区别
-
使用
var
声明的变量,其作用域为 该语句所在的函数内,且存在变量提升现象。<button>1</button> <button>2</button> <button>3</button> <script type="text/javascript"> window.onload = function() { let btn = document.getElementsByTagName('button'); for (var i = 0; i < btn.length; i++) { btn[i].onclick = function() { alert(i); // 使用var关键字,点击每个按钮都会弹出3 } } // 弹出3的原因是,循环结束的条件是 3 // 事件是异步的,所以只能的到最后的索引值 } </script>
通过函数发的方式修改:
for (var i = 0; i < btn.length; i++) { (function(){ btn[i].onclick = function() { alert(i); } })(i); }
-
使用
let
声明的变量,其作用域为 该语句所在的代码块内,不存在变量的提升。<button>1</button> <button>2</button> <button>3</button> <script type="text/javascript"> window.onload = function() { // 2 将var 改为 let for (let i = 0; i < btn.length; i++) { btn[i].onclick = function() { alert(i); // 使用let关键字,点击那个按钮就弹出那个按钮的索引 } } } </script>
-
使用
const
声明的变量,在后面出现的代码中 不能在修改该常量的值。var let const 函数级作用域 块级作用域 块级作用域 变量提升 不存在变量提升 不存在变量提升 值可更改 值可更改 值不可更改
解构赋值
ES6中允许从数组中取值,按照对应位置,对变量赋值。对象也可实现解构。
数组解构
变量的值和数组的值数量是一样:
let [a,b,c] = [1,2,3];
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
不一样:
如果解析不成功,变量的值为undefined
let foo = [];
let [a,b] = [1];
console.log(a); // 1
console.log(b); // undefined
arr = [1, 2, 3];
let [a, b, c] = arr;
console.log(arr); //打印输出 [1, 2, 3]
对象解构
解构赋值
按照一定模式,从数组中或对象中提取值,将提取出来的值赋值给另外的变量。
使用变量去匹配属性:
let person = { name: 'zhangsan', age: 20};
let { name, age } = person;
console.log(name); // zahngsan
console.log(age); // 20
let person = { name: 'zhangsan', age: 20};
let { name: myName, age: myAge } = person; //myName,myAge属于别名
console.log(myName); //zhangsan
console.log(myAge); //20
注意
-
两边的结构必须一样
let {a, b, c} = [1, 2, 3]; //错误 //必须为 let {a, b, c} = {x, x, x}
-
右边必须是
合法
arr = [1, 2, 3]; let [a, b, c] = arr; console.log(arr); //打印输出 [1, 2, 3]
-
赋值和解构必须同时完成
let {a, b}; console.log({a, b} = {a: 12,b: 15}); // 错误 Missing initializer in destructuring declaration //正确写法 let {a, b} = {a: 12,b: 15}; console.log({a, b}); // 打印输出 {a: 12, b: 15}
箭头函数
ES6中新增的定义函数的方式。
- 箭头函数是用来简化函数定义语法。
() => {}
// 箭头函数的调用
// 将函数赋值给一个变量,然后通过变量名来调用
const fn = () => {
console.log(123)
}
fn(); //在控制台打印输出 123
- 函数中只有一句代码,且代码的执行结果就是返回值,可以省略大括号。
// 普通函数
function sum(num1, num2){
return num1 + num2;
}
// 箭头函数
const sum = (num1, num2) => num1 + num2;
const result = sum(2, 3);
console.log(result); // 浏览器控制台输出 5
- 如果形参只有一个,可以省略小括号。
// 普通函数
function fn(v){
return v;
}
//箭头函数
const fn = v => { alert(v); };
fn(20);
排序:
let arr = [1,4,55,9,2,0];
console.log(arr.sort()); // 打印输出 [0, 1, 2, 4, 55, 9] 他是把数值当成字符来排序的
// 普通函数
arr.sort(function(n1,n2){
return n1 - n2;
});
console.log(arr); //打印输出 [0, 1, 2, 4, 9, 55]
// 箭头函数 () => {}
arr.sort((n1,n2) => { n1 - n2; });
console.log(arr); //打印输出 [0, 1, 2, 4, 9, 55]
方法
map 映射 【一一对应】
根据分数判断评语:
let arr = [45,60,90,100];
// 通过if来判断
let arr2 = arr.map(function(item){
if (item >= 60) {
return '及格';
} else {
return '不及格';
}
});
// 通过三元表达式来判断
let arr2 = arr.map(item){
return item >= 60 ? '及格':'不及格';
}
// 箭头函数
let arr2 = arr.map(item >= item >= 60 ? '及格':'不及格');
console.log(arr); // [45, 60, 90, 100]
console.log(arr2); // ["不及格", "及格", "及格", "及格"]
reduce 缩减 【只有一个】
求总和和平均数:
let arr = [45, 60, 90, 100, 75, 67];
let result = arr.reduce(function (tmp, item, index) {
// console.log('第'+ index + ':' + tmp + ',' +item);
// 第1:45,60,第2:undefined,90,第3:undefined,100,第4:undefined,75,第5:undefined,67
return tmp + item;
});
console.log('和为:' + result); // 打印输出437
console.log('平均数为:' + result / arr.length); //平均数为:72.83333333333333
平均数:
let arr = [45, 60, 90, 100, 75, 67];
let result = arr.reduce(function (tmp, item, index) {
if(index == arr.length -1){ //最后一次
return (tmp + item)/arr.length;
} else {
return tmp + item;
}
});
console.log(result); // 打印输出72.83333333333333
filter 过滤
筛选偶数:
let arr = [45, 60, 90, 100, 75, 67];
// 1 通过if判断来筛选
let newArry = arr.filter(item => {
if(item % 2 === 1){
return false;
} else {
return true;
}
});
// 2 通过三元表达式来筛选
let newArry = arr.filter(item => item % 2 === 0);
console.log(newArry); //[60, 90, 100]
forEach 遍历
let arr = [45, 60, 90, 100, 75, 67];
// 第0个值是45,第1个值是60,第2个值是90,第3个值是100,第4个值是75,第5个值是67
arr.forEach((item, index) => console.log('第' + index + '个值是' + item));
// 通过字符串模板(反单引号)来遍历
arr.forEach((item, index) => console.log(`第${index}个值是${item}`));
箭头函数中的this指向
箭头函数不绑定 this 关键字,箭头函数中的this,指向的是 函数定义位置的上下文this。
箭头函数被定义在哪儿,this关键字就指向哪儿。
箭头函数不绑定this,箭头函数没有自己的this关键字,如果在箭头函数中使用this,this关键字将指向箭头珊瑚定义位置中的this。
const obj = { name: '小陈' };
function fn () {
console.log(this); // Object
// 匿名函数
return () => {
console.log(this);// Object
}
}
// call方法可以改变函数内部的this指向
const resFn = fn.call(obj); //使用call方法调用fn函数,将函数的this指向了obj对象
resFn();
// Identifier 'json' has already been declared
// 注意: class 命名必须为以大写字母开头
class Json {
constructor(){
console.log(this); // 打印输出 Json {} 对象
this.a = 12;
this.b = 8;
this.fn = function() {
console.log(this.a); // 打印输出 12
}
this.fnn = function() {
console.log(this.b); // 打印输出 8
}
}
}
// 实例化Json类
let json = new Json();
// 调用Json里面的fn方法
json.fn();
// 调用Json里面的fnn方法
json.fnn();
箭头函数面试题
对象是不能产生作用域的
var obj = {
age: 20,
// 箭头函数没有this
say: () => {
console.log(this.age); //打印输出undefined
}
}
// obj是一个对象,不能产生作用域,所以箭头函数实际上被定义在全局作用域下,所以调用时,this指向的window,window没有age属性,所以打印输出的是undefined
obj.say();
剩余参数(参数展开/扩展运算符)
参数展开:收集剩余参数,展开信息。
剩余参数语法允许我们将一个不定量的参数表示为一个数组。
当函数实参大于新参时,可以把大于的实参放在数组中。
function sum(first, ...args){
console.log(first); // 10
console.log(args); // [20,30]
}
sum(10, 20, 30);
计算所传值的和:
const sum = (...args) => {
let total = 0;
//args.forEach(item => {
// total += item;
//});
args.forEach(item => total += item);
//将计算的值返回回去
return total;
};
sum(10, 20);
sum(10, 20, 30);
let are = [14, 12, 11];
function show(a, b, c){
console.log(a + b + c);
}
show(are); // 打印输出 14,12,11undefinedundefined ,相当于只传了一个参数
show(...are); // 打印输出 37
json的合并:
let json = {a: 12, b: 15};
let json2 = {
...json,
c: 20
}
console.log(json2);
剩余参数和解构配合使用
剩余参数和解构配合使用:
let students = ['yanyan' , 'meimei', 'juanjuan'];
let [s1,...s2] = students;
console.log(s1); // 'yanyan'
console.log(s2);` // ['meimei', 'juanjuan']
JSON
JSON的标准写法:{“a”:2,“b”:3},在js中可以简写{a: 2, b:3}。
-
JSON.stringify()
-
传入json值,返回来的是字符串
var js = JSON.stringify({a: 2, b:3}); console.log(js); // 打印输出 {"a":2,"b":3}
-
-
JSON.parse()
-
将字符串解析为json
var js = JSON.parse('{"a":2,"b":3}'); console.log(js); //打印输出{a: 2, b: 3}
-
ES6的内置对象扩展
Array的扩展方法
扩展运算符(展开语法)
扩展运算符可以将数组或者对象转为用逗号分隔的参数序列。
let ary = [1, 2, 3];
//...ary //1 2 3 也就是将ary数组的中括号去掉了
console.log(...ary);
扩展运算符可以应用与 合并数组
// 方法一
let ary1 = [1, 2, 3];
let ary2 = [4, 5, 6];
let ary3 = [...ary1, ...ary2];
console.log(ary3); // 打印输出[1, 2, 3, 4, 5, 6]
// 方法二
//通过push方法,将ary2中的元素追加到ary1中
ary1.push(...ary2);
console.log(ary1); // 打印输出[1, 2, 3, 4, 5, 6]
扩展运算符可以将类数组或可遍历的对象转换为真正的数组
let d = document.getElementsByTageName('div');
d = [...d];
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<script type="text/javascript">
var d = document.getElementsByTagName('div');
// 现在的d是一个伪数组
// console.log(d);
//将伪数组转换成一个真正的数组
const ds = [...d];
console.log(ds);
// 将伪数组转换为真正的数组后,就可以使用数组的方法
ds.push('a');
console.log(ds);
</script>
</body>
</html>
构造函数方法Array.from()
将类数组或可遍历的对象转换成真正的数组。
let array = {
'0':'a',
'1':'b',
'2':'c',
'3':'d',
'4':'e',
length:5 //注意:在伪数组中一定要写length,不然遍历出来的值为[]
};
let arry2 = Array.from(array);
console.log(arry2); //["a", "b", "c", "d", "e"]
方法还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值返回数组。
let array = {
'0':'1',
'1':'2',
'2':'3',
'3':'4',
'4':'5',
length:5 //注意:在伪数组中一定要写length,不然遍历出来的值为[]
}
let arry2 = Array.from(array, item => item * 2);
console.log(arry2); // [2, 4, 6, 8, 10]
Array.find()
用于找出第一个符合条件的数组成员,如果没有找到返回undefined。
let array = [{
id: 1,
name: '小陈'
},{
id: 2,
name: '小王'
},{
id: 3,
name: '小姜'
},{
id: 4,
name: '小唐'
},{
id: 5,
name: '小黎'
},{
id: 6,
name: '小肖'
}];
// item 代表的是当前循环的值,index代表的是当前循环的索引
// let target = array.find((item, index) => item.id ==2);
let target = array.find((item) => item.id ==2);
console.log(target); //打印输出 {id: 2,name: '小王'}
Array.findIndex()
用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1。
var ary = [1, 3, 5, 7, 9];
let index = ary.findIndex((value) => value > 5);
console.log(index); //打印输出 3
Array.includes()–检测是否存在
表示某个数组是否包含给定的值,返回的是布尔值。
//js
console.log([1, 2, 3].indexOf(3) != -1); // 返回true
//es7中includes方法
[1, 2, 3].includes(2); //true
String的扩展方法
模板字符串
模板字符串
ES6新增的创建字符串的方式,使用反引号定义。
let name = `xiaochen`;
特点:
-
模板字符串可以 解析变量
let name = `xiaochen`; let sayHello = `hello,my name is ${name}`; console.log(sayHello); // 打印输出 hello,my name is xiaochen
-
模板字符串可以 换行
let result = { name: 'xiaochen', age: 20, sex: '女' } let html = ` <div> <span>${result.name}<span> <span>${result.age}<span> <span>${result.sex}<span> </div> `; console.log(html);
-
模板字符串可以 调用函数
const sayHello = function(){ return 'hello world'; } // 在变量中调用函数 let get = `${sayHello()}`; console.log(get); //打印输出 hello world
startsWith和endsWith
-
startsWith():表示是参数字符串是否在原字符串的头部,返回布尔值
-
endsWith():表示参数字符串是否在原字符串的尾部,返回布尔值
let str = 'hello world'; let r1 =str.startsWith('hello'); console.log(r1); // true let r2 = str.endsWith('world'); console.log(r2); // true
repeat()
repeat方法表示将原字符串重复n次,返回一个新的字符串
let x = 'x'.repeat(3);
console.log(x); //打印输出 xxx
Set数据结构
ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成Set数据结构。
const s = new Set();
console.log(s.size); //打印输出0,证明数据结构为空
Set构造函数可以接受一个数组作为参数,用来初始化。(数组中的值会被自动存储在Set数据结构中)
const set = new Set([1, 2, 3, 4]);
console.log(set.size); //打印输出4,证明在当前数据结构中存储了4个值
当我们使用Set,向里面传值时,会把重复的值过滤掉。
const s = new Set([1, 1, 2]);
console.log(s.size); //打印输出2
可以利用Set的这个属性做数组去重。
const s = new Set([1, 1, 2]);
console.log(s.size); //打印输出2
const ary = [...s]; // 通过扩展运算符得到新的数组
console.log(ary); //打印输出 [1, 2]
Set数据结构实例方法
-
add(value):添加某个值,返回Set结构本身
-
delete(value):删除某个值,返回一个布尔值,表示是否删除成功
-
has(value):返回一个布尔值,表示该值是否为Set的成员
-
clear():清除所有成员,没有返回值
const s = new Set(); // 向Set结构中添加值 s.add(1).add(2).add(3); console.log(s); //打印输出 {1, 2, 3} // 删除Set结构中的2 s.delete(2); console.log(s); //打印输出 {1, 3} // 判断Set结构中有没有1 返回的是布尔值 console.log(s.has(1)); // 打印输出 true // 清除Set结构中所有的值 s.clear(); console.log(s); // 打印输出 {}
从Set结构中取值(遍历)
Set结构的实例与数组一样,也拥有forEach方法,用于每个成员执行某种操作,没有返回值。
s.forEach(value => console.log(value));
const s5 = new Set(['小小','大大','跳跳','悄悄']);
s5.forEach((value) => {
console.log(value); //打印输出小小 大大 跳跳 悄悄
});
babel.js编译
用法:解决低版本浏览器不兼容es6的问题
方法1:引入js文件,在客户端编译。
缺点:会延迟,会卡,浏览器低版本不认识(babel本身就不兼容低版本浏览器)
<!-- 引入browser.min.js文件 -->
<script src="browser.min.js" charset="utf-8"></script>
<!-- 在script标签上面添加 type="text/babel" -->
<script type="text/babel">
let a = 12;
let show = n => alert(n);
show(a);
</script>
方法2:编译js文件
-
安装Node.js,初始化项目
创建package.json文件
npm init -y
2.安装babel-cli
npm i @babel/core @babel/cli @babel/preset-env -D
npm i @babel/polyfill -S
-
添加执行脚本(package.json中)
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "babel src -d dest" //通过babel来编译src这个目录,输出dest }
-
添加
.babelrc
配置文件{ "presets": [ // 声明预设 "@babel/preset-env" ] }
-
执行编译
npm run build
-
异步操作
异步操作(ajax):
优点:可以同时进行多个操作,用户体验良好
缺点:代码混乱,编写麻烦
ajax('www.baidu.com',function (data) {
ajax('www.baidu.com',function (data) {
...
},function (data) {
console.log("编译失败");
})
},function () {
console.log("编译失败");
});
同步操作:
优点:代码清晰,编写简单
缺点:一次只能进行一个操作,用户体验不好
let data1 = ajax('http://baidu.com');
...
融合异步操作和同步操作的优势:Promise,async/await
Promise–封装
注意:jquery本身就是一个Promise,有返回值then
Promise
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="styles/jquery.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<script type="text/javascript">
// 对异步操作做一个统一封装
let p = new Promise(function(resolve, reject) {
// resolve 解决/成功
// reject 拒绝/失败
$.ajax({
url: 'data/1.txt',
dataType: 'json',
success(arr) {
resolve(arr);
},
error(res) {
reject(res);
}
});
});
// 调用
p.then(function(arr) {
// 成功
console.log('成功');
console.log(arr);
},function(res) {
console.log('失败');
console.log(res);
});
</script>
</body>
</html>
Promise.all()方法
Promise.all([
$.ajax(url: 'data/1.txt', dataType: 'json');
$.ajax(url: 'data/2.txt', dataType: 'json');
$.ajax(url: 'data/3.txt', dataType: 'json');
]).then(arr => {
// 输出的是上面三个文件里面的所有内容
// 需要上面三个文件都成功,然后就执行成功操作
console.log(arr);
//可以通过解构解析,取出某一个文件中的值
[data1,data2,data3] = arr;
console.log(data2); //打印输出data2中的数据
},res => {
console.log('失败')
});
Promise.race()–竞速–谁先读取完就先用哪个
除非都失败了才走error
async/await
通俗的说async和await是函数的一种形式。
async是一种语法,使用时直接加载function的前面。
async function show(){
...
// 等待操作结束后再继续往下执行
let data = await $.ajax();
}
普通函数 和 async函数区别:
普通函数————一直执行,直到结束
async函数————能够"暂停"-“await”
// 实际上async的执行过程(解析成单个来解析的)
// 写起来更方便,但是执行还是异步的
// function show1() {
// let a = 12;
// let b = 5;
// }
// let data = await $.ajax({url: 'data/1.txt', dataType: 'json'}).then(function(){
// show2();
// });
// function show2() {
// console.log(a + b + data[0]); //打印输出 18
// }
async function show() {
let a = 12;
let b = 5;
//使用try catch来捕获错误
try{
let data = await $.ajax({url: 'data/1.txt', dataType: 'json'});
console.log(a + b + data[0]); //打印输出 18
} catch(e) {
console.log(e);
}
}
show();
ES6面向对象
语言发展历史
机器语言 -> 汇编语言 -> 低级语言(面向过程)-> 高级语言(面向对象)-> 模块系统 -> 框架 -> 系统接口(API)
ES5中的面向对象
- es5中的面向对象是一个假的面向对象
- 没有统一的写法(处于一个自我摸索的阶段)
// 没有专门的类声明方法,类是通过函数实现的
// 1.既是构造函数,又是类
// 是以函数的方式来写对象
function Person(name, age){
this.name = name;
this.age = age;
}
// 2.方法独立在类之外
// 给类添加方法
Person.prototype.show = function (){
alert(this.name);
}
// 3.没有专门的继承方法
function worker(name, age, job) {
Parson.call(this, name, age); // 4.从父类继承数据
this.job = job;
}
// 5.没有专门继承父类的方式
// 创建类的实例
worker.prototype = new Person();
worker.prototype.constructor = worker;
worker.prototype.Job = function (){
console.log(this.job);
};
let w = new worker('xiaochen', 18, '程序员');
ES6中的面向对象
统一了写法,出现了类class
,构造函数constructor
,继承extends
,超类/父类super
的声明。
继承的优点:省事儿(父类有的直接用),便于扩展(出现错误只需要修改一处)。
class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
show(){
console.log(this.name);
}
}
class work extends Person{
constructor(name, age, job){
super(name,age);
this.job = job;
}
showjob(){
console.log(this.job);
}
}
let w = new work('xiaochen', 12, '程序员');
w.showjob();
ES6模块系统
JS模块系统演化简史
没有模块 -> CMD(Common Model Definition)[民间模块系统,但不受官方支持,模块必须加载完后再执行] -> AMD(Asynchronous Module Definitious) [异步模块,模块加载自由,不受官方支持] -> 语言提供模块支持(ES6)
模块的定义和使用
浏览器现在不支持ES6的模块系统,但是为了使用模块系统,就出现了webpack
webpack.config.js中:
// 引入path包
const path = require('path');
module.exports = {
// 告诉浏览器编译的模式是什么
mode: 'production',
// 入口
entry: './index.js',
// 输出 or 编译结果
output: {
// 放在哪儿去
path: path.resolve(__dirname,'build');
// 文件名
filename: 'build.js';
}
};
使用
-
导出(export)
// 导出一个变量 export let a = 12; // 导出多个变量 let a,b,c = ...; export {a, b, c}; // 导出函数 export function show(){ } // 导出class export class Promise{} // 导出默认成员 export default a...
-
导入(import)
import * as mod from 'XXX'; // 引入所有成员 import mod from 'XXX'; // 引入default成员 import {a,b} from 'XXX'; // 引入a,b变量 import 'XXX'; //引入整个文件 let p = import('./mode'); //异步引入,使用什么就引入什么(当函数使用的)
-
webpack编译
总结
-
es7中的 幂操作 和 includes方法
// 求三的五次方 console.log(Math.pow(3, 5)); // 打印输出243 // 在es7中求三的五次方 console.log(3 ** 5); // 打印输出243
es7中的includes方法
-
es8中 async/await
,但是执行还是异步的
// function show1() {
// let a = 12;
// let b = 5;
// }
// let data = await $.ajax({url: ‘data/1.txt’, dataType: ‘json’}).then(function(){
// show2();
// });
// function show2() {
// console.log(a + b + data[0]); //打印输出 18
// }
async function show() {
let a = 12;
let b = 5;
//使用try catch来捕获错误
try{
let data = await $.ajax({url: 'data/1.txt', dataType: 'json'});
console.log(a + b + data[0]); //打印输出 18
} catch(e) {
console.log(e);
}
}
show();
## ES6面向对象
### 语言发展历史
机器语言 -> 汇编语言 -> 低级语言(面向过程)-> 高级语言(面向对象)-> 模块系统 -> 框架 -> 系统接口(API)
### ES5中的面向对象
1. es5中的面向对象是一个假的面向对象
2. 没有统一的写法(处于一个自我摸索的阶段)
```javascript
// 没有专门的类声明方法,类是通过函数实现的
// 1.既是构造函数,又是类
// 是以函数的方式来写对象
function Person(name, age){
this.name = name;
this.age = age;
}
// 2.方法独立在类之外
// 给类添加方法
Person.prototype.show = function (){
alert(this.name);
}
// 3.没有专门的继承方法
function worker(name, age, job) {
Parson.call(this, name, age); // 4.从父类继承数据
this.job = job;
}
// 5.没有专门继承父类的方式
// 创建类的实例
worker.prototype = new Person();
worker.prototype.constructor = worker;
worker.prototype.Job = function (){
console.log(this.job);
};
let w = new worker('xiaochen', 18, '程序员');
ES6中的面向对象
统一了写法,出现了类class
,构造函数constructor
,继承extends
,超类/父类super
的声明。
继承的优点:省事儿(父类有的直接用),便于扩展(出现错误只需要修改一处)。
class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
show(){
console.log(this.name);
}
}
class work extends Person{
constructor(name, age, job){
super(name,age);
this.job = job;
}
showjob(){
console.log(this.job);
}
}
let w = new work('xiaochen', 12, '程序员');
w.showjob();
ES6模块系统
JS模块系统演化简史
没有模块 -> CMD(Common Model Definition)[民间模块系统,但不受官方支持,模块必须加载完后再执行] -> AMD(Asynchronous Module Definitious) [异步模块,模块加载自由,不受官方支持] -> 语言提供模块支持(ES6)
模块的定义和使用
浏览器现在不支持ES6的模块系统,但是为了使用模块系统,就出现了webpack
webpack.config.js中:
// 引入path包
const path = require('path');
module.exports = {
// 告诉浏览器编译的模式是什么
mode: 'production',
// 入口
entry: './index.js',
// 输出 or 编译结果
output: {
// 放在哪儿去
path: path.resolve(__dirname,'build');
// 文件名
filename: 'build.js';
}
};
使用
-
导出(export)
// 导出一个变量 export let a = 12; // 导出多个变量 let a,b,c = ...; export {a, b, c}; // 导出函数 export function show(){ } // 导出class export class Promise{} // 导出默认成员 export default a...
-
导入(import)
import * as mod from 'XXX'; // 引入所有成员 import mod from 'XXX'; // 引入default成员 import {a,b} from 'XXX'; // 引入a,b变量 import 'XXX'; //引入整个文件 let p = import('./mode'); //异步引入,使用什么就引入什么(当函数使用的)
-
webpack编译
总结
-
es7中的 幂操作 和 includes方法
// 求三的五次方 console.log(Math.pow(3, 5)); // 打印输出243 // 在es7中求三的五次方 console.log(3 ** 5); // 打印输出243
es7中的includes方法
-
es8中 async/await
-
es9中 rest/spread消除异步操作,及 异步迭代,Promise.all/race/finally
学习资料推荐:https://es6.ruanyifeng.com/