[前端学习笔记]JS高级语法+ES6

本文详细探讨了JavaScript中的面向对象编程,包括ES6的类和对象、继承、构造函数和原型。此外,还介绍了ES5新增的数组、字符串和对象方法,如forEach、filter和Object.keys()。深入讲解了函数进阶概念,如this指向、高阶函数和闭包。同时,阐述了正则表达式在匹配、替换和提取方面的应用,并简要概述了ES6的关键字、解构赋值和箭头函数。

文章目录

一、面向对象

1. 编程思想
  • 面向过程编程(POP, Process-oriented programming):分析解决问题的步骤,按照步骤解决问题。

    优点:性能高,适合与硬件联系紧密的东西。
    缺点:不易维护、复用、扩展。

  • 面向对象编程(OOP, Object-oriented programming):以对象功能划分问题,由对象之间分工合作解决。

    优点:可以设计出低耦合、灵活、易维护、复用、扩展的大型系统。
    缺点:性能比面向过程低。

    面向对象三大特性:封装性、继承性、多态性。

2. ES6类和对象
  • 对象:特指一个实例化的具体的对象,由属性(特征)和方法(行为)组成。

  • 类:泛指某一大类,抽象化对象的公共属性和方法封装成一个类。

    // 创建类[类首字母大写]
    class Star{
      // 构造函数[类自动生成该函数,创建实例时自动调用该函数]
      constructor(uname,age){
        // 共有属性
        this.uname = uname;
        this.age = age;
      }
      // 类中函数不需要加function
      // 多个函数方法之间不需要添加逗号分隔
      sing(song) {
        console.log(this.uname + song);
      }
    }
    // 创建类的实例--对象
    var ldh = new Star('刘德华', 18)
    ldh.sing('冰雨') // 刘德华冰雨
    
3. 类的继承

extends关键字用于继承父类。
super关键字用于访问和调用父类的函数。可以为构造函数/普通函数。

class Son extends Father {
    constructor(x, y) {
      // super(x,y)调用父类构造函数
      // 必须先调用父类的构造方法,再使用子类构造方法
      super(x, y);
      this.x = x;
      this.y = y;
    }
  	say() {
      // super.say()调用父类普通函数
      console.log(super.say() + '的儿子');
    }
}

【注意】
1)ES6中类没有变量提升,必须先定义类再实例化对象。
2)类里面的属性和方法一定要加this使用。
3)继承中的属性/方法查找为就近原则。
4)this指向问题:constructor里的this指向实例对象,方法里的this指向方法的调用者。

4. 面向对象案例:Tab对象

1)【切换功能】点击Tab栏切换相应内容项
2)【添加功能】点击+添加Tab栏和内容项

// insertAdjacentHTML()可以直接把字符串格式的元素追加到父元素指定位置
var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>';
ul.insertAdjacentHTML('beforeend', li);

3)【删除功能】点击x删除当前Tab栏和内容项
4)【修改功能】点击Tab栏或内容项文字可以修改文字内容

// ondblclick 双击事件
this.spans[i].ondblclick = this.editTab;
// 双击禁止选定文字
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

二、构造函数和原型

1. 构造函数

特殊的函数,ES6前用来初始化对象,与new一起使用。将对象中公共的属性和方法抽取出来封装到构造函数中。

// 创建某类对象时:首字母大写
function Star(uname, age) {
   this.uname = uname;
   this.age = age;
   this.sing = function() {
       console.log('我会唱歌');
   }
}
// 与new一起使用,new执行时:
// 1)在内存中创建一个空对象
// 2)用this指向这个空对象
// 3)执行构造函数中的代码,为对象添加属性和方法
// 4)返回这个对象
var ldh = new Star('刘德华', 18);
2. 实例成员与静态成员
  • 实例成员:构造函数内部,this添加的成员
    实例成员只能通过实例化的对象访问。

    console.log(ldh.sing())
    
  • 静态成员:构造函数外部,构造函数本身添加的成员
    静态成员只能通过构造函数来访问。

    Star.sex='男'
    console.log(Star.sex)
    
3. 原型
1)构造函数存在的问题

构造函数定义的函数方法非共享,每创建一个对象实例就要开辟一块新的内存空间,存在浪费内存的问题。

2)原型
  • 原型是一个对象:prototype对象
    每一个构造函数都有一个prototype属性指向一个对象。这个对象的所有属性和方法为构造函数所有。

  • 原型的作用为共享方法
    将不变的方法直接定义在prototype对象上,所有的对象实例都可以共享这些方法。

    // 一般公共属性定义到构造函数中,公共方法定义到原型对象中
    Star.prototype.sing = function() {
       console.log('我会唱歌');
    }
    
3)对象原型

对象原型__proto__指向构造函数的prototype原型对象。它是非标准属性,在开发中不可以使用。
__proto__prototype是等价的,因此对象可以使用构造函数prototype原型对象的属性和方法。

4)constructor属性

__proto__prototype都有一个constructor属性,指回构造函数本身。

Star.prototype = {
// 给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
    constructor: Star,
    sing: function() {
       console.log('我会唱歌');
    }
}
5)原型链
  • 原型链成员查找规则:就近原则,没有则向上查找。
6)原型对象的应用

扩展内置对象方法:

Array.prototype.sum = function() {
   var sum = 0;
   for (var i = 0; i < this.length; i++) {
      sum += this[i];
   }
   return sum;
};
4. 继承

ES6前通过“构造函数+原型对象”实现继承,称为组合继承。

  • 通过构造函数继承父类属性:通过call( )将父类的this指向子类型的this
  • 通过原型对象继承父类方法:通过new父类的实例传递原型对象的方法
// call(thisArg, arg1, arg2, ...) 可以改变函数的this指向

// 1)通过构造函数继承父类属性
function Father(uname, age) {
   this.uname = uname;
   this.age = age;
}
function Son(uname, age, score) {
   // 此时Father的this指向子构造函数的对象实例
   Father.call(this, uname, age);
   this.score = score; // 子类的属性
}
var son = new Son('刘德华', 18, 100);
// 2)通过原型对象继承父类方法
Father.prototype.money = function() {
   console.log(100000);
};
// Son.prototype = Father.prototype; 会导致Father的原型随Son变化
Son.prototype = new Father();
Son.prototype.constructor = Son; // 修改了原型对象,别忘了指回原来的构造函数
Son.prototype.exam = function() { // 子类的方法
   console.log('孩子要考试');
}
5. 类的本质:function

类就是构造函数的语法糖。

// 1) 类也有原型对象prototype,所有方法都定义在prototype上
console.log(Star.prototype)
// 2) 类原型对象prototype里面也有constructor指向类本身
console.log(Star.prototype.constructor)
// 3) 类也可以通过原型对象添加方法
Star.prototype.sing = function() {
   console.log('冰雨');
}
// 4) 类创建的实例对象有__proto__原型且指向类的prototype原型对象
console.log(ldh.__proto__ === Star.prototype);

三、ES5新增方法

1. 数组方法
1)forEach遍历数组
// arr.forEach((value,index,arr)=>{})
arr.forEach(function(value, index, array) {
   console.log('每个数组元素' + value);
   console.log('每个数组元素的索引号' + index);
   console.log('数组本身' + array);
})
2)filter筛选数组
// arr.filter((value,index,arr)=>{})
// 返回一个筛选后的数组,包含满足条件的元素
var newArr = arr.filter(function(value, index) {
   return value % 2 === 0;
});
3)some查找数组
// arr.some((value,index,arr)=>{})
// 返回布尔值,如果查找到符合条件的元素就返回true,并终止循环
var flag1 = arr.some(function(value) {
    return value < 3;
});
2. 字符串方法
1)trim() 去除字符串两边空白

不影响原字符串本身,返回一个新的字符串。

var str = input.value.trim()
3. 对象方法
1)Object.defineProperty()

定义对象中新属性,或修改原有属性。

// Object.defineProperty(obj目标对象,prop属性,descriptor特性)
// 特性包含{value:属性值, writable:是否可重写, enumerable:是否可被枚举, configurable:是否可被删除/再次修改特性}【后面三个属性默认都为false】
Object.defineProperty(obj, 'address', {
   value: '中国山东蓝翔技校xx单元',
   writable: false,
   enumerable: false,
   configurable: false
});
console.log(Object.keys(obj)) //不会打印address属性
delete obj.address //无效
2)Object.keys()

获取对象对象自身的所有属性,返回一个由属性名组成的数组。

Object.keys(obj)

四、函数进阶

1. 函数的定义和调用
  • 函数定义

    // 1. 自定义函数(命名函数) 
    function fn() {};
    // 2. 函数表达式(匿名函数)
    var fun = function() {};
    // 3. 利用new Function('参数1','参数2', ..., '函数体');
    var f = new Function('a', 'b', 'console.log(a + b)');
    

    函数也属于对象,所有函数都是Function的实例对象。

  • 函数调用和this指向

    函数类型调用方式this指向
    普通函数fn( ) 或 fn.call( )window
    构造函数new Star( )实例对象 [原型中的this也是实例对象]
    对象方法o.sayHi( )所属对象
    事件绑定函数触发事件调用绑定事件的对象
    定时器函数定时器自动调用window
    立即执行函数自动调用window
2. 改变this指向

js提供了改变函数内this指向的三种方法:

1)call方法

调用一个对象返回结果,并可以改变函数的this指向。

// fun.call(thisArg, arg1, arg2, ...)
fn.call(o, 1, 2);
// 主要应用于实现继承
Father.call(this, uname, age, sex);
2)apply方法

调用一个对象返回结果,并可以改变函数的this指向,参数必须是数组/伪数组。

// fun.apply(thisArg, [argsArray])
fn.apply(o, [1,2]);
// 主要应用于数组运算 
var max = Math.max.apply(Math, arr);
var max = Math.max(...arr); // 也可以直接展开数组元素
3)bind方法

可以改变函数的this指向,但不会调用函数,返回改造后的原数组拷贝。

// fun.bind(thisArg, arg1, arg2, ...)
// 主要应用于 改变函数的this指向但不想立即执行函数
for (var i = 0; i < btns.length; i++) {
   btns[i].onclick = function() {
      this.disabled = true;
      setTimeout(function() {
      	this.disabled = false;
        // 让定时器this指向btns,btns有disabled属性,window没有
      }.bind(this), 2000); 
   }
}
3. 严格模式(strict mode)
1)什么是严格模式

在严格的条件下运行JS代码。消除了JS语法不合理、不严谨、不安全之处,提高编译运行速度,禁用了保留字。
严格模式在IE10以上版本浏览器支持,旧版本浏览器中忽略。

  • 变量规定

    1)变量名必须先声明再使用
    2)禁止删除已声明的变量

  • this指向规定

    1)全局作用域中函数中的this是undefined
    2)构造函数不加new调用this指向的是undefined,赋值会报错
    3)【不变】定时器this还是指向window
    4)【不变】事件、对象this还是指向调用者

  • 函数规定

    1)函数里面的参数不允许重名
    2)函数必须声明在顶层,不允许在非函数的块级作用域声明函数

2)怎么开启严格模式
  • 为整个脚本开启

    (function() {
       'use strict';
    })();
    
  • 为某个函数开启

    function fn() {
       'use strict';
    }
    
4. 高阶函数

高阶函数是对其他函数进行操作的函数。接收函数作为参数将函数作为返回值输出
最典型的是回调函数~

5.闭包closure

已知函数外部不可以使用局部变量,当函数执行完毕内部的局部变量会销毁。

1)什么是闭包

闭包是一个函数,指一个作用域可以访问另一个函数内部的局部变量。这个被访问的函数为闭包函数。

// 闭包函数
function fn() {
   var num = 10;
   return function() {
      console.log(num);
   }
}
var f = fn();
f();
2)闭包的作用:延伸变量的作用范围
3)闭包的应用
// 1.点击li输出当前li的索引号
for (var i = 0; i < lis.length; i++) {
   // 利用for循环创建了4个立即执行函数【小闭包】,立即执行函数里面的任何一个函数都可以使用它的i这变量
   (function(i) {
      lis[i].onclick = function() {
          console.log(i);
      }
   })(i);
}
// 2.定时打印所有li元素的内容
for (var i = 0; i < lis.length; i++) {
   (function(i) {
       setTimeout(function() {
          console.log(lis[i].innerHTML);
       }, 3000)
   })(i);
}
6. 递归
1)什么是递归

在一个函数内部调用其本身,这个函数就是递归函数。
递归很容易发生“栈溢出”错误,所以必须加退出条件。

2)递归的应用
// 1.求1~n的阶乘
function fn(n) {
   if (n == 1) {
      return 1;
   }
   return n * fn(n - 1);
}
// 2.求斐波那契数列
function fb(n) {
   if (n === 1 || n === 2) {
      return 1;
   }
   return fb(n - 1) + fb(n - 2);
}
// 3.深层遍历数组
function getID(json, id) {
   var o = {};
   json.forEach(function(item) {
       if (item.id == id) {
          o = item;
       // 里面应该有goods这个数组&&数组的长度不为0 
       } else if (item.goods && item.goods.length > 0) {
          o = getID(item.goods, id);
       }
   });
   return o;
}
7. 浅拷贝和深拷贝
1)浅拷贝

只拷贝一层,更深层次的对象只拷贝引用。

// 通过简单的for循环拷贝
// ES6的Object.assign(target, sources)实现浅拷贝
Object.assign(o, obj)
2)深拷贝

拷贝多层,每一层的数据都会拷贝。

// 可以通过递归实现
function deepCopy(newobj, oldobj) {
    for (var k in oldobj) {
       var item = oldobj[k];
       if (item instanceof Array) {
         		// 判断这个值是否是数组
            newobj[k] = [];
            deepCopy(newobj[k], item)
       } else if (item instanceof Object) {
            // 判断这个值是否是对象
            newobj[k] = {};
            deepCopy(newobj[k], item)
      } else {
            // 属于简单数据类型
            newobj[k] = item;
      }
   }
}

五、正则表达式

1. 正则表达式

用来匹配字符串中字符组合的模式。灵活性、逻辑性和功能性很强。

1)匹配:表单验证
2)替换:敏感词
3)提取:获取特定部分
2. 正则表达式的使用
1)创建
// 1.通过RegExp对象的构造函数创建
var regexp = new RegExp(/123/);
// 2.通过字面量创建
var rg = /123/;
2)验证
// 1. regObj.test(str) 返回布尔值
console.log(rg.test('abc'))
// 2. regObj.exec(str) 返回匹配值,否则返回null
console.log(rg.exec('abc'))
3. 正则表达式的特殊字符
符号含义
^开头
$结尾
[]多选一(内部的^表示取反)
.匹配所有,除了空字符串
*{0, } 匹配0位或多位
+{1, } 匹配1位或多位
{0,1} 匹配0位或1位
\d \D数字 非…
\w \W数字字母下划线 非…
\s \S空格换行 非…
4. 正则表达式替换
// stringObj.replace(被替换,替换为),返回一个替换完的新字符串
// g全局匹配   i忽略大小写
div.innerHTML = text.value.replace(/激情|gay/g, '**')

六、ES6语法

ES6(ECMAScript)是有ECMA国际标准化组织制定的一项脚本语言的标准化规范
ES6实际上是一个泛指,指ES2015及后续版本

1. 关键字
1)let关键字
// 1.不存在变量提升
console.log(a) // not defined
let a = 100

// 2.只在所处块级有效
if (true) {
	let num = 100
}
console.log(num) // not defined

// 3.暂时性死区
var num = 10
if (true) {
	console.log(num) // not defined
  // num被let定义的绑定
	let num = 20
}
2)const关键字
// 1.声明常量时必须赋值
const PI // missing initializer

// 2.常量赋值后值不能修改【引用类型的地址不能修改】
const PI = 3.14
PI = 100 // assignment to constant variable
const ary = [100, 200]
ary[0] = 123 // 可以
ary = [1, 2] // assignment to constant variable

// 3.具有块级作用域
if (true) {
	const a = 10
}
console.log(a) // not defined
varletconst
函数级作用域块级作用域块级作用域
变量提升不变量提升不变量提升
值可修改值可修改值不可修改
2. 解构赋值

ES6中按照一定的模式,从数组或对象中提取值,将提取出来的值赋值给另外的变量。

1)数组解构
let ary = [1,2,3]
let [a, b, c, d, e] = ary
console.log(a) // 1
console.log(b) // 2
console.log(c) // 3
console.log(d) // undefined
2)对象解构
let person = {name: 'lisi', age: 30, sex: '男'}
let { name, age, sex } = person
// 冒号后面可以重命名
let {name: myName} = person
3. 箭头函数 ( ) => { }

ES6中新增定义函数的方式。

// 函数体只有一句return代码,可以省略大括号
const sum = (n1, n2) => n1 + n2
console.log(sum(10, 20))
// 形参只有一个,可以省略小括号
const fn = v => { alert(v) }
fn(20)
// 箭头函数没有自己的this,指向定义位置中的this
function fn () {
	console.log(this) // obj
		return () => {
			console.log(this) // obj
	}
}
const obj = {name: 'zhangsan'}
const resFn = fn.call(obj)
resFn()
// 【注意】普通对象不能产生作用域,里面的变量定义在全局作用域,this是指向window
4. …
1)剩余运算符:将多个元素合并为一个数组
// ...args 将参数合并为数组
function add(...args) {
  return args.reduce((total,item) => total + item, 0)
}
console.log(add(1, 2)) // 3
console.log(add(1, 2, 3, 4, 5)) // 15
// 剩余参数与解构配合使用
let ary1 = ['张三', '李四', '王五']
let [s1, ...s2] = ary1
console.log(s1) // '张三'
console.log(s2) // ['李四', '王五']
2)展开运算符:将一个数组展开为多个元素,用逗号分隔
let ary = ["a", "b", "c"]
console.log(...ary) // a b c

// 1.用于合并数组
let ary1 = [1, 2, 3]
let ary2 = [4, 5, 6]
let ary3 = [...ary1, ...ary2]
let ary3 = ary1.push(...ary2)
// 2.用于将伪数组转换为真正的数组
var oDivs = document.getElementsByTagName('div')
var ary = [...oDivs]
5. ES6内置对象扩展
1)Array扩展方法
  • Array.from(obj, function):将伪数组或可遍历对象转换为真正的数组

    var arrayLike = {
    			"0": "1",
    			"1": "2",
    			"length": 2
    }
    // 第二个参数相当于map对每个元素进行处理,返回处理后的数组
    var ary = Array.from(arrayLike, item => item * 2)
    
  • Array.find(function):找出第一个符合条件的数组成员,没有返回undefined

    let target = ary.find(item => item.id == 3)
    
  • Array.findIndex(function):找出第一个符合条件的数组成员索引,没有返回-1

    let index = ary.findIndex(item => item > 15)
    
  • Array.includes(value):判断某个数组是否包含给定的值,返回布尔值

    let result = ary.includes('a')
    
2)String扩展方法
  • 模版字符串:使用反引号定义,${ }包含

    // 模版字符串可以换行
    let html = `
    		<div>
    			<span>${result.name}</span>
          <span>${result.age}</span>
    		</div>
    `;
    // 模版字符串中可以调用函数
    const fn = () => {
    			return '我是fn函数'
    }
    let html = `我是模板字符串 ${fn()}` // 我是模板字符串 我是fn函数
    
  • startsWith( )和endsWith( ):判断参数字符串是否为开头/结尾,返回布尔值

    let str = 'Hello ECMAScript 2015'
    let r1 = str.startsWith('Hello') // true
    let r2 = str.endsWith('2016') // false
    
  • repeat( ):将原字符串重复n次,返回新字符串

    console.log("y".repeat(5)) // yyyyy
    
3)Set数据结构

ES6提供了新的数据结构Set,类似于数组,但里面的值是唯一的。

  • 定义及初始化

    const s1 = new Set()
    const s2 = new Set(["a", "b"])
    
  • 应用:数组去重

    const s3 = new Set(["a","a","b","b"])
    console.log(s3.size) // 2
    const ary = [...s3] // ['a','b']
    
  • 遍历:forEach

    s5.forEach(value => {
    	console.log(value)
    })
    
  • 实例方法

    // 1. add(value)添加某个值,返回set
    s4.add('a').add('b')
    // 2. delete(value)删除某个值,返回布尔值
    const r1 = s4.delete('c')
    // 3. has(value)是否包含某个值,返回布尔值
    const r2 = s4.has('d')
    // 4. clear()清除所有成员,无返回值
    s4.clear()
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值