方君の小窝 方君の小窝
首页
  • 原生js总结
  • 样式相关
  • vue
  • 其他必备知识
  • php
其他
GitHub

方君

迷糊小前端
首页
  • 原生js总结
  • 样式相关
  • vue
  • 其他必备知识
  • php
其他
GitHub
  • 原生js总结

    • js基础
    • ajax
    • 跨域,js同步异步
    • promise(待扩展,微队列及all,race案例)
    • 原型、原型链、继承
      • 1. 先了解构造函数!
      • 2. 原型
      • 3. 原型链
      • 那么到底什么是原型链?
      • 思考题:
    • 闭包
    • 设计模式-单例、观察者
    • jquery
    • json格式
    • class
    • 模块化
    • cookie
  • 样式相关

  • vue

  • 其他必备知识

  • 前端
  • 原生js总结
方君
2020-08-24

原型、原型链、继承

# 1、原型、原型链

什么是原型(prototype)?

# 1. 先了解构造函数!

function Person(name){//constructor
    this.name=name;
    this.getName=function(){
        console.log(this.name);
    }
}
Person.prototype.type="人类"
var dongfang=new Person("dongfang");//实例化
var xiaobao=new Person("xiaobao");//实例化
1
2
3
4
5
6
7
8
9
  • 首字母大写,区分普通函数
  • 内部使用this对象,指向即将实例化的对象
  • 使用new来实例对象

试想一下,如果每执行一次构造函数,就要创建一个新的对象,所有新的对象的方法还都是相同的,造成了大量的空间占用。

所以要把这个方法放在一个单独的地方,让所有实例都可以访问。这就是原型(prototype)

# 2. 原型

在javascript中,每当定义一个函数数据类型(函数对象,函数),都会天生带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型(对象)。

原型

原型对象就相当于一个公共区域,所有实例都访问这个原型对象

function Person(){
    this.name="dongfang";
}
Person.prototype.age="18";         //通过prototype设置构造函数属性
Person.prototype.getName=function(){
    console.log(this.name);
}
Person.prototype.getAge=function(){
    console.log(this.age);
}
var dongfang= new Person();
dongfang.getName();
dongfang.getAge();
1
2
3
4
5
6
7
8
9
10
11
12
13

在构造函数内声明属性与用prototype声明属性有什么不同。

//构造函数内声明属性
function DOG(name){
    this.name = name;
    this.sex = "公狗";
}
var dogA= new DOG("端午");
var dogB= new DOG("糯米");

dogB.sex="母狗";
console.log(dogA.sex);   //公狗
console.log(dogB.sex);   //母狗


//使用prototype声明属性
function DOG(name){
    this.name = name;
}
DOG.prototype.sex="公狗";
var dogA=new DOG("端午");
var dogB=new DOG("糯米");

console.log(dogA.sex);   //公狗
console.log(dogA.sex);   //公狗

DOG.prototype.sex="母狗";

console.log(dogA.sex);   //母狗
console.log(dogA.sex);   //母狗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

总结:

所有实例对象都需要共享的属性和方法,都放在这个prototype里,不需要共享的属性和方法,放在构造函数里面

放在prototype里的属性和方法节省了大量内存的开支。

# 3. 原型链

__proto__和constructor

每一个对象数据类型(),还天生自带一个__proto__属性,该值指向当前实例所属类的原型(prototype)。原型对象中有一个属性constructor(构造器)指向函数对象

每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性
1

原型链

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


//es5获得对象原型的方法
console.log(Object.getPrototypeOf(person) == Person.prototype)  //true
1
2
3
4
5
6
7
8

# 那么到底什么是原型链?

js中万物都是对象,对象与对象间也有关系。js中是通过prototype对象指向父类对象,直到指向Object为止,形成了一条原型的指向链条,就叫做原型链

打个比方:person->Person->Object 普通人继承人类,人类继承对象

当我们访问对象的一个属性或方法时,他会先在对象自身中寻找,如果有直接使用,如果没有就去原型中寻找,如果还找不到去原型的原型中寻找,最后找到Object对象的原型。但是Object对象的原型没有原型!!!如果Object的原型依然找不到,就返回null

Object是JS所有对象数据类型的基类,在Object.prototype上没有__proto__这个属性

原型链2

console.log(Object.prototype.__proto__ === null);   //true

var A = function(){};
var a = new A();
console.log(a.__proto__); //A {}(即构造器function A 的原型对象)
console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)
console.log( Object.prototype); //Object的原型对象
console.log(a.__proto__.__proto__.__proto__); //null

var arr=new Array();
console.log(arr.__proto__);   //所有数组方法
console.log(Array.prototype);
var str=new String();
console.log(str.__proto__);   //所有字符串方法
console.log(String.prototype);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 思考题:

  1. person1.__proto__ 是什么?
  2. Person.__proto__ 是什么?
  3. Person.prototype.__proto__ 是什么?
  4. Object.__proto__ 是什么?
  5. Object.prototype.__proto__ 是什么?

第一题: 因为 person1.__proto__ === person1 的构造函数.prototype 因为 person1的构造函数 === Person 所以 person1.__proto__ === Person.prototype

第二题: 因为 Person.__proto__ === Person的构造函数.prototype 因为 Person的构造函数 === Function 所以 Person.__proto__ === Function.prototype

第三题: Person.prototype 是一个普通对象,我们无需关注它有哪些属性,只要记住它是一个普通对象。 因为一个普通对象的构造函数 === Object 所以 Person.prototype.__proto__ === Object.prototype

第四题,参照第二题,因为 Person 和 Object 一样都是构造函数

第五题: Object.prototype 对象也有proto属性,但它比较特殊,为 null 。因为 null 处于原型链的顶端,这个只能记住。 Object.prototype.__proto__ === null

总结:

  1. 原型prototype,是函数对象独有的,存储实例对象共享的属性和方法的对象(节省内存开支)
  2. _proto_,是所有对象都有的,指向当前实例所属类的原型对象的属性
  3. constructor,是构造函数中的属性与方法
  4. js中是通过原型prototype对象指向父类对象,直到指向Object为止,形成了一条原型的指向链条就是原型链

# 2、继承

js中继承就是获取父类中已有属性和方法的方式

继承

function Person(name,age){          //父类constructor
    this.name=name;
    this.age=age;
    this.sex="man";
    this.getName=function(){
        console.log(this.name);
    }
}
Person.prototype.message="原型";
var dongfang=new Person();

var person=new Person("dongfang");
1
2
3
4
5
6
7
8
9
10
11
12
  1. 构造函数继承

    
    function Student(name){
        //利用call,apply方法在创建对象时使用父类构造函数创建实例
        Person.call(this,name,age);     //使用call方法继承
        Person.apply(this,[name]);  //使用apply方法继承
    }
    
    var stu=new Student("dongfang");
    stu.getName();
    console.log(stu.sex);
    //缺点,获取不到构造函数原型上的属性与方法
    console.log(stu.message);        //undefined
    console.log(person.message);     //原型
    
    
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
  2. 原型链继承

    function Student(name){
        this.name=name;                 //需要把实参与即将实例化的实例属性对应
        
    };
    var dongfang=new Person();
    
    
    Student.prototype = dongfang;   //把父类实例化(父类实例)传递给新构造函数(子类)的原型,因为实例化中包含constructor里的全部属性方法,和prototype里面的全部属性方法
    var stu=new Student("dongfang");
    console.log(stu.name);     undefined
    stu.getName();
    
    //可以获取构造函数原型上的属性与方法
    console.log(stu.message);        //原型
    console.log(person.message);     //原型
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
编辑
#基础
promise(待扩展,微队列及all,race案例)
闭包

← promise(待扩展,微队列及all,race案例) 闭包 →

最近更新
01
vue自定义指令&生命周期
08-24
02
ajax
08-24
03
promise
08-24
更多文章>
Theme by Vdoing | Copyright © 2019-2020
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式