原型与原型链

构造函数

内置构造函数

自定义构造函数

构造函数中的属性和方法 称为成员,成员可以添加

   function Star(name,age){
     this.name = name;
     this.age = age;
     this.sing = function(){
       console.log("我会唱歌");
     }
   }
   //  通过new 创建对象  ---实例化对象
   var s = new Star('小小',12);

1:实例成员就是构造函数内部通过this添加的成员 name ,age ,sing就是实例成员
实例成员只能通过实例化对象来访问,不可以通过构造函数来访问实例成员

console.log(s.name);// 小小
console.log(Star.name);//Star

2:静态成员 在构造函数本身上添加的成员 sex就是静态成员

Star.sex = "男";

静态成员只能通过构造函数来访问,不能通过实例对象来访问

console.log(Star.sex)//男
console.log(s.sex) //undefined 

构造函数存在问题

构造函数方法,存在浪费内存的问题。
在这里插入图片描述

我们希望所有的对象使用同一个函数,这样节省内存,如何使用同一个函数呢?

原型

js规定,每一个构造函数都有一个prototype属性,指向另一个对象。

这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有

我们可以把哪些不变的方法,定义在prototype对象上,这样所有对象的实例就可以共享这些方法

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

// 往构造函数的原型对象中添加方法
Star.prototype.sing = function(){
  console.log("我会唱歌");
}

var  s1 = new Star('张三',12);

var s2 = new Star('李四',23);
console.log(s1.sing === s2.sing);  //true
s1.sing();  //s1实例调用构造函数原型的方法
s2.sing(); //s2实例调用构造函数原型的方法
  • 一般情况下,公共的属性定义到构造函数里,公共的方法我们放到原型对象上
  • 构造函数中定义的方法会浪费内存空间 使用原型 解决 所有的对象共有同一个函数
  • 原型解决的问题是,节省内存空间

每一个构造函数都有一个属性prototype 构造函数.prototype 指向构造函数的原型;
构造函数.prototype 就是一个对象,这个对象的属性和方法 ,都会被构造函数所拥有
所以构造函数的实例对象 可以访问构造函数的原型对象中的成员

对象的原型

  • 对象都会有一个属性 proto 指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在;
  • proto 对象原型和原型对象 prototype 是等价的
  • proto 对象原型的意义在于为对象的查找机制提供了一个方向,但是它是一个非标准属性,因此在实际开发中,不可以使用这个属性,它只是内部指向原型对象prototype
function Star(name,age){
    this.name = name;
    this.age = age;
    //this.sing = function(){
      //console.log(123)
    //}
}

// 给构造函数原型添加成员
Star.prototype.sing = function(){
  console.log("唱歌");
}
var s1 = new Star("张三",12);
var s2 = new Star('李四',13);

s1.sing();  //实例对象可以访问原型对象成员

// 对象身上系统自己添加一个__proto__指向我们构造函数的原型对象  prototype

console.log(s1)
console.log(s1.__proto__  === Star.prototype);  //true

在这里插入图片描述

实例对象调用方法 查找规则:
首先先看 s1对象上是否有sing方法 如果有就执行对象上的sing,如果没有就去它的构造函数的原型上查找。

总结:

  1. 原型就是原型对象
  2. 构造函数.prototype 就是原型
  3. 实例对象.__proto__ === 构造函数.prototype

原型链

每一个实例对象有__proto__属性,指向的是构造函数的原型对象,构造函数的原型对象也是一个对象,也有__proto__属性,这样一层一层往上找就形成了原型链

在这里插入图片描述

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

  //  原型对象
Star.prototype.sing = function(){
  console.log("我会跳舞");
}
//  实例化对象   
var s = new  Star('张三',12);

1.只要是对象就有 __proto__ 指向原型对象

console.log(Star.prototype === s.__proto__);//true

2.我们Star原型对象的__proto__ 指向的是Object.prototype

// Star的原型对象 是 Object的实例化对象
console.log(Star.prototype.__proto__ === Object.prototype);  //true

3.我们Object.prototype原型对象的__proto__指向为null

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

constructor构造函数

对象 proto 和构造函数prototype 里都有一个属性 constructor
constructor 我们称为构造函数,因为他指回构造函数本身
constructor 主要用来 记录对象引用于哪个构造函数

function Star(name,age){
    this.name = name;
    this.age = age;
}
Star.prototype.sing = function(){
  console.log("我会跳舞")
}
var s = new Star('李四',45);
console.log(s.constructor)
/*
	ƒ Star(name,age){
       this.name = name;
       this.age = age;
   }
*/

constructor 指向的是 自身的构造函数;

我们修改了原来的原型对象,给原型对象赋值的是一个对象:

function Star(name,age){
    this.name = name;
    this.age = age;
}
Star.prototype = {
// 需要我们手动的给constructor 指回原来的构造函数
  // constructor:Star,
  sing:function(){
    console.log("我会跳舞")
  },
  movie:function(){
    console.log("我爱看电影")
  }
}
var s = new Star('李四',45);
console.log(s.constructor)
// ƒ Object() { [native code] }

都说要手动指回原来的构造函数,但我不知道为什么,或这个说 记录下对象引用于哪个构造函数 有什么用,,我就只能先记下,日后知道的时候再回来补充。。

原型链成员查找规则

  1. 当访问一个对象的属性或者方法时,首先查找这个对象自身有没有该属性
  2. 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
  3. 如果还没有查找到就查找原型对象的原型 (Object的原型对象)
  4. 类推 一直找到Object位置 null
function Star(name,age){
       this.name = name;
       this.age = age;
   }
  Star.prototype.sing = function(){
    console.log("我回唱歌");
  }

 Star.prototype.sex = "女";

 var  s = new Star('小小',34);
 console.log(s.sex);  //女
 console.log(Object.prototype);
 console.log(s);
 console.log(Star.prototype);
 console.log(s.toString());//[object Object]

原型对象中this的指向

构造函数中的this 和 原型对象中的this 都指向我们new出来的实例对象

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

var that;
Star.prototype.sing = function(){
  console.log("我会唱歌");
  that = this;
}

var s = new Star('小妞',12);
s.sing();
console.log(that === s);   //true

通过原型为数组扩展内置方法

数组.push
数组.splice
数组.shift

都是定义在
Array.prototype原型对象上的

// 为数组扩展内置方法
Array.prototype.sum = function(){
  // this  指向arr
  var sum = 0;
  for(var i = 0; i <this.length;i ++){
    sum += this[i]
  }
  return sum
}

var arr = new Array(23,45,1,2,4,5,7)
// arr.push(23,45,1,2,4,5,7)
// console.log(arr)
console.log(arr.sum())

继承

call方法

call() 可以调用函数

call()可以修改this的指向,使用call()的时候,参数1是修改后的this指向,参数2,参数3 使用逗号隔开

构造函数继承:
只能继承父类的实例属性和方法 ,不能继承 原型属性或者方法
// 父构造函数
function Parentl(){
  this.name = 'parentl'
}

Parentl.prototype.getName = function(){
  return this.name
}

// 子构造函数
function Child(){
  // this指向子构造函数的对象实例
  Parentl.call(this);  //c
  this.type = "child"
}

var c = new Child();
console.log(c);  //继承了Parentl的name属性
console.log(c.getName())//报错
// 父类原型对象中一旦存在父类之前自己定义的方法,那么子类将无法继承这些方法

借用原型对象继承方法

// 1:父构造函数
function Parentl(name,age){
  // this指向父构造函数的对象实例
  this.name = name;
  this.age = age;
}

Parentl.prototype.money = function(){
  console.log(1000000);
}

// 子构造函数
function Child(name,age,score){
  // this指向子构造函数的对象实例
  Parentl.call(this,name,age);  //c
  this.score = score;
}
Child.prototype = new Parentl()
// 利用对象的形式修改了原型对象,手动设置constructor
Child.prototype.constructor = Child
Child.prototype.exam = function(){
  console.log("要考试了")
}
var c = new  Child('小明',20,98);
console.log(c);
console.log(c.money);
console.log(Parentl.prototype);
console.log(Child.prototype.constructor)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值