JS高级
js面向对象编程
面向对象介绍
什么是对象
- 是单个事物的抽象
- 对象是个容器, 封装了属性和方法
- 数据集或功能集
- ECMAScript-262把对象定义为:无序属性的集合, 其属性可以包含基本值/对象或者函数
- 对象的属性和方法, 叫做成员
- 对象的每个属性或方法都有一个名字, 而每个名字都映射到一个值
什么是面向对象
-
特点: 封装/继承/多态(抽象)
封装性: 对象是将数据与功能组合到一起, 即封装
继承性: 自己没有, 别人有, 拿过来为自己所用, 并成为自己的东西
多态性: -
有点: 灵活/可复用/高度模块化
程序中面向对象的基本体现
创建对象
// 1. 字面量
var obj = {
name: 'zs',
age: 18
}
// 2. 使用object对象创建对象, Object对象是所有对象的祖宗, 函数也是对象
var obj = new Object();
// 3. 自定义构造函数
function Person(name, age) {
this.name = name,
this.age = age
}
var zs = new Person('zs', 18);
new 做的事情分为四个步骤
1. new 在内存中开辟一片空间, 创建了一个新的对象
2. this 指向了这个新创建出来的对象
3. 让构造函数执行
4. 返回新创建出来的那个对象
// 4. 工厂函数
function createPerson(name, age) {
return {
name:name,
age: age
}
}
简单方式
简单方式的改进: 工厂函数
更优雅的方式: 构造函数
构造函数的问题
原型
更好的解决方案: prototype
构造函数/实例/原型三者之间的关系
- 每一个构造函数, 在加载到内存的时候, 浏览器会帮助我们自动创建一个对象, 这个对象我们称之为构造函数的原型对象, 简称原型
- 我们通过构造函数的prototype属性可以访问到自己的原型对象
- 原型对象身上有一个constructor属性, 可以访问到自己对应的构造函数
- 构造函数的实例, 可以调用原型对象上的属性, 如果构造函数里也有这个属性, 那么会执行构造函数上的, 如果构造函数没有这个属性, 才执行原型对象上的
属性成员的搜索原则: 原型链
实例对象读写原型对象成员
更简单的原型语法
原生对象的原型
原型对象使用建议
函数进阶
函数的定义方式
函数声明
函数表达式
函数声明与函数表达式的区别
函数的调用方式
函数内this指向的不同场景
函数也是对象
call/apply/bind
call
apply
bind
小结
函数的其他成员
函数的静态成员和实例成员
高阶函数
作为参数
作为返回值
函数闭包
作用域/作用域链/预解析
什么是闭包
闭包的思考题
正则表达式
正则表达式简介
什么是正则表达式
正则表达式的作用
正则表达式的特点
正则表达式的测试
正则表达式的组成
元字符串
常用元字符串
限定符
其他
案例
js中使用正则表达式
创建正则对象
参数
正则匹配
正则提取
正则替换
案例:表单验证
实现继承的方式
var base = {
name:'',
age: '',
sayHello() {
console.log('hello');
}
}
// 1. 混入式继承(用的极少)
var obj = {};
for(var k in base) {
obj[k] = base[k];
}
// 2. 原型继承(用的比较多)
function Person() {
}
Person.prototype = base;
var p = new Person();
function Student() {
}
Student.prototype = Person.prototype;
// 3. 经典继承 Object.create
// 下面的代码的作用
// 1. 创建一个新对象obj1
// 2. 把obj1的原型(__proto__)设置为base
// 传进去的base就是我们要继承的对象, obj1对象的原型上面, 就是base上面的成员
var obj1 = Object.create(base);
console.log(obj1);
// 4. 借用构造函数继承(call apply)(继承的是属性, 无法继承到原型上的方法)
function Person() {
this.name = "";
this.age = ""
}
function Student() {
Person.call(this);
}
var stu = new Student();
console.log(stu);
// 5. 组合式继承 = 原型继承 + 借用构造函数继承
function Person() {
this.name = '喵喵';
this.age = '';
this.play = [1,2,3];
}
Person.prototype.sayHello = function () {
console.log('我最棒, 真的');
}
function Student() {
this.color = 'yellow';
Person.call(this);
}
Student.prototype = new Person();
var p = new Person();
var s = new Student();
var h = new Student();
s.play.push(4); // 如果不加构造函数继承的话, 这里的改变, 也会改变其他实例上的这个数组, 这就改的太丧心病狂了. 加了以后, 就可以随便改了, 怎么改都是改自己实例, 而不会连其他实例的都一起改变
s.color = 'ss';
console.log(p);
console.log(s);
console.log(h);
h.sayHello();
// 6. es6实现继承的方法
class Person{
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log('hello');
}
static sayHi() {
console.log('hi');
}
}
// extends 关键字使用的其实就是 组合式继承
class Student extends Person{
constructor() {
// 在子类构造函数中, 第一步事情, 调用父类的构造函数
super(); // 相当于es5的Person.call(this); 不写会报错
this.stuNo = 10000;
}
}
let stu = new Student('喵喵', 0.67);
console.log(stu.stuNo);
stu.sayHello();
Student.sayHi(); // Person的静态成员也被继承了