原型,原型链

原型,原型链

原型 prototype

  • 是一个对象,叫prototype
  • 实例化之前,原型只是挂靠在构造函数上边
  • 实例化后,它存在于实例化的对象里面,也就是this里边。
  • 放在__proto__容器里面。
  • 原型是实例化以后才有的
  • Car.prototype是构造函数Car的原型.
  • prototype定义了每个构造函数构造出的每个对象的公共祖先。
  • 所有被构造函数构造出的对象,都可以继承原型上的属性和方法。

proto

  • __proto__属于每个实例化的对象
  • 是存储原型的容器 proto: Object.prototype
  • 实例化对象的proto是能改的,改变构造函数的原型即可。

原型链

  • 沿着__proto__向上,逐层查找原型的属性和方法的链条,就叫做原型链。
  • 原型链的最顶端是: Object.prototype
  • 实例化出来的对象在原型链的最底端

原型的作用

  • 把固定的(也就是写死的)变量值和方法,写在原型上
  • 把需要参数赋值的变量值写在构造函数里面

什么时候写在原型上,什么时候写在构造函数里
- 写死的值和方法写在原型上,
- 需要传参的值,写在构造函数里面,
- 所有的方法都写在原型上
//固定的值和方法
var color = 'red';
var fb = function(){
    //...
}

插件的写法:

  • ;立即执行函数
  • 构造函数
  • 原型上写东西
  • window放到全局
;(function(){
    var Test = function(){};
    Test.prototype = {
        fb:function(){}
    }
    window.Test = Test;
}();

实例能修改原型吗?

  • 实例对象不能修改原型上的原始值
  • 能修改引用值的项,因为引用值拿的是同个堆内存的地址。
  • 原始值只读,引用值可修改
    function Car(){}
	Car.prototype = {
		name:123,
		str:{
			age:18
		},
		arr : [1,2,3]
	}
	var car = new Car();
	car.arr[0] = 100.;
	console.log(car.arr);
	console.log(Car.prototype.arr)
	//结果是 [100, 2, 3] [100, 2, 3]

prototype里面的内容

  • construtor: 指向构造函数本身,相当于实例化函数后prototype里面的内容
  • construtor是可以在原型里面更改的

Car.prototype实例化之后仍可修改

  • 修改prototype会实时更新到所有实例化对象上
  • 因为__proto__存的是prototype的引用
Car.prototype = {
    constructor:function Car(){}
}

constructor:
constructor是构造器,在实例化对象的prototype下面。它指向构造函数本身,且下面存放的是构造函数原型的属性。(与当前最新的构造函数原型同步。)

原型考题

Car.prototype.name = 'Benz';
function Car(){}
var car = new Car();
Car.prototype = {
    name:'Mazda';
}
console.log(car.name);
//'Benz'
//因为修改prototype的对象是在实例化之后修改的,修改的值,只修改了car的prototype的下面的constructor所指向的构造函数里面的prototype, 并未修改到实例化对象里面的prototype的值;

//输出结果
      Car.prototype.name = 'Mazda';
      function Car(){}
      var car = new Car();
      Car.prototype.name = 'Benz';
      console.log(car.name);
      //Benz		// 对同个原型修改,所有对之前之后实例化的所有对象有效。


直接对原型修改与对原型重新赋值:
//因为实例化时,this拿的是prototype的地址引用,如果地址引用没变,修改里面的值是可以修改的。
//实例化之后,再给prototype赋值新对象,是一个新的地址.
//而car的this里面存的还是原来的prototype的引用,所以还是原来的值,'Benz';

window和return的不同:
window保存到全局。window.variable = fun;
return在函数执行完后,返回值,如果要全部保存的话,要用变量接收。var variable = test();

原型继承:

      function TelePhone(){
          
      }

 TelePhone.prototype.name = '电话';;
      
      function HandPhone(color, brand, system){
        this.color = color;
        this.brand = brand;
        this.system = system;
      }

      HandPhone.prototype = {
        constructor: TelePhone,
        rom: '64G',
        ram: '6G',
        screen: '18:9',
        call: function(){
          console.log('I am calling somebody');
        }
      }
      var hp1 = new HandPhone('black','iPhone','IOS');
      console.log(HandPhone.prototype);
  console.log(hp1.prototype.constructor.prototype); //能得到Teel的原型

构造函数与new的关系
构造函数必须经过new,才能生成原型属性;
因此,原型是存在于实例对象里边的,是实例对象的this下面的一个属性;
(如果不经过实例化,那么原型就没有载体)

Object.create()

  • 自定义对象原型的创建对象的方法
  • Object.create(原型对象或null)
  • 创建没有原型的对象,Object.create(null);
function Obj(){
    
}
Obj.prototype.num = 1;
var obj1 = Object.create(Obj.prototype);
var obj2 = new Obj();
console.log(obj1);
console.log(obj2);
//两个对象的构成完全一样

Object.prototype.toString.call()

  • [object Object]
  • [什么类型的,什么构造函数]
  • 用来判断类型

call/apply/bind

  • 作用:改变this指向,调用里面的方法
  • 不同之处:参数不同,call传一组对应的参数,apply传arguemnts, bind传参与call一样,但返回的是函数,需要再加个执行符号。
  • 用法
  • Car.call(car, 一组参数);
  • Car.apply(car, [ar1, ar2]);
  • Car.bind(car, 一组参数) ();
  • test() 等于test.call()
function Car(brand, color){
    this.brand = brand;
    this.color = color;
}
var newCar = {};
Car.call(newCar, 'Benz', 'red');
console.log(newCar);
//newCar里面有了两个属性
//.call改变了this的指向,借用了属性和方法
call/apply用法案例
function Compute(){
    this.plus = function(a, b){
        console.log(a + b);
    }
    this.minus = function(a, b){
        console.log(a - b);
    }
}
function FullCompute(){
    Compute.apply(this);
    //Compute.call(this);
    //Compute.bind(this)(); //再加个执行符号
    this.mul = function(a, b){
        console.log(a * b);
    }
    this.div = function(a, b){
        console.log(a / b);
    }
}
//借用以前函数的方法和属性,
//使用情景:
//维护以前的模块,补充完整模块
//多人协作
//分类

关于__proto__:

  • 这是系统自动创建的,如果自己造的__proto__属性并赋值,不能构成原型链继承
  • 无法向下访问proto里面的属性

公共原型

funtion Teacher(){
    
}
Teacher.prototype.name = 'teachers';
Student.prototype = Teacher.prototype;
function Student(){
    
}
//如此,当修改Student.prototype里面的属性时,Teacher的原型也修改了。
//二者公用同个原型对象。

圣杯模式 - 企业级的原型继承方法

  • 使用中间的缓冲构造函数Buffer,隔离两个prototype
  • 需求:继承Teacher.prototype, 且能够在Student.prototype里面写东西
function Teacher(){}
Teacher.prototype.major = '软件工程';
function Buffer(){}
Buffer.prototype = Teacher.prototype;
var buffer = new Buffer();
function Student(){}
Student.prototype = buffer; //student的原型是实例化的buffer对象。
Student.prototype.myFun = function(){}
//这样,就能够只继承目标的prototype,又能往自己的prototype里面写东西了。
  • Teacher也叫做超类,指的是继承的谁。命名是super_class, 也叫继承源。
  • 超类指的是原型继承中,被继承的类。如Teacher。

封装圣杯模式

  • 分析,创建1个Buffer继承原型,并添加constructor和super_class
//圣杯模式,模块化的写法
var inherit = (function (Target, Origin){
	var Buffer = function(){}
	return function(){
	    Buffer.prototype = Origin.prototype;
    	Target.prototype = new Buffer();
    	Target.prototype.constructor = Target;//添加构造器指向自身
    	Target.prototype.super_class = Origin;//添加超类指向继承源
	}
})();

function Teacher(){}
Teacher.prototype.name = '小野老师';
function Student(){}
inherit(Student, Teacher);
var s = new Student();
console.log(s);
//圣杯模式封装, 原型链继承-企业
	function inherit(Target, Origin){
		function Buffer(){}
		Buffer.prototype = Origin.prototype;
		Target.prototype = new Buffer();
		Target.prototype.constructor = Target;//添加构造器指向自身
		Target.prototype.super_class = Origin;//添加超类指向继承源
	}

模块化开发:用自执行函数的方式,构建封闭的作用域,相当于有了自己的命名空间,用于多人协作开发,互不影响。防止了全局变量污染,利于维护和二次开发。

闭包的分类:1. 普通的闭包:即返回一个函数,或返回一个对象(对象里带着函数)。2.构造函数的闭包:隐式返回this。

普通的闭包特点:1. 变量私有化:产生了私有变量:返回的函数能够拥有父函数的变量。2. 保护数据:只有return出去的函数能访问。

构造函数闭包特点: new生成了this。然后隐式return this。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值