JavaScript的原型与构造函数

来源:互联网 发布:自制单片机开发板 编辑:程序博客网 时间:2024/06/06 12:48

构造函数

  • 作用
    1. 初始化数据
    2. 在js中给对象添加属性,初始化属性用
  • 实例分析
    var o=new Student();

    1. 首先运算符new在堆中开辟了一段空间创建了一个对象,它类似于”{}”,是一个没有任何成员(其实有方法)的对象,然后这个对象会传递给this

    2. 调用构造函数为刚创建的对象初始化成员

      • 构造函数在调用的一瞬间有一个赋值操作,即 this=刚创建出来的对象;
      • 因此在构造函数中this表示刚刚创建出的对象
      • 构造函数的内部使用对象的动态特性为对象添加成员

      注:使用new创建的对象,对象的类型就是创建它的构造函数名,而使用”{}”都是object类型,相当于new Object();

function Student(){    this.name='张三';    this.age=18;}var p=new Student();

这里写图片描述

简单来说谁调用构造函数,谁就是this所指对象

上面那段构造函数本质上如下

function student(o){    o.name="张三";    o.age=18;    return o;}var p=student({});

与构造函数的区别是:
- 必须要有return
- 类型要是object

构造函数引申

function Student(name,age){    this.name=name;    this.age=age;    this.study=function(){        console.log(this.name+"在看书");    };}var s1=new Student("小莫",16);var s2=new Student("小楠",19);console.log(s1.study==s2.study);//false

从上面代码中可看出,多个对象之间有多个study方法副本,但每个方法的业务逻辑是完全一样的,所以搞多个方法副本完全没必要,只会多占用内存,影响性能,所以应想办法将方法单独抽取出来.
- 可以考虑将方法都放在外面,但有很大的安全隐患,在实际开发中会引入各种框架和库,而开发中肯定需要很多构造函数,每个构造函数应该有很多方法,这样一来自定义成员大大增加,与引入的框架或库函数的命名冲突几率非常大,维护起来会非常困难.

那到底怎么解决?别担心,js贴心的为你想好了应对之策

任意一个对象都会默认的连接到它的原型中

  • 凡是创建函数,都会附带的创建一个特殊的对象,该对象使用函数名.prototype引用,称其为:函数的原型属性
  • 函数的原型特点如下
    • 每个由该函数作为构造函数创建的对象都会默认的连接到该对象上,
    • 该对象访问某个方法或者属性时,如果该对象中没有,就会到这个神秘对象中去查找,找到了就当成自己的用

    function Fun() {        Fun.prototype.age = 20;        Fun.prototype.name = "小陈";        Fun.prototype.study=function(){            return "2017年"+this.name+"是菜鸟";        };    };         var p = new Fun();         var p1 = new Fun();                 console.log(p.name); //小陈,Fun.prototype中存在        console.log(p.age); //19,在p中找不到就去Fun.prototype中就去找        p1.name="小强";        console.log(p1.name); //小强,在p1中存在就直接用        console.log(p1.age);//19        console.log(p1.study());//小强是菜鸟

代码流程图

这里写图片描述

原型相关的概念

  • 凡是函数,在创建出来后都有一个对象与之对应,(构造函数也不例外)而我们把这个对象称之为原型对象.
  • 而我们知道,每个对象都有构造函数,所以这也意味着每个对象都有对应的原型对象,
  • 同一个原型对象,相对于构造函数而言,被称为构造函数的原型属性,简称原型
  • 相对于构造函数创建出来的对象,被称为原型属性,也简称原型(坑不坑)
  • 同一个原型,构造函数通过构造函数名.prototype访问,而由这个构造函数实例化的对象通过对象名._proto_访问,这两个引用指向同一个原型(看上面的流程图可明白).

原型与继承的一些弯弯绕绕


  • 构造函数创建出来的对象再找相关属性和方法时,会先从构造函数实例化时有没有给它动态创建和初始化这些属性和方法,若有,那直接用,不在查了
  • 构造函数名.prototype若没有,则会到构造函数的原型属性里面去找(或者说到该对象自己的原型对象中去找,[两种说法,但其实一个玩意]),若这里面有,那得嘞,也当成自己的,直接就用了
  • 特别需说明的是,由于由同一个构造函数创建出来的对象,它们指向的原型对象都是同一个,所以,所有有实例化出来的对象都能拥有原型对象(或者说构造函数的原型属性)的属性和方法,并且能为自己所用(就看对象用不用),这样一来,不就像儿子继承老子的东西吗?继承的概念不就呼之欲出可吗?

所以,特别自然的所以说,构造函数创建出来的对象继承自构造函数的原型属性也可以这么说,构造函数创建出来的对象(实例对象)继承自该对象自己的原型对象,而我们把这种实例对象继承自原型称之为原型继承
所以,再要有人问你就是js是个啥玩意,你可以满不在乎的痞性的回答

JavaScript是基于原型继承的面向对象的语言


(关于原型的详细情况,比如原型链请关注我后续博客,爱你哟(づ ̄3 ̄)づ╭❤~)