面向对象

92 阅读6分钟

面向对象的编程思想

面向对象是利用对象进行编程的一种思想, 面向对象的编程思想是相对于面向过程的编程思想而言。
面向对象的程序设计(英语:Object-oriented programming,缩写:OOP)中, 对象是一个由信息及对信息进行处理的描述所组成的整体, 是对现实世界的抽象. 在现实世界里我们所面对的事情都是对象, 如计算机、电视机、自行车等。
ECMAScript有两种开发模式: 1.面向过程, 2.面向对象(OOP)。

面向对象编程(OOP)的三个基本特性

  1. 封装:将属性和方法(数据和功能)封装在一起。

  2. 继承:继承它可以使用现有类的功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

  3. 多态:允许让父类的指针分别指向不同的子类, 调用不同子类的同一个方法, 会有不同的执行效果。多态表现形式有重写Override和重载Overload。JS中可以使用多态的重写,子类重写父类的方法或是属性。重载是指同一个类里的方法可以有多种实现,同名(方法名、函数名)不同参。

对象的组成

属性(对象的属性) ——变量:状态、静态的
方法(对象的行为) ——函数:过程、动态的

面向过程和面向对象

面向过程:

就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现, 使用的时候一个一个依次调用就可以了。

面向对象:

是把构成问题的事务分解成各个对象,每个对象都有自己独立的属性和行为, 对象可以将整个问题事务进行分工, 不同的对象做不同的事情, 这种面向对象的编程思想由于更加贴近实际生活, 所以被计算机语言广泛应用。

构造函数

使用了new来创建对象的函数就是构造函数。

//ES6 还没出来之前,就遇到了一些问题,创建的对象类型不明确
//  采用构造函数来解决
//  构造函数创建对象
function Person(name, age) {
    this.name = name;
    this.age = age;
}
var p = new Person("刘亦菲", 18);

function Dog(name, age) {
    this.name = name;
    this.age = age;
}
var d = new Dog("旺财", 3)

console.log(p);//Person {name: '刘亦菲', age: 18}

console.log(d);//Dog {name: '旺财', age: 3}

构造函数和普通函数的区别

构造函数与普通函数的唯一区别在于调用它们的方式, 任何函数, 只要通过new操作符来调用, 就可作为构造函数; 而任何函数, 若不通过new操作符调用, 就是普通函数。

new操作符做了什么

  1. 在构造函数内部(隐式)创建一个空对象
  2. 空对象的指针(__proto__)指向构造函数的原型(prototype)
  3. 构造函数的this指向空对象,给空对象添加(自定义的)属性和方法
  4. 隐式的返回 return this
function Person(name,age){
    //new操作符做了什么
    //1.在构造函数中创建一个空对象
    var o=new Object();
    //2.空对象的指针指向构造函数的原型
    o.__proto__=Person.prototype;
    //3.给空对象添加属性,挂载属性和方法
    o.name=name;
    o.age=age;
    //4.构造函数内部的this指向空对象,不再指向window
    //5.隐式返回this,由于this指向o,相当于返回o
    return o;
}
var p1=Person("刘亦菲",18);//没有使用new关键字,出来的结果和构造函数new出来的一样
console.log(p1);//Person {name: '刘亦菲', age: 18}

匿名函数

1. 匿名函数就是没有函数名字的函数

var aa=function(){
    console.log("aa");
}
aa();//调用匿名函数,这里的aa是一个变量,相当于函数的名称

函数中包含匿名函数

function bb(){
    return function(){//匿名函数
        console.log("cc");
    }
}
bb()();//bb()函数返回一个匿名函数,后面再加一个小括号执行匿名函数。

2.匿名函数的自运行

匿名函数的自运行, 不需要主动调用, 会直接执行

(function(msg){//形参
      console.log(msg);
})("我是自运行函数,不需要调用自己就会执行");//实参

闭包(Closure)

闭包是这样的一种机制:函数嵌套函数,内部函数可以引用外部函数的参数和变量,参数和变量不会被垃圾回收机制所回收。

function aa() {
    var a = 5;
    return function () {
        a++;
        console.log("a=" + a);
    }
}
// console.log(a);   //无法直接访问a   Uncaught ReferenceError: a is not defined
var cc = aa();  //aa函数被执行了, 并返回了内部的匿名函数给cc
//a一直在内存中没有被释放
cc();  //a=6  
cc();  //a=7
cc();  //a=8

闭包的好处

  1. 可以让一个变量长期的驻扎在内存中不被释放,在IE6、7、8下会存在内存溢出
  2. 避免全局变量污染,和全局变量不同,闭包中的变量无法被外部使用

闭包的用途

  1. 实现缓存
  2. 存储值防止全局变量污染
  3. 实现函数科里化
  4. 节流和防抖

使用闭包的注意点

  1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄漏。
  2. 闭包会在父函数的外部,改变父函数内部变量的值。

垃圾回收机制GC

JS引擎会在一定的时间间隔来自动对内存进行回收(把内存释放)

JS垃圾回收机制有两种:

  1. 标记清除:js会对变量做一个标记Yes or No的标签以供js引擎来处理, 当变量在某个环境下被使用则标记为yes, 当超出该环境(可以理解为超出作用域)则标记为no, js引擎会在一定时间间隔来进行扫描, 会对有no标签的变量进行释放(将该变量所占的内存释放掉)。
  2. 引用计数:对于js中引用类型的变量, 采用引用计数的内存回收机制, 当一个引用类型的变量赋值给另一个变量时, 引用计数会+1, 而当其中有一个变量不再等于值时, 引用计数会-1, 如果引用计数为0, 则js引擎会将其释放掉。

this关键字

JS中的this指的是当前对象,this在不同的代码环境下代表的对象是不一样的。

  1. 情况一:此时this指的是此刻正在运行的函数所依附的对象
var btn=document.querySelector("button");
//按下按钮
btn.onclick=function(){
    console.log(this);
}

image.png 2. 情况二:定时器中的this
定时器setInterval()中的匿名函数是在被全局中的window对象调用的, 所以里面的this指的就是window对象, 而不是button。

var btn = document.querySelector("button");
btn.onclick = function () {
    console.log(this);     //button对象
    setInterval(function () {
        console.log("setInterval:", this); //window对象
    }, 2000);
    setTimeout(function () {
        console.log("setTimeout:", this);  //window对象
    }, 3000);
}

image.png 3. 情况三:构造函数中的this
在构造函数中的this是使用new关键字创建的那个对象。

function Person(name){
    this.name=name;
    this.show=function(){
        console.log(this);
        console.log(this.name);
    }
}
new Person("刘亦菲").show();

image.png 4. 情况四:箭头函数的this
箭头函数的this指向上下文对象,它本身没有this,利用bind、call、apply都无法改变this。

var arrowFn1 = () => {
    console.log("arrowFn1", this);//window
}
arrowFn1();

console.log("--------------------------------------------------------------------------------------------------");

var btn = document.querySelector("button");
//按下按钮
btn.onclick = function () {
    let arrowFn2 = () => {
        console.log("arrowFn2", this);//button对象
    }
    arrowFn2();
}

image.png 5. 情况五:普通函数中的this
this指的就是window对象。

function fn(){
   console.log(this);//window
}
fn();

image.png