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

933

被折叠的 条评论
为什么被折叠?



