设计模式梳理之原型模式

这篇实际上应该叫做,“原来原型也算模式”
原型模式,这个东西其实能完全吃透原型链的都很容易理解,我们先说一下js的原型链

原型链
  • 1.万物皆对象
    js从古老的流传就有一句话叫万物皆对象,但是都是对象,那能一样吗,肯定不一样,我们可以区分为普通对象和函数对象
    对象我们都知道,啥叫函数对象,顾名思义,你看到的所有的函数都叫函数对象,但是其实不仅如此,准确来说,new Function出来的都是函数对象,有人就问了,我创建一个函数直接function fun(){},那也没new啊,你没new,有人替你new了,凡是创建出来的普通的函数,都是有一个隐藏的var fun = new Function()过程来创建的
    这里有一些仔细想会有疑惑的地方,我看网上有个说法是new Function出来的和js的Object都是函数对象,要我来说,狭隘了,控制台打印一下知道:
Object.constructor
> ƒ Function() { [native code] }

我们看下就知道Object的构造函数指针指向的就是Function,那么为啥要把所谓的js的Object拿出来单说是函数对象呢,混淆了视听,以为只有这俩才是函数对象,从而忽略了重要的东西,那就是,Array,String,Number这些也都是与Object一样的

let a=[1]
a.__proto__
> [constructor: ƒ, concat: ƒ, copyWithin: ƒ,...]
a.constructor
> ƒ Array() { [native code] }
a.prototype
> undefined
Array.__proto__
> ƒ () { [native code] }
Array.constructor
> ƒ Function() { [native code] }
Array.prototype
> [constructor: ƒ, concat: ƒ, copyWithin: ƒ, ...]

其实可以思考一个问题,那就是我们创建的对象,数组,字符串,为啥可以直接使用一些方法,比如数组的方法,比如字符串的方法,都哪来的,有的不清楚的可能直接说,内置的,内置在哪了,总得有个依托把,这些就"依托"在他们的prototype

  • 2.函数对象的prototype
    由最最核心的来展开来讲吧,关于原型链并不难,老感觉是网上的一群人给复杂化了,概念是概念,理解要有自己的理解,不能硬搬是不是
    首先来了解一个规则:所有对象都有__proto__,但是只有函数对象才有prototype
    js高程书里说,prototype是指针,指向函数的原型对象,我爆句粗口,向权威说no,这不是脱裤子放屁吗,我肉眼可见的prototype是一个对象属性,虽然说js的指针与传统意义的指针不同,但是也不能给所有的东西都安装上指针的名头,不能说在函数对象的prototype属性找不到的东西可以去函数对象的构造者去找,就把其当作一个指针吧 __proto__是指针我也是勉强接受的,因为这个是一个单纯的作为指向的东西,不同意prototype是一个指针也是因为在寻找自身属性寻找不到的时候,其实本质上是通过隐式原型__proto__上去寻找才找到的,__proto__作为指向的作用也是指向它的构造函数的prototype,如此层层向上查找的

我觉得我的不同理解就总结在了上边加粗的这段话里,不吐不快

那我们总的来看一下

  • constructor是构造函数指针,指向了函数的构造函数,啥叫构造函数
function fun(name) {
 this.name = name;
 this.a= 1;
 this.b = 2;
 this.sayName = function() { console.log(this.name) } 
}
var fun1 = new Person("fun1");
var fun2 = new Person("fun2");

fun就是函数,也是fun1和fun2的构造函数,也就是所谓的创造者,我们刚才说了所有的函数都是new Funtion出来的,那我创建一个数组,是从哪来的,是new Array来的,字符串与数字等等是一致的逻辑,但是数组是不是函数对象,不是,所以数组是没有prototype的

  • __proto__是原型指针,为啥叫原型指针,作用就是指向构造函数的原型

原型指针跟构造函数指针一样,没有额外的作用,就是一个指向作用

  • prototype是函数对象特有的一个属性,挂载在函数对象上,且prototype上挂载的一切属性及方法都可以被以此函数对象作为构造函数时生成的实例所取用
String.prototype
> String {"", constructor: ƒ,...}
String.prototype.f=333
> 333
b="789"
> "789"
b.f
> 333

我们可以从这里看出,函数对象String的prototype挂载的值,可以被所有的字符串通过向上层寻找而找到

单个的三个东西,constructor,proto,prototype,我们都已经解释过了,那我们通过一个完整的例子来看一下原型链

function Foo(_name) {
  this.name = _name;
}
Foo.prototype.show = function() {
  console.log('I am ', this.name);
};
var f1 = new Foo('obj1');
var f2 = new Foo('obj2');

f1.show();  //  I am obj1
f2.show();  //  I am obj2

Foo的constructor是谁------Function,因为所有的普通函数都是由其构造的
Foo的__proto__指向谁-----------Function的prototype,因为指针指向构造者的prototype属性
Foo的prototype有什么作用-----------挂载东西(show方法),等着被以自身为构造函数而实例化的实例(也就是f1和f2)来查找使用

f1的constructor是谁---------Foo,因为他就是由Foo构造的
f1的__proto__指向谁----------Foo的prototype
fi有没有prototype---------没有,为什么,因为f1不是有Function构造的

f2同f1

那么这只是层层递进,是属于一个链条了,也就是说原型链了,但是为啥有人说原型链是一个圆形的闭环,实际上这个并不重要,我解释一下
prototype本身作为一个基础的对象,不是函数对象也不是指针,那么prototype作为对象本身就要有constructor和__proto__,来指向这个prototype的构造者和所在构造者的prototype,他的构造者是Object,但是Object又是由Function构造的,Function又有自己的prototype,着环形不就出来了
其实以我的理解这里最容易混淆,反而所有人分析原型链都要把这部分加进去,导致很多人看不懂,这段闭环要是真是理解不了,其实并不影响理解原型链原理

原型模式

原型模式用于在创建对象时,通过共享某个对象原型的属性和方法,从而达到提高性能、降低内存占用、代码复用的效果。
原型模式的实现可以通过两种方式来实现:E5提出的Object.create以及prototype属性。

  • Object.create实现(我感觉不常用)
    Object.create()方法接收两个参数:第一个参数是__proto__对象,第二个是prototiesObject(可选,使用第二个参数可以初始化额外的其他属性,接受字面量对象形式)
var someCar = {
    drive: function () { },
    name: '马自达'
};

// 使用Object.create创建一个新车
var anotherCar = Object.create(someCar);
anotherCar.name = '丰田佳美';

我们使用Object.create实际上是新建了一个对象vehiclePrototype,并且继承了vehiclePrototype的方法,所以此时vehicle.proto == vehiclePrototype;第二个参数中初始化了"model"的值,将model的值初始化为了"法拉利",所以此时新创建的对象vehiclePrototype中只有一个model,值为"法拉利";

  • prototype实现
    这个较为简单,就是把上边说的原型用起来,因为有一个很重要的功能,就是可以层层向上查找
function F() { };
F.prototype.init = function (carModel) {
    this.model = carModel || "保时捷";
}, 
F.prototype.init = function () {
    console.log('车辆模具是:' + this.model);
}
function vehicle(model) {
    var f = new F();
    f.init(model);
    return f;
}
var car = vehicle('法拉利');
car.getModel();  // 车辆模具是:法拉利

总结:梳理原型模式其实更重要的是理解原型链这回事儿,网上说的原型链去学习的时候不能被牵着鼻子走,我们要自己动手去实验去查看,语言只是描述现象的工具,有时候只需要理解某种逻辑就够了,说法很多,语言也会误导,不同的解释注定会是不同的结果

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值