JavaScript面向对象编程——构造函数

JavaScript面向对象编程——构造函数

写在开头,本篇是学习阮一峰的JavaScript教材后,为加深理解和记忆所写的博客,本文中基本全部引用阮一峰的JavaScript教材。详情请看https://wangdoc.com/javascript/oop/index.html

  1. 构造函数

    面向对象第一步就是要生成对象,对象的生成需要一个模板,在Java中这个模板是“类”,但JavaScript中,面向对象的模板是构造函数和原型链。
    构造函数作为对象的模板,用来生成实例对象的函数,描述了实例对象的基本结构,一个构造函数可以生成多个实例对象,这些实例对象都有相同的结构。
    构造函数也是一个普通的函数,但是有自己的特征和用法。

    var Animal=function(){
    this.name='老虎';
    };
    
    

    上面代码中,animal就是构造函数。为了与普通函数有区别,构造函数第一个字幕通常大写。
    构造函数有两个特点

    • 函数内部使用了this关键字,代表了所要生成的对象实例。

    • 在生成对象的时候,必须使用new命令。

  2. new命令

    new命令的作用,执行构造函数时返回一个实例对象

    	var Animal=function(){
    	 this.name='老虎';
    	}
    	var  a=new Animal();
    	a.name;//老虎
    

    以上代码中,构造函数Animal生成一个实例对象 保存在a中。这个对象从构造函数Animal中得到了name属性。new命令执行过程中,构造函数内部的this,就代表了新生成的实例对象。
    使用new命令时,也可以接受参数

    var Animal=function(p){
    this.name=p;
    };
    var  a=new Animal('狮子');
    

    实例对象生成的写法

    //推荐写法
    var  a=new Animal();
    //不推荐的写法
    var  a=new Animal;
    

    注:如果忘记使用new命令,此时的构造函数就变成普通函数,不会生成实例对象。此时函数内的this就代表全局对象。

    var Animal = function (){
      this.name = '老虎';
    };
    
    var a= Animal();
    a // undefined
    name // 老虎
    

    为了避免忘记使用new命令,可以在构造函数内部加上 use strict,利用严格模式,直接调用时就会报错。
    另一个解决办法是,在内部判断是否使用new命令,如果没有使用,则直接返回一个实例对象

    function Fubar(foo,bar){
    if(!(this instanceof Fubar)){
    return new Fubar(foo,bar);
    }
    this._foo=foo;
    this._bar=bar;
    Fubar(1, 2)._foo // 1
    (new Fubar(1, 2))._foo // 1
    
    
  3. new命令原理

    使用new命令时,它后面的函数依次执行下面的步骤。

    • 创建一个空对象,作为将要返回的对象实例。

    • 将这个空对象的原型,指向构造函数的prototype属性。

    • 将这个空对象赋值给函数内部的this关键字。

    • 开始执行构造函数内部的代码。
      之所以构造函数叫构造函数,意思是此函数的目的是操作一个空对象(this对象),将其构造成需要的样子,如果构造函数内部有return语句,而且后面跟着一个对象,new 命令就会返回return语句指定的对象;否则,就不会管return语句,返回this对象

  4. 原型
    由于构造函数生成新对象,再通过为构造函数为实例定义属性,虽然方便,但有弊端,一个构造函数的多个实例之间无法共享属性,造成资源的浪费,因此可以利用原型,将实例中属性放在原型上,不仅节省了空间,还体现了实例对象之间的联系。

    	function Animal(name) {
    	  this.name = name;
    	}
    	Animal.prototype.color = 'white';
    	
    	var cat1 = new Animal('大毛');
    	var cat2 = new Animal('二毛');
    	
    	cat1.color // 'white'
    	cat2.color // 'white'
    

    注:在定义原型对象的属性时,当实例对象本身没有某个属性或方法的时候,他会到原型对象上去寻找该属性或方法。如果实例中有某个属性或方法,就不会去原型对象上寻找。

  5. 原型链
    JavaScript定义了,每个对象都有自己的原型对象,一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……,最终可以到Object构造函数的prototype属性,也就是所有对象都继承了Object.prototype的属性,而Object.prototype的原型是null。

  6. constructor 属性
    prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数,因此可以根据此原理,判断某个实例对象是由哪一个构造函数产生的。

    function F() {};
    var f = new F();
    
    f.constructor === F // true
    f.constructor === RegExp // false
    

    上面代码中f就是F的实例对象,不是RegExp的。

    同时constructor属性表示原型对象与构造函数之间的关联关系,如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。

    
    // 坏的写法
    C.prototype = {
      method1: function (...) { ... },
      // ...
    };
    
    // 好的写法
    C.prototype = {
      constructor: C,
      method1: function (...) { ... },
      // ...
    };
    
    // 更好的写法
    	C.prototype.method1 = function (...) { ... };
    
    	会出现的问题
    function Person(name) {
      this.name = name;
    }
    
    Person.prototype.constructor === Person // true
    
    Person.prototype = {
      method: function () {}
    };
    
    Person.prototype.constructor === Person // false
    Person.prototype.constructor === Object // true
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值