面向对象

面向对象编程

逆战班
ECMAScript有两种开发模式
1.函数式(过程化) 面向过程( Procedure Oriented Programming )(POP); 关注过程,分布执行
2.面向对象( Object Oriented Programming )(OOP)关注整体,按模执行

  • 面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,ECMAScript 没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。

  • js本身是没有class类型的,但是每个函数都有一个prototype属性。prototype指向一个对象,当函数作为构造函数时,prototype则起到类似class的作用。

创建对象方式

面向对象里的几种创建对象的方式:字面量,内置构造函数,工厂函数,自定义构造函数,原型对象,原型链,__proto__

字面量

{ }
弊端:代码冗余

//字面量创建
        var stu1 = {
            name:"yuzitong",
            age:18,
            sayHello:function(){
                console.log(this.name);
            }
        }
        var stu2 = {
            name:"yangli",
            age:18,
            sayHello:function(){
                console.log(this.name);
            }
        }

内置构造函数

new Object()
弊端:代码冗余

//借助内置构造函数创建具体的对象
        var stu1 = new Object();
        stu1.name = "jiangdachen";
        stu1.age = 20;
        stu1.sayHello = function(){
            console.log(this.name);
        }

        var stu2 = new Object();

工厂函数

function createObj(){
// statements
}
弊端:无法判断对象属于哪一个类型

//通过工厂函数创建具体的对象
        function createObj(name,age){
            var obj = new Object();
            obj.name = name;//属性
            obj.age = age;
            obj.sayHello = function(){//方法
                console.log(obj.name);
            }
            return obj;
        }
        var stu1 = createObj("john1",21);
        var stu2 = createObj("yanghang",20);

        var mimiao = createObj("xiaohua",2);

        console.log(stu1);
        console.log(stu2);
        console.log(mimiao);

        //instanceof 判断某一个具体的对象(实例)是否属于某一个类型(类)
        console.log(stu1 instanceof Object);
        console.log(mimiao instanceof Object);

        console.log(stu1 instanceof Person);
        console.log(mimiao instanceof Animal);

自定义构造函数

构造函数

  • 用于构建(创建)对象的函数
  • 函数是不是构造函数,取决于调用方式
  • 使用new调用函数会创建返回一个新对象
  • 构造函数的命名使用大驼峰命名法
  • 在使用构造函数时(使用new调用函数)该函数里的this关键字指向新创建的实例对象
  • 通常在构造函数中使用this给新对象添加属性
  • 这里的属性叫对象的私有属性
  • 关键字new的作用在(内存)中开辟一块存储空间,并返回它的地址堆(内存)中开辟的存储空间function
  • 构造函数:是一个普通函数,当它和new运算符一起使用时,我们称之为构造函数,构造函数的首字母大写。
  • function是JavaScript中的一等公民
    JS是一个基于对象和原型的语言
    JS中所有的对象都是new出来的
    JS中所有的对象都是由函数创建的

function Person(){
//statements
}

var person = new Person();

弊端:每个实例调用的方法应该是一致的,但是实际上在生成实例时,各自都创建了自己的方法。消耗了内存。

function Person(name,age){ //构造函数
            //添加两个属性,一个方法
            this.name = name;
            this.age = age;
            this.sayHello = function(){
                console.log(this.name);
            }
        }

        function Animal(name,age){//构造函数
            this.name = name;
            this.age = age;
            this.sound = function(){
                console.log("声音");
            }
        }

        //创建两个实例
        var person1 = new Person("john1",21);
        var person2 = new Person("john2",22);

        //创建两个实例
        var animal1 = new Animal("miaomiao",2);
        var animal2 = new Animal("wangwang",2);

        //测试

        console.log(person1,person2);

        //测试person1和perosn2属于哪一个类型的实例

        console.log(person1 instanceof Person);//true
        console.log(person1 instanceof Object);//true

        console.log(animal1 instanceof Animal);

        person2.sayHello();
        animal2.sound();

        //判断出实例方法是否是同一个
        console.log(person1.sayHello===person2.sayHello);//false

this指向

  • 普通函数 指向window
//普通函数
        function foo(){
            console.log(this);//window
        }
        foo(); //window.foo()
  • 对象方法里this 指向obj
//对象方法里this
        var obj = {
            age:21,
            sayHello:function(){
                console.log(this);//obj
            }
        }
        obj.sayHello();
  • 事件 指向btn
//事件
        btn.onclick = function(){
            console.log(this);//btn
        }
  • 严格模式下普通函数里this是指向undefined
"use strict"
        function foo(){
            console.log(this);//严格模式下普通函数里this是指向undefined
        }

        foo();//没有具体的调用对象
        window.foo();

指导思想:谁调用这个函数或者方法,this就指向谁

  • 指导思想:箭头函数里的this指向定义时所在环境中的那个this对象
  • setTimeout是window内置的方法
 var name = "window";
        var obj = {
            name:"obj",
            sayHello:function(){
                console.log(this);//obj
                setTimeout(()=>{
                    console.log(this.name);//obj
                })
            }
        }
        obj.sayHello();
  • 构造函数中的this 指向实例
  • 构造函数创建对象时的四个步骤
    1.创建一个新对象
    2.改变this指向,指向这个新对象
    3.执行构造函数里的代码,给这个新对象添加属性和方法
    4.返回这个新对象
function Person(name,age){
            this.name = name; //给实例添加属性  实例属性
            this.age = age;
            this.sayHello = function(){ //给实例添加方法  实例方法
                console.log(this.name);
            }
        }
        var person  = new Person("john",20);
        //构造函数里this是指向实例
        console.log(person.name,person.age);

原型对象

  • JavaScript语言就是基于原型和对象的
  • 原型本身就是一个对象
  • 所有对象都拥有原型对象
  • 箭头函数没有原型对象,并且箭头函数不能当做构造函数使用
  • this关键字给新对象添加属性
  • this中绑定的属性叫私有属性
  • 在原型中的属性 所有实例对象都可以访问 节省内存空间
  • 每一个函数都有一个属性prototype,
    称之为原型对象或者原型。原型是一个引用类型,
    原型上的属性和方法能被实例访问。
  • 弊端:解决了多个实例相同的方法指向不一样的问题,但是无法添加自己的属性值
function Person(){
}
//给原型对象添加属性和方法
        Person.prototype.name = "john";
        Person.prototype.age = 20;
        Person.prototype.sayHello = function(){
            console.log(this.name);
        }

        var person1 = new Person();
        var person2 = new Person();

        console.log(person1.sayHello === person2.sayHello);//true

        console.log(person1.name,person2.name);

  • 组合创建
  • 属性放到构造函数里,方法放到原型对象上
    面向对象_第1张图片
function Person(name,age){
            this.name = name;
            this.age = age;
        }
        Person.prototype.sayHello = function(){ //原型方法
            console.log(this.name);//this也是指向实例
        }

        var person1 = new Person("john1",21);
        var person2 = new Person("john2",22);

        console.log(person1.name,person2.name);

constructor

constructor 作为原型对象的一个默认属性存在,表示创建实例的构造函数的引用

  • constructor 构造函数构造器
  • 出现在构造函数原型中
  • 它是一个指针 指向固定构造函数
  • 作用:检测数据类型
  • instance实例 在js中所有的引用类型instanceof检测Object,结果都是true 使用instanceof检测数据类型不准确
function Foo(){

        }
        //console.dir(Foo);
        console.log(Foo.prototype);
        console.log(Foo.prototype.constructor);

原型链

指的是一个虚拟的链条
Js中都有一个隐藏的属性__proto__隐式原型其实它也是一个指针 它指向只有可能是原型对象(prototype)
所有原型对象都是由object创建的

  • 原型链概念解析
    面向对象_第2张图片面向对象_第3张图片
    foo.prototype是由Object创建的
    每一个构造函数都有一个原型对象,原型对象上的属性和方法能被实例所访问,每一个实例上有指向这个原型对象的内部指针__proto__
fa.__proto__ === FnA.prototype
 function FnA(){
            this.a = "aa";
        }


        function FnB(){
            this.b = "bb";
        }


        function FnC(){
            this.c = "cc";
        }

       FnA.prototype = new FnB();
        
        console.log(FnA.prototype);
        var fa = new FnA();
        console.log(fa.__proto__);

让一个类型(构造函数)的原型对象 等于另外一个类型的实例的话

FnA.prototype = new FnB(); //new FnB()创建了一个FnB的实例,这个实例里面有一个__proto__,指向FnB.prototype
        console.log(FnA.prototype.__proto__ === FnB.prototype);
        FnB.prototype = new FnC();
        onsole.log(FnB.prototype.__proto__ === FnC.prototype);
        var fa = new FnA();
        console.log(fa.b);//bb
        console.log(fa.c);//undefined

总结:每一个构造函数都有一个原型对象,每一个原型对象上都有一个指向构造函数的指针(constructor),每一个实例上有指向这个原型对象的内部指针__proto__,原型对象上的属性和方法能被实例所访问到

FnB.prototype = new FnC();  //让FnB原型对象具有c属性
        var fb = new FnB();
        console.log(fb.c);//cc
        FnA.prototype = new FnB();//让FnA原型对象里具有b属性
        var fa = new FnA();
        console.log(fa.b);
        console.log(fa.c);
        
        console.log(fa.__proto__=== FnA.prototype);
        console.log(FnA.prototype.__proto__ === FnB.prototype);
        console.log(FnB.prototype.__proto__=== FnC.prototype);

原型链查找顺序

  • 在Js中
    1.在自身的私有属性查找
    2.沿着原型(链)向上查找
Foo.__proto__===Function.prototype

对象都是由(构造)函数创建的
函数时由函数的构造函数创建的
function Function(){}函数都是由此创建的

Function.__proto__===Function.prototype

面向对象_第4张图片

console.log(fa.__proto__.__proto__.__proto__.__proto__.__proto__);
        var arr = [];
        console.log(arr.__proto__===Array.prototype);
        console.log(arr.__proto__.__proto__);
        console.log(arr.__proto__.__proto__.__proto__);

找到Object.prototype如果还没有就放回undefined
能力检测
所谓的能力检测就是用来处理兼容问题的

class

class Person{
//statements
}

var person = new Person();
class 类 自定义数据类型
es新增关键字 class
在JavaScript 是没有类的,由于 构造函数 的语法 对后端程序员不太友好
class的本质 是一个语法糖 构造函数的语法糖
构造函数 的意义 是创建 对象

class Person{
            constructor(name,age){ //默认存在
                this.name = name;
                this.age = age;
            }
            sayHello(){ //自定义
                console.log(this.name);
            }
        } 
        
        var person = new Person("john",20);
        person.sayHello();

        console.log(Person.prototype);

class和构造函数的关系

function Person(name,age){
                this.name = name;
                this.age = age;
           } 
           Person.prototype.sayHello = function(){
               console.log(this.name);
           }

           console.log(Person.prototype);
class Person{
                constructor(name,age){ //默认存在
                    this.name = name;
                    this.age = age;
                }
                sayHello(){ //自定义
                    console.log(this.name);
                }
        } 

你可能感兴趣的:(笔记)