JavaScript(10) 面向对象

1,面向对象

1.1构造函数

在ES6之前,JavaScript 不是基于类来创建,而是基于构造函数(constructor)和原型链(prototype)来创建对象。
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new关键字一起使用。我们把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在JS中,使用构造函数时要注意以下两点:

  • 构造函数用于创建某一类对象,其首字母要大写
  • 构造函数要和new关键字一起使用才有意义
    new关键字在创建对象时做以下几件事件:
  • 在内存中创建一个新空对象
  • 让this指向到这个新空对象
  • 执行构造函数里面的代码,给这个新对象添加属性和方法。
  • 返回这个新对象

1.2对象成员

对象成员分为实例成员和静态成员

1.2.1实例成员

实例成员就是构造函数内部通过this添加的成员。如上例代码中name、age、say就是实例成员。实例成员只能通过实例化的对象来访问。

1.2.2静态成员

静态成员是在构造函数本身上添加的成员。如下列代码中 gender就是静态成员。静态成员只能通过构造函数来访问。

1.3instanceof

instancpof 是一个JavaScript的关键字,用于判断是否为某个对象的实例,如果是则返回true,否则返回false。

1.4constructor

每一个对象在创建的时候都会自动拥有一个构造函数属性constructor。
constructor属性是继承自原型对象,指向了构造函数的引用。

1.5原型对象

构造函数很方便,但是存在内存空间浪费的问题。而JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。

1.5.1原型关系

  • 构造函数:用来初始化新创建对象的函数。上例中的Foo就是构造函数。它会自动给构造函数赋予一个叫prototype的属性,该属性指向了实例对象的原型对象。
  • 实例对象:通过new 创建的对象就是实例对象,如上例中的f1就是实例对象,实例对象可以创建多个并且是独立的。每一个原型对象中都有一个_proto_对象。每个实例对象都有一个constructor属性,这个属性是继承自父类,它指向了当前的构造函数。
  • 原型对象:Foo.prototype

①在JS中万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此它们都会具有对象共有的特点。即:对象具有属性proto_,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。
②方法(Function)是一个特殊的对象,除了和其他对象一样有上述_proto_属性之外,还有自己特有的属性一原型属性(prototype),这个属性是一个指针指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。

总结:

  • 构造函数Foo()的原型属性Foo.prototype指向了原型对象,在原型对象里有共有的方法,所有构造函数声明的实例(这里是f1,f2)都可以共享这个方法。
  • 原型对象Foo.prototype保存着实例共享的方法,有一个constructor指回构造函数。
  • 对象f1是Foo对象的实例,这个对象有一个_proto_ 属性,指向构造函数的原型对象,用于访问原型对象的所有方法。

1.5.2原型属性

proto_和constructor属性是对象所独有,而prototype属性是函数所独有的。但由于在JS中函数也是一种对象,因此函数也拥有_proto_和constructor属性。
原型继承的作用:

  • JS继承的机制:通过原型对象实现继承。其实我们平时调用的字符串方法、数组方法、对象方法、函数方法等都是靠proto_继承而来的。
  • 原型对象的作用就是定义所有实例对象共享的属性和方法。

1.5.3原型链

原型链:对象的原型 ->原型的原型 ->原型的原型的原型=> null根据原型链查找,如果一层一层往上查找,所有对象的原型最终都可以寻找到Object.prototype (Object构造函数的prototype)。
总结:所有的对象都继承了Object.prototype 上的属性和方法。
读取属性和方法的规则:

JS引擎会先寻找对象本身的属性和方法,如果找不到就到原型对象上去寻找,这样一层一层寻找,直到找到为止,如果找不到就抛出异常。

1.5.4原型总结

	<script>
        function Foo() {
        }
        Foo.prototype.name = 'jock';
        var f1 = new Foo();
        //1,原型对象与实例对象的关系
        console.log(Foo.prototype === f1._proto_);
        //2,原型对象与构造函数的关系
        console.log(Foo.prototype.constructor === Foo);
        //3,原型对象与构造函数的关系
        console.log(f1.constructor === Foo);
    </script>

总结:

  • 需要牢记两点:_proto_和constructor属性是对象所独有的;②prototype属性是函数所独有的,由于函数也是一种对象,因此函数也拥有_proto_和constructor属性。
  • _proto__属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的 proto_属性所指向的那个对象(父对象)里找,一直找,直到__proto__属性的终点null,再往上找就相当于在null上取值,会报错。通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链。
  • prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法,即f1.proto_=== Foo.prototype.
  • constructor属性的含义是指向该对象的构造函数,所有函数最终的构造函数都指向Function。l

1.6对象创建

在JS中共有五种方式创建对象

1.6.1对象字面量

  1. new构造函数
var obj = new Object();
obj.name = '张三';
console.log(obj);
  1. 字面量
var person = {
	name: '张三',
	age: 18
}
console.log(preson);
console.log(person.name);v  
  1. create
    在ES5中定义了另一种创建对象的方法:从一个实例对象来生成另一个实例对象,使用Object.create()方法来创建。
	 <script>
        var person = {
            name: 'zhang',
            age: 18,
            say: function () {
                console.log(name);
            }
        }
        var p = Object.create(person);
        console.log(p);
        p.say();
    </script>
    //Object对象的create()方法中的参数person作为返回实例对象p的原型对象,在person中定义的属性和方法,都能被实例p继承下来。

1.6.2工厂模式

如果创建单个对象,适字面量的方式来创建是非常方便快捷的。但是,如果我们要创建很多相似的对象,则使用工厂模式是一个比较好的选择。

	<script>
        function createPerson(name,age) {
            this.name = name;
            this.age = age;
        }
        var p1 = new createPerson('wang',20);
        var p2 = new createPerson('zhang',21);
    </script>
    //工厂模式可以创建多个类似的对象,但没有解决对象识别的问题

1.6.3构造函数模式

可以通过使用构造函数模式来解决工厂模式中存在的无法解决对象识别的问题。

	<script>
        function createPerson(name,age) {
            this.name = name;
            this.age = age;
            this.showName = function () {
                console.log(this.name);
            }
        }
        var p1 = new createPerson('wang',20);
        var p2 = new createPerson('zhang',21);
    </script>
    //存在问题:使用构造函数模式解决了工厂模式在创建对象是带来的问题,但同时也会产生新问题:在所有实例对象中各自都存有自己的showName方法,这样就浪费了资源。

1.6.5构造函数拓展模式

构造函数拓展模式解决了构造函数模式中存在的浪费资源的问题。它的设计思想是把方法抽取出来形成一个独立的方法。

	<script>
        function createPerson(name,age) {
            this.name = name;
            this.age = age;
            this.showName = showName;
        }
        function showName() {
            console.log(this.name);
        }
        var p1 = new createPerson('wang',20);
        var p2 = new createPerson('zhang',21);
    </script>

构造函数拓展模式解决了系统内存占用的问题,但同时又产生了新的问题:由于函数定义到了对象外部,此时提升为了一个全局函数。是对象中需要有多个方法,是否需要都定义到全局中呢?如果是会污染全局空间,如果不是,那又如何解决?使用寄生构造函数模式来解决。

1.6.5寄生构造函数模式

寄生构造函数模式接合了工厂模式和构造函数模式。
创建一个函数,函数体内实例化一个对象,并且将对象返回,在外部的使用new来实例化对象。

	<script>
        function Person(name,age) {
            var o = new Object();
            o.name = name;
            o.age = age;
            o.showName = function () {
                console.log(this.name);
            }
            return 0;
        }
        var p1 = new Person('wang',20);
        var p2 = new Person('zhang',21);
    </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值