JavaScript面向对象

JavaScript面向对象

之前的一个月学习了javascritp的基础,这个月开始学习面向对象了,下面我和大家分享下我的学习经验.

面向对象是什么?

  • Object-Oriented Programming(OOP) 面向对象编程
  • 在这之前 我们学习编程的思想主要是"面向过程编程" Process-oriented programming(POP);
  • 首先,先理解一下对象,很多事物都是对象,简单到一整数,复杂到一架飞机,对象是一个整体,对外提供一些操作;那么面向对象就是说,使用对象的时候,你可以直接使用它所提供的功能而忽略其内部组成情况。面对对象不一定只有在编程界里才有,我们生活中无处不在;我的理解是这样的:比如说,你家里的电空调,你使用了遥控,就能操作空调,但是你实际上不知道这台空调里面是什么零件组成的,你只要知道,我拿到遥控就可以操作空调就好了。这就是一种面向对象的思想。
  • JS中的面向对象编程就是把构成问题的事物分解成对象,描述这些对象的行为,先整体再具体去实现。

1.创建对象有六种创建对象的方式

一. new 操作符 + Object 创建对象

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

        var stu2 = new Object();
        //缺点:代码冗余

二、字面量创建对象

//字面量创建
        var stu1 = {
            name:"张三",
            age:18,
            sayHello:function(){
                console.log(this.name);
            }
        }
        var stu2 = {
            name:"李四",
            age:18,
            sayHello:function(){
                console.log(this.name);
            }
        }
//……
        //弊端:代码冗余
  • 以上两种方法在使用同一接口创建多个对象时,会产生大量重复代码,为了解决此问题,工厂模式被开发。

三、工厂函数

function createPerson(name,age,family) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.family = family;
    o.say = function(){
        alert(this.name);
    }
    return o;
}

var person1 =  createPerson("lisi",21,["lida","lier","wangwu"]);   //instanceof无法判断它是谁的实例,只能判断他是对象,构造函数都可以判断出
var person2 =  createPerson("wangwu",18,["lida","lier","lisi"]);
console.log(person1 instanceof Object);                           //true
  • 工厂模式解决了重复实例化多个对象的问题,但没有解决对象识别的问题(但是工厂模式却无从识别对象的类型,因为全部都是Object,不像Date、Array等,本例中,得到的都是o对象,对象的类型都是Object,因此出现了构造函数模式)。

四、构造函数模式

function Person(name,age,family) {
    this.name = name;
    this.age = age;
    this.family = family;
    this.say = function(){
        alert(this.name);
    }
}
var person1 = new Person("lisi",21,["lida","lier","wangwu"]);
var person2 = new Person("lisi",21,["lida","lier","lisi"]);
console.log(person1 instanceof Object); //true
console.log(person1 instanceof Person); //true
console.log(person2 instanceof Object); //true
console.log(person2 instanceof Person); //true
console.log(person1.constructor);      //constructor 属性返回对创建此对象的数组、函数的引用

对比工厂模式有以下不同之处:

1、没有显式地创建对象

2、直接将属性和方法赋给了 this 对象

3、没有 return 语句

以此方法调用构造函数步骤 {

  1. 创建一个新对象

  2. 将构造函数的作用域赋给新对象(将this指向这个新对象)

  3. 执行构造函数代码(为这个新对象添加属性)

  4. 返回新对象 ( 指针赋给变量person ??? )

}

可以看出,构造函数知道自己从哪里来(通过 instanceof 可以看出其既是Object的实例,又是Person的实例)

构造函数也有其缺陷,每个实例都包含不同的Function实例( 构造函数内的方法在做同一件事,但是实例化后却产生了不同的对象,方法是函数 ,函数也是对象)

因此产生了原型模式

五、原型模式

function Person() {
}

Person.prototype.name = "lisi";
Person.prototype.age = 21;
Person.prototype.family = ["lida","lier","wangwu"];
Person.prototype.say = function(){
    alert(this.name);
};
console.log(Person.prototype);   //Object{name: 'lisi', age: 21, family: Array[3]}

var person1 = new Person();        //创建一个实例person1
console.log(person1.name);        //lisi

var person2 = new Person();        //创建实例person2
person2.name = "wangwu";
person2.family = ["lida","lier","lisi"];
console.log(person2);            //Person {name: "wangwu", family: Array[3]}
// console.log(person2.prototype.name);         //报错
console.log(person2.age);              //21
  • 原型模式的好处是所有对象实例共享它的属性和方法(即所谓的共有属性),此外还可以如代码第16,17行那样设置实例自己的属性(方法)(即所谓的私有属性),可以覆盖原型对象上的同名属性(方法)。

六、混合模式(构造函数模式+原型模式)

function Person(name,age,family){
    this.name = name;
    this.age = age;
    this.family = family;
}

Person.prototype = {
    constructor: Person,  //每个函数都有prototype属性,指向该函数原型对象,原型对象都有constructor属性,这是一个指向prototype属性所在函数的指针(可省略不写)
    say: function(){
        alert(this.name);
    }
}

var person1 = new Person("lisi",21,["lida","lier","wangwu"]);
console.log(person1);
var person2 = new Person("wangwu",21,["lida","lier","lisi"]);
console.log(person2);

2.原型对象

一. 什么是原型对象???

  • 原型对象:只要创建了一个新函数,就会根据一些特定的规则为该函数创建一个prototype属性,这个属性指向的对象就是该新函数的原型对象。(默认情况下,所有原型对象都会自动获取一个constructor属性,这个属性是一个指向prototype属性所在函数的指针)
  • 原型对象的优点:可以让所有对象实例共享它所包含的属性和方法

下面看代码

    function fn1() {
    }
    var fn2 = function () {
    }
    var fn3 = new Function()
	
	var obj=new Object();

	var obj1={};

    console.log(typeof fn1) //function
    console.log(typeof fn2) //function
    console.log(typeof fn3)  //function
    console.log(type obj)	//object
    console.log(type obj1)	//object

    console.dir(fn1) //如下图
    console.dir(fn2)//如下图
    console.dir(fn3)//如下图
    console.dir(obj)//如下图
    console.dir(obj1)//如下图

在这里插入图片描述在这里插入图片描述

得出结论~记住,重点
function 对象有一个prototype属性,使用new生成的对象就没有这个prototype属性。

二.原型对象有什么作用?

   function Person(name, age) {
        this.name = name
        this.age = age
        this.eat = function () {
            console.log("吃饭")
        }
    }
    var per1 = new Person("小明", 18)
    var per2 = new Person("小红", 20)
   
    console.log(per1 === per2) //false
    per1.eat() //吃饭
    per2.eat() //吃饭
    console.log(per1.eat === per2.eat) //false

自定义构造函数每次实例化出来的对象,构造函数都会创建一次,
所以eat方法在内存中创建了两次!他们在内存中的地址不同,所以不等!
但是因为它们的逻辑和功能一样,这样就导致了代码冗余,影响性能,所以这里就需要用到原型对象!

 function Person(name, age) {
        this.name = name
        this.age = age
    }
    Person.prototype.eat = function () { //将eat方法添加到Person的原型中
        console.log("恰饭")
    } 
    var per1 = new Person("小明", 18)
    var per2 = new Person("小红", 20)
    console.log(per1 === per2) //false
    console.log(per1.eat === per2.eat) //true
    per1.eat() //恰饭
    per2.eat() //恰饭

通过原型添加的方法,可以完美的解决数据共享问题,从而节省了内存空间…

Constructor

  • 接下来看一下Constructor (构造器)
    在这里插入图片描述

Constructor出现在构造函数原型中,它是每一个实例对象都拥有的属性,这个属性它是一个指针,指向固定,指向构造函数

每个构造函数都有默认的prototype属性,指向一个对象。此对象作为该构造函数new出的对象的原型对象。此对象上有constructor属性,反向指向构造函数本身。说起来比较绕,示例代码:

function Person(){
}
 
console.log(Person.prototype.constructor == Person);// true
 
var person = new Person();
console.log(person.constructor)// Person

所以,对象上的constructor属性,实际是从它的原型对象上继承来的,指向它的构造函数

3.原型链

一.什么是原型链

  • 原型链是针对构造函数的,比如我先创建了一个函数,然后通过一个变量new了这个函数,那么这个被new出来的函数就会继承创建出来的那个函数的属性,然后如果我访问new出来的这个函数的某个属性,但是我并没有在这个new出来的函数中定义这个变量,那么它就会往上(向创建出它的函数中)查找,这个查找的过程就叫做原型链。
Object ==> 构造函数1 ==> 构造函数2

就和css中的继承一样,如果自身没有定义就会继承父元素的样式。

function a(){};
a.prototype.name = "张三";
var b = new a();
console.log(b.name); //张三
b.name = "lisi"
console.log(b.name); //lisi

下面我们来看一张图
在这里插入图片描述

二.原型指针(隐式原型)

proto:
proto 是原型链查询中实际用到的,它总是指向 prototype,换句话说就是指向构造函数的原型对象,它是对象独有的。注意,为什么Foo构造也有这个属性呢,因为再js的宇宙里万物皆对象,包括函数;

根据以上的概括我们能知道Foo构造函数_proto_指向的是他的构造函数的原型对象,它的构造函数是Function, 也就是说Foo的_proto_指向Function.prototype, 我们再看到左边绿色的a和b函数的_proto_指像的是Foo.prototype,因为他们是通过 new Foo实例化出来的,它们的构造函数就是Foo(), 即a.proto = Foo.prototype; 接着我们来看看最右边紫色的模块Function.prororype, 它的_proto_指针指向的是Object.prototype,Object._proto_又为null.。于是我们就可以得出:在原型链中的指向是,函数 → 构造行数 → Function.prototype → Object.protype → null ;

结论:

1、proto 是原型链查询中实际用到的,它总是指向 prototype;

2、prototype是函数独有的,在定义构造函数时自动创建,它总是被__proto__所指向 

所有对象都有__proto__属性,函数这个特殊对象除了具有__proto__属性,还有特有的原型属性prototype。prototype对象默认有两个属性,constructor属性和__proto__属性。prototype属性可以给函数和对象添加可共享(继承)的方法、属性,而__proto__是查找某函数或对象的原型链方式。constructor,这个属性包含了一个指针,指回原构造函数。

本期的内容就讲到这里了,还是一个新手,如有不足望多多指正,希望在逆战班能越学越好加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值