文章目录

  • es6创建类
    • 类中添加共有方法
    • 类继承extends和super关键字
      • super
      • 子类继承父类的方法同时扩展自己的方法
      • 类里面的this指向
    • 面向对象tab栏
  • 构造函数和原型
    • 实例成员和静态成员
    • 构造函数原型对象prototype
      • 对象原型__proto__
      • 原型constructor构造函数
      • 构造函数、实例和原型对象三角关系
      • 原型链
      • 对象成员查找规则
      • 原型对象this指向
      • 利用原型对象扩展内置对象方法
  • 继承
    • call()
    • 利用父构造函数继承属性
    • 利用原型对象继承方法
    • 类的本质
  • 新增的方法
    • 迭代(遍历数组)forEach
    • filter
    • some
    • 查询商品案例
      • 渲染页面数据
      • 根据商品名称筛选商品
    • some和forEach的区别
    • trim
    • Object.defineProperty()定义新属性或者修改原来的属性
  • 函数进阶
    • 函数的定义和调用
      • 函数的调用方式
      • 函数内this的指向
      • 改变函数内部this指向
        • call()
        • apply
        • bind
        • call apply bind总结
  • 严格模式
    • 严格模式下this指向问题
    • 函数变化
  • 高阶函数
  • 闭包
    • 闭包应用
      • 点击li打印当前索引号
      • 3秒钟后打印
      • 计算打车价格
      • 思考题
  • 递归
    • 利用递归求阶乘
    • 利用递归求斐波那契
    • 利用递归遍历数据
    • 浅拷贝和深拷贝
      • 深拷贝
  • 正则表达式
    • 正则表达式在javascript中的使用
      • 测试正则表达式 test() 返回true false
      • 正则表达式里面的特殊字符
        • 边界符
        • 字符类
        • 量词符
        • 量词重复某个模式的次数
      • 用户名验证
      • 括号总结
      • 预定义类
        • 座机号码验证
      • 表单验证
      • 正则替换

面向对象特性:封装性 继承性 多态性
面向对象的思维特点

  1. 抽取抽象对象共用的属性和行为封装成一个类(模板)
  2. 对类进行实例化,获取类的对象
    万物皆对象,对象是一个具体事物,
    对象有属性和方法
    类抽象了对象的公共部分,泛指一大类
    对象特指某一个,通过类实例化一个具体的对象

es6创建类

constructor()方法是类的构造函数,用于传递参数,返回实例对象

 // 1.创建类 class 明星类class Star {constructor(uname, age) {this.uname = unamethis.age = age}
}// 2. 利用类创建对象 new
var ldh = new Star('刘德华', 30)
var zxy = new Star('张学友')
console.log(ldh)
console.log(zxy.uname)
//Star { uname: '刘德华', age: 30 }
//张学友
  1. 通过class关键字创建类,类名首字母大写
  2. 类里的constructor函数,可以接收传递过来的参数,同时返回实例对象
  3. constructor函数只要new生成实例时,就会自动调用这个函数,如果不写这这个函数,类也会自动生成这个函数
  4. 生成实例 new不能省
  5. 创建类 类名后不加小括号,生成实例 类名后加小括号,构造函数不需要加function

类中添加共有方法

多个函数方法之间不需要添加逗号分隔

 // 1.创建类 class 明星类class Star {constructor(uname, age) {this.uname = unamethis.age = age}sing(song) {console.log(this.uname+'sing'+song)}
}// 2. 利用类创建对象 new
var ldh = new Star('刘德华', 30)
var zxy = new Star('张学友')
console.log(ldh)
console.log(zxy.uname)
ldh.sing('冰雨')

类继承extends和super关键字

class Father {constructor(x, y) {this.x = xthis.y = y}sum() {console.log(this.x + this.y)}money() {console.log(100)}
}class Son extends Father{constructor(x, y) {super(x, y); //调用了父类中的构造函数}
}var son = new Son(1, 3)
var son2 = new Son(11, 3)
son.money() //100
son.sum() //4
son2.sum()//14

super

class Father {say() {return '我是爸爸'}
}class Son extends Father {say() {// console.log('我是二字')console.log(super.say()+'的儿子')// 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调用父类的构造函数// super必须在子类this之前调用super(x, y)this. x = x this.y = y}subtract() {console.log(this.x - this.y)}
}var son = new Son(10, 5)
son.sum() // 15
son.subtract() // 5

使用类的注意点:
在es6中类没有变量提升,所以必须先定义类,才能通过类实例化对象
类里面共有的属性和方法一定要加this使用

类里面的this指向

constructor里面的this指向的是 创建的实例对象

方法里面的this指向这个方法的调用者

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><button>点击</button><script>var that;class Star {constructor(uname, age) {// constructor里面的this指向的是 创建的实例对象that = thisthis.uname = unamethis.age = agethis.btn = document.querySelector('button')// 这里的sing是btn调用的 指向btn btn.uname为undefined 可以把this改为thatthis.btn.onclick = this.sing}sing() {// 解决方法 把这里的this改为that// console.log(this.uname)console.log(that.uname)}}var ldh = new Star('刘德华')console.log(that === ldh)</script>
</body>
</html>

面向对象tab栏

功能需求:

  1. 点击tab栏,可以切换效果
  2. 点击+号,可以添加tab项和内容项
  3. 点击x号,可以删除当前的tab项和内容项
  4. 双击tab项文字或者内容项文字,可以修改里面的内容
    抽取对象 tab对象
    该对象具有切换功能
    该对象具有添加功能
    改对象具有删除功能
    该对象具有修改功能

添加功能:点击+可以实现添加新的选项卡和内容
5. 创建新的选项卡li 和新的内容section
6. 把创建的两个元素追加到对应的父元素中

以前的做法:动态创建元素createElement,但是元素里面内容较多,需要innerHTML赋值 ,在appendChild追加到父元素里面
现在高级做法:利用insertAdjacentHTML()可以直接把字符串格式元素添加到父元素中

删除功能;
点击x可以删除当前的li选项卡和当前的section
x是没有索引号的,但是它的父亲li有索引号,这个索引号正是我们想要的索引号
所以核心思路是: 点击x号可以删除这个索引号对应的li和section

编辑功能:
双击选项卡li或者section里面的文字,可以实现修改功能
双击事件:ondblclick
如果双击文字,会默认选定文字,此时需要双击禁止选中文字
window.getSelection?window.getSelection().removeAllRanges(): document.selectionempty()
核心思路:双击文字的时候,在里面生成一个文本框,当失去焦点或者按下回车 然后把文本框的值给原先的元素即可
代码

构造函数和原型

在es6之前,对象不是基于类创建的,而是构造函数这种特殊函数来定义对象和它们的特征
创建对象三种方式:

  1. new Objext()创建对象
  2. 对象字面量
  3. 构造函数
    new在执行时会做四件事
  4. 在内存中创建一个新的对象
  5. 让this指向这个新的对象
  6. 执行构造函数里面的代码,给这个新对象添加属性和方法
  7. 返回这个新对象(所以构造函数里面不需要return)

实例成员和静态成员

// 构造函数中的属性和方法称为成员 成员可以添加
function Star(uname, age){this.uname = unamethis.age = agethis.sing = function(){console.log('唱歌')}
}var ldh = new Star('刘德华',18)
var zxy = new Star('张学友',10)
// 实例成员就是构造函数内部通过this添加的成员 uname age sing就是实例成员
// 实例成员只能通过实例化的对象来访问
console.log(ldh.uname)ldh.sing()
console.log(Star.uname) // 不可以通过构造函数来访问实例成员
// 静态成员 在构造函数本身上添加的成员
Star.sex = '男' // 此时sex是静态成员 只能通过构造函数
console.log(ldh.sing() === zxy.sing()) // false

构造函数原型对象prototype

构造函数方法很好用,但是存在浪费内存的问题
我们希望所有的对象使用同一个函数,这样就比较节省内存,但是应该如何做
构造函数通过原型分配的函数是所有对象所共享的
每一个构造函数都有一个prototype对象
我们可以把那些不变的方法,直接定义在prototyoe对象上,这样所有的对象的实例就可以共享这些方法

// 构造函数中的属性和方法称为成员 成员可以添加
function Star(uname, age){this.uname = unamethis.age = age// this.sing = function(){//   console.log('唱歌')// }
}
Star.prototype.sing = function() {console.log('我们唱歌')
}var ldh = new Star('刘德华',18)
var zxy = new Star('张学友', 30)
ldh.sing()
zxy.sing()
console.log(ldh.sing() === zxy.sing()) // true

原型是什么:
一个对象,我们也称为prototype为原型对象
原型的作用是什么:
共享方法
一般情况下,我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象上

对象原型__proto__

对象身上系统自动添加一个__proto__指向我们的构造函数的原型对象

console.log(ldh.__proto__ === Star.prototype) // true

方法的查找规则:
说先看ldh实例对象身上是否有sing方法,如果有就执行这个对象上的sing
如果没有,因为__proto__的存在,就去构造函数原型对象prototype身上去查找sing这个方法

原型constructor构造函数

对象原型__proto__和构造函数prototype原型对象里面都有一个属性constructor属性,
constructor称为构造函数,因为它指回构造函数本身
constructor主要用于记录该对象引用与哪个构造函数,他可以让原型对象重新指向原来的构造函数

很多情况下,我们需要手动的利用这个属性指回原来的构造函数
如下

Star.prototype = {//如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数constructor: Star,sing: function() {},movie: function() {}
}

构造函数、实例和原型对象三角关系

原型链

function Star(uname, age) {this.uname = unamethis.age = age
}
Star.prototype.sing = function() {console.log('我会唱歌')
}
var ldh = new Star('ldhk', 33)
// 只要是对象就有__proto__原型 指向原型对象
console.log(Star.prototype)
console.log(Star.prototype.__proto__ === Object.prototype)
// Star原型对象里面的__proto__原型指向的是Object.prototype
console.log(Object.prototype.__proto__)
// Object.prototyp原型对象里面的__proto__原型 指向为null

对象成员查找规则

  1. 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
  2. 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
  3. 如果还没有就查找原型对象的原型(Object的原型对象)
  4. 依次类推一直找到Object为止(null)
  5. __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说是一条路线

原型对象this指向

function Star(uname, age) {this.uname = unamethis.age = age
}var that;
Star.prototype.sing = function() {console.log('我会唱歌')that = this
}var ldh = new Star('李德华', 39)
// 1. 在构造函数中,里面的this指向的是对象实例 this
ldh.sing()
console.log(that === ldh) // true// 2.原型对象函数里面的this指向的是实例对象 ldh
// this一般指向调用者

利用原型对象扩展内置对象方法

// 原型对象的应用 扩展内置对象方法
// console.log(Array.prototype)Array.prototype.sum = function() {var sum = 0for(var i = 0; i < this.length; i ++) {sum += this[i]}return sum
}var arr = [1,2,3]
console.log(arr.sum())//6

注意:数组和字符串内置对象不能给原型对象覆盖操作Array.prototype= {}只能是Array.prototype.xxx = function(){}的方式

继承

es6之前并没有提供extends继承。可以通过构造函数+原型对象模拟实现继承,被称为组合继承。

call()

调用这个函数,并且修改函数运行时的this指向
fun.call(thisArg,arg1,arg2,,,,)
this.Arg:当前调用函数this的指向对象

function fn() {console.log('我想要喝水')console.log(this)
}
var o = {name: 'andy'
}
// 1. call()可以调用函数
fn.call()
// 2. call()可以改变这个函数的this指向 此时这个函数的this就指向了o这个对象
fn.call(o)

利用父构造函数继承属性

// 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname, age) {// this指向父构造函数的对象实例this.uname = unamethis.age = age
}
// 2. 子构造函数
function Son(uname, age, score) {// this指向子构造函数的对象实例// 调用父构造函数 但是要把父构造函数中的this修改为子中的thisFather.call(this, uname, age)this.score = score
}var son = new Son('ldh', 22, 100)
console.log(son)

利用原型对象继承方法

// 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname, age) {// this指向父构造函数的对象实例this.uname = unamethis.age = age
}Father.prototype.money = function() {console.log(10000)
}
// 2. 子构造函数
function Son(uname, age, score) {// this指向子构造函数的对象实例// 调用父构造函数 但是要把父构造函数中的this修改为子中的thisFather.call(this, uname, age)this.score = score
}
// Son.prototype = Father.prototype 直接赋值有问题,修改了子 父也变了
Son.prototype = new Father()
// 如果利用对象的形式修改了原型对象 要记得利用constructor指回原来的构造函数
Son.prototype.constructor = Son
Son.prototype.exam = function() {console.log('考试')
}var son = new Son('ldh', 22, 100)
console.log(son)

类的本质

es6之前通过 构造函数+ 原型实现面向对象编程
es6通过类实现面向对象编程

  1. class的本质还是function
    类的本质还是一个函数,可以简单的认为 类就是构造函数的另外一种写法

构造函数有原型对象prototype
构造函数有原型对象prototype 里面的constructor指向构造函数本身
构造函数可以通过原型对象添加方法
构造函数创建的实例对象有__proto__原型 指向构造函数的原型对象

所以es6的类其实就是构造函数的语法糖

新增的方法

迭代(遍历数组)forEach

forEach() \ map() filter() some() every()
array.forEach(functin(currentValue, index, arr))
currentValue: 数组当前项的值
index:数组当前项的索引
arr:数组对象本身

var arr = [1,2,3]
var sum = 0
arr.forEach(function(currentValue, index, array) {console.log('每个数组元素' + currentValue)console.log('每个数组元素的索引' + index)console.log('数组' + array)sum += currentValue
})

filter

array.filter(function(currentValue, index, arr))
filter()方法创建一个新的数组 新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组
注意:它直接返回一个新数组
currentValue:数组的当前项的值
index:数组当前项的缩影
arr:数组对象本身

var arr = [12, 66, 4, 88]
var newArr = arr.filter(function(currentValue, index) {return currentValue > 20
})
console.log(newArr)//[66, 88]

some

array.some(function(currentValue, index, arr))
some方法用于监测数组中的元素是否满足指定条件
就是查找数组中是否有满足条件的元素
注意:它返回值是布尔值,如果查找到这个元素就返回true,如果查找不到就返回false
如果找到第一个满足条件的元素,则终止循环,不再继续查找
currentValue:数组当前项的值
index:数组当前索引
arr: 数组对象本身

// some 查找数组中是否有满足条件的元素
var arr = [10, 30, 4]
var flag = arr.some(function(value) {return value>20
})
console.log(flag)//true

filter也是查找满足条件的元素 返回的是一个数组,而且是把所有满足条件的元素都返回回来
some也是查找满足条件的元素 返回的是一个布尔值,如果查找到第一个满足条件的元素就终止循环
map和forEach相似 every()和some()相似

查询商品案例

渲染页面数据

// 利用新增数组方法操作数据var data = [{id: 1,pname: '小米',price: 3999},{id: 2,pname: 'oppo',price: 999},{id: 3,pname: '荣耀',price: 1299},{id: 4,pname: '华为',price: 1999}]// 1.获取相应的元素var tbody = document.querySelector('tbody')// 2. 把数据渲染到页面中data.forEach(function(currentValue, index) {var tr = document.createElement('tr')tr.innerHTML = `<td>${currentValue.id}</td><td>${currentValue.pname}</td><td>${currentValue.price}</td>`tbody.appendChild(tr)})``
### 根据价格筛选商品```js
// 利用新增数组方法操作数据var data = [{id: 1,pname: '小米',price: 3999},{id: 2,pname: 'oppo',price: 999},{id: 3,pname: '荣耀',price: 1299},{id: 4,pname: '华为',price: 1999}]// 1.获取相应的元素var tbody = document.querySelector('tbody')var search_price = document.querySelector('.search-price')var start = document.querySelector('.start')var end = document.querySelector('.end')setData(data)// 2. 把数据渲染到页面中function setData(myData) {// 先清空原来的tbody里面的数据tbody.innerHTML = ''myData.forEach(function(currentValue, index) {var tr = document.createElement('tr')tr.innerHTML = `<td>${currentValue.id}</td><td>${currentValue.pname}</td><td>${currentValue.price}</td>`tbody.appendChild(tr)})}// 3. 根据价格查询商品// 当我们点击了按钮,就可以根据我们的商品价格去筛选数组里面的对象search_price.addEventListener('click', function() {var newData = data.filter(function(currentValue) {var min = start.value var max = end.valuereturn currentValue.price >= min && currentValue.price <= max})setData(newData)})

根据商品名称筛选商品

// 4.根据商品名称查找商品// 如果查询数组中唯一的元素,用some方法更适合,因为它找到这个元素,就不在进行循环,效率更高search_pro.addEventListener('click', function() {var arr = []data.some(function(value) {if(value.pname === product.value) {arr.push(value)return true}})// 把拿到的数据 渲染到页面当中setData(arr)})

代码

some和forEach的区别

forEach里面的return不会终止迭代
some里面遇到return true就是终止遍历,迭代效率更高

trim

trim()方法会从一个字符串的两端删除空白字符
str.trim()
不影响字符串本身 返回的是一个新的字符串

Object.defineProperty()定义新属性或者修改原来的属性

Object.defineProperty(obj, prop, descriptor)
obj:必须,目标对象
prop: 必需,需定义或修改的属性的名字
desciptor:必须,目标属性所拥有的特性
第三个参数decriptor说明:以对象的形式书写
value:设置属性的值,默认为undefined
writable:值是否可以重写, ture|false, 默认为false
enumerable: 目标属性是否可以被枚举, ture|false, 默认为false
configurable: 目标属性是否可以被删除或是否可以再次修改特性 ture|false, 默认为false

函数进阶

函数的定义和调用

命名函数function fn()
匿名函数var fun = function(){}

new Function('参数1', '参数2', '函数体')

所有函数都是Function的实例(对象)

函数的调用方式

// 1. 普通函数
function fn() {console.log('ccc')
}
fn()
fn.call()// 2. 对象方法
var o = {sayHi: function() {console.log('obj')}
}
o.sayHi()// 3. 构造函数
function Star() {}
new Star()
// 4.绑定事件函数
// btn.onclick = function() {}//点击按钮就调用
// 5.定时器函数
setInterval(function(){}, 1000)//自动1秒调用一次
// 6.立即执行函数
(function(){console.log('ccc')
})()
//立即执行函数是自动调用

函数内this的指向

this的执行,是当调用函数的时候确定的,调用的方式的不同,决定了this指向的不同
一般指向调用者

调用方式 this指向
普通函数调用 window
构造函数调用 实例对象 原型对象里面的方法也指向实例对象
对象方法调用 该方法所属对象
事件绑定方法 绑定事件对象
定时器函数 window
立即执行函数 window

改变函数内部this指向

bind() call() apply()

call()

// call()
var o = {name: 'andy'
}function fn(a, b) {console.log(this)console.log(a + b)
}fn.call(o, 1, 3)
// call可以调用函数 可以改变函数内this指向
function Father(uname, age, sex) {this.uname = unamethis.age = agethis.sex = sex
}
function Son(uname, age, sex) {Father.call(this, uname, age, sex)
}
var son = new Son('ldh', 39, '男')
console.log(son)
//{ name: 'andy' }
//4
//Son { uname: 'ldh', age: 39, sex: '男' }

apply

apply()方法调用一个函数,简单理解为调用函数的方式,但是它可以改变函数this指向
fun.apply(thisArg, [argsArray[)
this.Arg: 在fun函数运行时指定的this值
argsArray: 传递的值,必须包含咋数组里面

返回值就是函数的返回值,因为它就是调用函数

var o = {name: 'andy'
}
function fn(arr) {console.log(this)console.log(arr)
}fn.apply(o, ['blue'])
// apply的主要应用 比如说可以利用apply借助数学内置对象求最大值
var arr = [1, 66, 3, 99, 19]
var max = Math.max.apply(Math, arr)
var min = Math.min.apply(Math, arr)
console.log(max, min)
-----------------
运行结果:
{ name: 'andy' }
blue
99 1

bind

bind()方法不会调用函数,但是能改变函数内部this指向
fun.bind(thisArg, arg1,arg2,...)
thisArg: 在fun函数运行时候指定的this值
arg1,arg2:传递的其他参数
返回由指定的this值和初始化参数改造的原函数拷贝

var o = {name: 'andy'
}
function fn(a, b) {console.log(this)console.log(a + b)
}var f = fn.bind(o, 1, 3)
f()
// 1, 不会调用原来的函数 可以改变原来函数内部的this指向
// 2. 返回的是原函数改变this之后产生的新函数
运行结果:
{ name: 'andy' }
4
<body><button>按钮</button><script>// 3. 如果有的函数我们不要立即调用 但是又想要改变这个函数内部的this指向此时用bind// 案例: 一个按钮,点击之后,就禁用这个按钮,3秒钟之后开启这个按钮var btn = document.querySelector('button')btn.onclick = function() {this.disabled = true// var that = thissetTimeout( function() {// this.disabled = false // 定时器函数里面的this指向的是window// that.disabled = falsethis.disabled = false}.bind(this), 3000)//这个this指向的是btn}</script>
</body>

call apply bind总结

相同点:
都可以改变函数内部的this指向
区别点:

  1. call和apply会调用函数,并且改变函数内部this指向
  2. call和apply传递的参数不一样,call传递参数arg1, arg2形式,apply必须数组形式
  3. bind不会调用函数,返回一个新的函数
    主要应用场景:
  4. call经常做继承
  5. apply经常跟数组有关系,比如借助数学对象实现数组最大值最小值
  6. bind不调用函数,但是还想改变this指向时使用,比如改变定时器内部的this指向

严格模式

严格模式中的变化
变量名必须先声明再使用
不能随意删除已经声明好的变量

严格模式下this指向问题

  1. 以前在全局作用域中的this指向window对象
  2. 严格模式下全局作用域中函数中的this是undefined
  3. 以前构造函数时不加new也可以调用,当普通函数,this指向全局对象
  4. 严格模式下,如果构造函数不加new调用,this会报错
  5. new实例化的构造函数指向创建的对象实例
  6. 定时器this还是指向window
  7. 事件 对象还是调用者

函数变化

参考mdn

高阶函数

高阶函数时对其他函数进行操作的函数,它接收函数作为参数将函数作为返回值输出
函数也是一种数据类型,同样可以作为参数,传递给 另一个参数使用,最典型的就是回调函数

function fn(a, b, callback)  {console.log(a + b)callback && callback()
}
fn(1, 3, function(){console.log('我是最后调用的')
})
运行结果:
4
我是最后调用的

闭包

闭包指有权访问另一个函数作用域中变量函数
简单理解就是,一个作用域可以访问另外一个函数内部的局部变量
闭包的主要作用:延伸了变量的作用范围

闭包应用

点击li打印当前索引号

<body><ul class="nav"><li>榴莲</li><li>臭豆腐</li><li>螺蛳粉</li><li>鲱鱼罐头</li></ul><script>var lis = document.querySelector('.nav').querySelectorAll('li')// 1. 利用动态添加属性的方式// for(var i = 0; i < lis.length; i++) {//   // 异步任务 点击之后才触发//   lis[i].index = i//   lis[i].onclick = function() {//     console.log(this.index)//   }// }// 2. 利用闭包的方式for(var i = 0; i < lis.length; i ++) {// 利用for循环创建了4个立即执行函数(function(j){// console.log(j)lis[i].onclick = function() {console.log(j)}})(i)}</script>
</body>

3秒钟后打印

<body><ul class="nav"><li>榴莲</li><li>臭豆腐</li><li>螺蛳粉</li><li>鲱鱼罐头</li></ul><script>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>
</body>

计算打车价格


// 闭包应用-计算打车价格
// 打车起步价13(3公里内) 之后每多一公里增加5块钱 用户输入公里数就可以计算打车价格
// 如果有拥堵情况 总价格多收取10块钱拥堵费
var car = (function () {var start = 13; //起步价 局部变量var total = 0; //局部变量return {price: function (n) {if (n <= 3) {total = start} else {total = start + (n - 3) * 5}return total},yd: function (flag) {return flag ? total + 10 : total}}
})()console.log(car.price(5))
console.log(car.yd(true))
console.log(car.price(1))

思考题

        // 思考题 1:var name = "The Window";var object = {name: "My Object",getNameFunc: function() {return function() {return this.name;};}};console.log(object.getNameFunc()())var f = object.getNameFunc();// 类似于var f = function() {return this.name;}f();// 思考题 2:// var name = "The Window";  // var object = {    //     name: "My Object",//     getNameFunc: function() {//         var that = this;//         return function() {//             return that.name;//         };//     }// };// console.log(object.getNameFunc()())

递归

如果一个函数在内部可以调用其本身,那么这个函数就是递归函数

利用递归求阶乘

function fn(n) {if(n === 0 || n === 1) return 1else return fn(n - 1) * n
}
console.log(fn(5)) // 120

利用递归求斐波那契

// 1 1 2 3 5 8 13 21
function fib(n) {if(n === 1 || n === 2) return 1else return fib(n - 1) + fib (n - 2)
}
console.log(fib(8))

利用递归遍历数据

var data = [{id: 1,name: '家电',goods: [{id: 11,gname: '冰箱',goods: [{id: 111,gname: '海尔'},{id: 222,gname: '格力'}]},{id: 12,gname: '洗衣机'}]},{id: 2,name: '服饰'}
]// 输入id号,就可以返回的数据对象
// 1. 利用forEach去遍历里面每一个对象
function getID(data, id) {var o = {}data.forEach(function(item) {// console.log(item) // 2个对象if(item.id === id) {// console.log(item)o = item// 想要得到里层的数据 11 12要利用递归函数// 里面要有goods数组 并且数组长度不为0}else if(item.goods && item.goods.length > 0) {o = getID(item.goods, id)}})return o
}
console.log(getID(data, 1))
console.log(getID(data, 11))
console.log(getID(data, 111))

浅拷贝和深拷贝

浅拷贝只是拷贝一层,更深层次对象级别只拷贝了引用
深拷贝拷贝多层,每一级别的数据都会拷贝
Object.assign(target,…sources) es6新增方法可以浅拷贝

var obj = {id: 1,name: 'andy',msg: {age: 18,}
}var o = {}
for (var k in obj) {o[k] = obj[k]
}
console.log(o)
o.msg.age = 20
// 修改后 也影响了obj里面的数据 浅拷贝更深层次对象只拷贝了地址
console.log(o)
console.log(obj)
var obj = {id: 1,name: 'andy',msg: {age: 18,}
}var o = {}
Object.assign(o, obj)
console.log(o)

深拷贝

var obj = {id: 1,name: 'andy',msg: {age: 18},color: ['pink', 'red']
}var o = {}
// 封装函数
function deepCopy(newobj,oldobj) {for(var k in oldobj) {//     判断我们的属性值属于哪种类型
//     1.获取值 oldobj[k]var item = oldobj[k]
//     2. 判断这个值是否是数组if(item instanceof Array) {newobj[k] = []deepCopy(newobj[k], item)}else if(item instanceof Object) {//      3. 判断这个值是否是对象newobj[k] = {}deepCopy(newobj[k], item)}else {//       4. 属于简单数据类型newobj[k] = item}}
}deepCopy(o, obj)
console.log(o)

正则表达式

正则表达式:是用于匹配字符串中字符组合的模式。
在javascript中,正则表达式也是对象

  1. 验证表单
  2. 过滤页面中的一些敏感词
  3. 获取字符串中的特定部分
    实际开发中,一般都是直接复制写好的正则表达式

正则表达式在javascript中的使用

两种方式创建正则表单式

var regexp = new RegExp(/123/)
console.log(regexp)// 2. 利用字面量创建
var rg = /123/

测试正则表达式 test() 返回true false

regexObj.text(str)
regexObj是写的是正则表达式
str是我们要测试的文本

var rg = /123/
console.log(rg.test(123))//true
console.log(rg.test('abc'))//false

正则表达式里面的特殊字符

可以参考MDN官网

边界符

// 边界符 ^ $
// ^开始 $结尾
// 正则表达式不需要加引号 无论是数字还是字符串
var rg = /abc/
console.log(rg.test('abc')) // true
console.log(rg.test('aabc')) // true
var reg = /^abc/console.log(reg.test('aabc')) // false
var regx = /^abc$/
console.log(regx.test('abcd')) // false

字符类

表示有一系列字符可供选择,只要匹配其中一个就可以了[]

var rg = /[abc]/ // 只要包含有a 或者有b 或者c 都返回true
console.log(rg.test('andy')) //true
console.log(rg.test('babay'))// truevar rgx = /^[abc]$/  // 三选一 只有是a 或者b  或者c
console.log(rgx.test('a')) // true
console.log(rgx.test('ab')) // falsevar rg2 = /^[a-z]$/  // 26个英文字母任何一个字母 都返回true
console.log(rg2.test('a')) // true

// 字符组合
var reg = /^[a-zA-Z0-9_-]$/ // 26个英文字母和任何数字 都返回true
console.log(reg.test('9')) // true
console.log(reg.test('_')) //true// 如果中括号里面有^ 表示取反的意思 千万不要和边界符^混淆
var reg2 = /^[^a-zA-Z0-9_-]$/
console.log(reg2.test('a'))  // false

量词符

量词符用来设定某个模式出现的次数

量词 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或者是更多次
{n, m} 重复n到m次
var reg = /^a*$/
console.log(reg.test(''))  // true
console.log(reg.test('aaa')) // truevar reg2 = /^a+$/
console.log(reg2.test('')) // false
console.log(reg2.test('aaaa')) //truevar reg3 = /^a{3}$/
console.log(reg3.test('aaa'))  // true

量词重复某个模式的次数


// 量词是设定某个模式出现的次数
var reg = /^[a-zA-Z0-9_-]{6,16}$/console.log(reg.test('baby13')) // true
console.log(reg.test('baby')) // false

用户名验证

功能需求:

  1. 如果用户名输入合法,则后面提示信息为:用户名合法并且颜色为绿色
  2. 如果用户名不合法,则后面提示信息为:用户名不符合规范 并且颜色红色

分析;
3. 用户名只能为英文字母,数字,下划线或者短横线组成,并且用户名长度为6-16位
4. 首先准备好这种正则表达式模式
5. 当表单失去焦点时开始验证
6. 如果符合正则规范,则让后面的span标签添加right类
7. 如果不符合正则规范,则让后面的span标签添加wrong类

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>JS Bin</title>
</head>
<body>
<input type="text" class="uname"><span>请输入用户名</span>
</body>
</html>
.right{color: green;
}.wrong {color: red;
}
let uname = document.querySelector('.uname')
let span = document.querySelector('span')
let reg = /^[a-zA-Z0-9_-]{6,16}$/
uname.onblur = function() {if(reg.test(this.value)) {span.classList.add('right')span.innerHTML = '用户名格式输入正确'}else {span.classList.add('wrong')span.innerHTML = '用户名格式输入错误'}
}

括号总结

// 中括号 字符集合 匹配方括号中的任意字符
var reg = /^[abc]$/// 大括号 量词符 里面表示重复次数
var reg = /^abc{3}$/ // 它只是让c重复三次 abccc// 小括号 表示优先级
var reg = /^(abc){3}$/ // 它是让abc 重复三次 abcabcabc

在线测试

预定义类

预定义类指的是某些常见模式的简写方式

预定类 说明
\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]

座机号码验证

// 座机号码验证: 全国座机号码
// 两种格式: 010-12345678  或者 0530-1234567var reg = /^\d{3,4}-\d{7,8}$/

表单验证

正则替换

replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式
stringObject.replace(regexp/substr, replacement)

  1. 第一个参数: 被替换的字符串或正则表达式
  2. 第二个参数: 替换为的字符串
    返回值是一个替换完毕的新的字符串
var str = 'andyAndbaby'
var newStr = str.replace('andy', 'baby')
console.log(newStr) //"babyAndbaby"

正则表达式参数
/表达式/[switch]
switch也称为修饰符 按照什么样的模式来匹配 有三种值:
g: 全局匹配
i: 忽略大小写
gi: 全局匹配+忽略大小写

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>JS Bin</title>
</head>
<body><textarea name="message" id="message" cols="30" rows="10" ></textarea><button>提交</button><div></div>
</body>
</html>
var text = document.querySelector('#message')
var btn = document.querySelector('button')
var div = document.querySelector('div')
btn.onclick = function() {div.innerHTML = text.value.replace(/激情|gay/g, '**')
}

javascript进阶面向对象ES6相关推荐

  1. JavaScript进阶面向对象ES6整合篇

    整合篇整体内容比较多,详细点可以查询目录 文章目录 一.JavaScript面向对象 1.面向对象编程介绍 2.ES6中的类和对象 3.类的继承 4.案例:面向对象案例 二.构造函数和原型 1. 构造 ...

  2. JavaScript 进阶面向对象ES6

    ES6类的本质 ES6之前 → 通过 构造函数 + 原型 实现面向对象编程 构造函数有原型对象 prototype prototype里有 constructor 指向构造函数本身 可以通过原型对象添 ...

  3. JavaScript进阶(四)

    JavaScript进阶(四) 2019版黑马程序员javaScript进阶面向对象ES6 122集教程,哔哩哔哩链接:https://www.bilibili.com/video/BV1Kt411w ...

  4. JavaScript进阶(二)

    JavaScript进阶(二) 2019版黑马程序员javaScript进阶面向对象ES6 122集教程,哔哩哔哩链接:https://www.bilibili.com/video/BV1Kt411w ...

  5. JavaScript进阶(三)

    JavaScript进阶(三) 2019版黑马程序员javaScript进阶面向对象ES6 122集教程,哔哩哔哩链接:https://www.bilibili.com/video/BV1Kt411w ...

  6. JavaScript进阶(一)

    JavaScript进阶(一) 2019版黑马程序员javaScript进阶面向对象ES6 122集教程,哔哩哔哩链接:https://www.bilibili.com/video/BV1Kt411w ...

  7. 前端学习笔记——JavaScript进阶

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.JavaScript 面向对象 1. 面向对象编程介绍 1.1 两大编程思想 1.2 面向过程编程 1.3 面向对 ...

  8. JavaScript进阶-高级特性及ES6

    任务 对象的扩展 let和const Object.keys() for...of 扩展运算符 Set 和 Map 模版字符串 默认参数 rest参数 箭头函数 解构赋值 对象的扩展 方法的简写 // ...

  9. JavaScript 进阶教程(1)--面向对象编程

    目录 1 学习目标 2 面向对象介绍 2.1 什么是对象 2.2 什么是面向对象 2.3 JavaScript 中面向对象的基本体现 3 JavaScript 如何创建对象 3.1 字面量方式 3.2 ...

  10. JavaScript进阶1-学习笔记

    文章目录 JavaScript进阶1 预解析 作用域 面向对象的写法 JavaScript进阶1 预解析 //预解析 //1) console.log(a); var a = 1; //解析过程 va ...

最新文章

  1. 山寨c 标准库中的getline 函数
  2. STM32 进阶教程 15 - 串口DMA收发
  3. ubuntu装jdk
  4. 分布式文件系统研究-搭建图片服务虚拟主机
  5. mega2560单片机开发_[MEGA DEAL] Ultimate Java开发和认证指南(59%折扣)
  6. tcp校验和计算校验和例子_OSI参考模型和TCP/IP参考模型
  7. python图片顶端_用python进行图片整理
  8. caffe数据集——LMDB
  9. 使用补丁修改DSDT/SSDT [DSDT/SSDT综合教程]
  10. 安装软件提示计算机管理员权限,win10安装软件需要管理员权限的处理办法|win10装软件提示error launching installer如何处理?...
  11. stm32万年历流程图_基于 STM32 RTC的万年历
  12. windows xp sp2的产品密钥
  13. 360手机如何修改服务器,360路由器手机怎么设置_手机如何设置360路由器? - 192路由网...
  14. autocad网络服务器如何安装许可证,使用网络许可选项文件的步骤
  15. Javascript错误处理——try...catch
  16. J storm战队成员_DOTA2J.Storm战队介绍-DOTA2梦幻联赛S11预选赛J.Storm战队介绍_牛游戏网攻略...
  17. wireshark 分析理解DHCP流程
  18. leaflet的引入
  19. 单点登陆(SSO)协议简介:OpenID、OAuth2、SAML
  20. html class函数,wordpress函数sanitize_html_class()用法示例

热门文章

  1. 计算机专业保研面试备考:线性代数
  2. 2013考研数学复习指南(理工类)-陈文灯
  3. Android仿高德地图打车的三段式BottomSheet
  4. 如何制作ISO镜像文件
  5. 大量带BPM的跑步歌曲/跑步音乐下载
  6. c语言公交查询系统,公交路线查询系统(基于数据结构和C语言)完整
  7. Java 6.22练习-----模拟物流快递系统程序设计
  8. 求某年某月某日是星期几公式
  9. 奖学金设计mysql_数据库设计-奖学金评定系统.doc
  10. 【顺序表】SqList *L是什么意思