zoukankan      html  css  js  c++  java
  • prototype的本质

    在《关于思维方式的思绪》那篇文章里提到了,
    原型的本质就是一种委托关系。
    即我这里没有,就到我的原型里去看看,一旦找到就当成我的用。

    本文详细说一下这个事情。
    比如某女买东西,钱都是她老公付款的。
    用程序刻画是这样的:

     1 var girl = {
     2     name:'小美'
     3 };
     4 var boy = {
     5     name:'小帅',
     6     pay:function(){
     7         console.log('花了1000元');
     8     }
     9 };
    10 Object.setPrototypeOf(girl,boy);
    11 girl.pay();

    /**
    程序中指明了girl的原型是boy, girl 没有pay方法, 但是boy有, 所以boy花钱了.
    从这个例子来看,原型是一种委托关系,如果说是一种继承关系就不是那么贴切了.
    */

     1 var girl0 = {
     2     name: '小美',
     3     pay:function(){
     4         boy0.pay();
     5     }
     6 };
     7 
     8 var boy0 = {
     9     name: '小帅',
    10     pay:function(){
    11         console.log('花了2000元');
    12     }
    13 }
    14 girl0.pay();

    同上面代码意义相同

     1 /**
     2 用这种委托关系,而不是用继承关系去理解原型,会感觉一切豁然开阔.
     3 下面我们通过这个例子看看什么事原型链?
     4 */
     5 var a = {
     6     fn1:function(){
     7         console.log(1);
     8     }
     9 };
    10 var b = {
    11     fn2:function(){
    12         console.log(2);
    13     }
    14 };
    15 var c = {
    16     fn3:function(){
    17         console.log(3);
    18     }
    19 };
    20 var d = {
    21     fn4:function(){
    22         console.log(4);
    23     }
    24 };
    25 Object.setPrototypeOf(d,c);
    26 Object.setPrototypeOf(c,b);
    27 Object.setPrototypeOf(b,a);
    28 d.fn1();
    29 d.fn2();
    30 d.fn3();
    31 d.fn4();
    32 /**
    33 上面代码中,a是b的原型,b是c的原型,c是d的原型.
    34 那么d要找到fn1方法,怎么找呢?
    35 先去其原型c中找.==没找到
    36 再去c的原型b中找.==没找到
    37 再去b的原型a中找.==找到了
    38 因此能调用fn1的方法.
    39 上面的过程就是原型链查找的过程.
    40 讲到这里,原型链的原理想必是懂了.
    41 此时我们再看a,b,c,d四个对象是什么关系?
    42 如果要看作是集成的话,那么就是父子关系.
    43 如果用委托的观点来看,那么每一个对象,都是后一个对象的智囊,也就是原型.
    44 所以本文的关点是什么呢?
    45 不要把原型当成亲爹,要当成智囊,要当成老公,要当成干爹.
    46 本质是委托关系,说白了,就是利用.
    47 其实,讲到这里原型是什么已经基本说完,后面我们准备展开说说,跟构造函数扯上.
    48 */

    第一个问题:什么叫做"一旦找到就当我的用"?
    其实指的就是this问题.

     1 var aaa = {
     2     sayName:function(){
     3         console.log(this.name);
     4     }
     5 };
     6 var laoyao = {
     7     name:'laoyao'
     8 };
     9 Object.setPrototypeOf(laoyao,aaa);
    10 laoyao.sayName();

    第二个问题:克隆的观点?
    加入一个对象是一个空对象的原型.
    因为空对象什么都没有,所有的都来自其原型,我们可以认为此对象是其原型的克隆.

     1 var laowang = {
     2     name:'laowang',
     3     sayName:function(){
     4         console.log(this.name);
     5     }
     6 };
     7 var fenshen={};
     8 Object.setPrototypeOf(fenshen,laowang);
     9 console.log(fenshen.name);
    10 fenshen.sayName();

    当然, Object.create更适合描述克隆.

    var laoli = {
        name:'laoli',
        sayName:function(){
            console.log(this.name);
        }
    };
    var clone = Object.create(laoli);
    clone.sayName();

    第三:我们封装产生对象的过程?
    希望上述对象通过函数产生.

    var createPerson = function(name){
        return{
            name:name,
            sayName:function(){
                console.log(this.name);
            }
        };
    }
    var laozhang =createPerson('laozhang');
    laozhang.sayName();

    我也换种方式来做:

     1 var createPersonOther = function(name){
     2     var o = {};
     3     o.name = name;
     4     var proto ={
     5         sayName:function(){
     6             console.log(this.name);
     7         }
     8     };
     9     Object.setPrototypeOf(o,proto);
    10     return o;
    11 }
    12 var laoyang =createPersonOther('laoyang');
    13 laoyang.sayName();
     1 var createPerson =function(name){
     2     var o = {};
     3     o.name = name;
     4     Object.setPrototypeOf(o,createPerson.proto);
     5     return o;
     6 }
     7 createPerson.proto={
     8     sayName:function(){
     9         console.log(this.name);
    10     }
    11 };
    12 var laoyao =createPerson('laoyao');
    13 laoyao.sayName();

     写到这里,你会发现其实跟我们平常写的代码很像:

     1 var Person = function(name){
     2     this.name=name;
     3 }
     4 Person.prototype = {
     5     sayName:function(){
     6         console.log(this.name);
     7     }
     8 };
     9 var laoyaoq =new Person('laoyaoq');
    10 laoyaoq.sayName();

    我们来刻画一下new过程.我们假设new是一个函数,类似call和bind的那样的函数.
    new Person('laoyaoq');我们换成Person.new('laoyao');
    此函数定义如下:

     1 Function.prototype.new = function (){
     2     var that = Object.create(this.prototype);
     3     this.apply(that,arguments);
     4     return that;
     5 };
     6 
     7 var Person = function (name) {
     8     this.name = name;
     9 }
    10 
    11 Person.prototype ={
    12     sayName:function(){
    13         console.log(this.name);
    14     }
    15 };
    16 var laoli = Person.new('laoli');
    17 laoli.sayName();

    其中这new函数,不是完整模拟new的(考虑返回值是否是对象).详细请看《js语言精粹》47页。其中this指向的是当前函数(Person)
    如果上面的代码看不习惯的话,我们也可以发明如下的api:
    myNew(Person, 'laoli')

     1 var myNew = function() {
     2     var Constructor = [].shift.call(arguments);
     3     var that = Object.create(Constructor.prototype);
     4     Constructor.apply(that, arguments);
     5     return that;
     6 }
     7 var Person = function(name) {
     8     this.name = name;
     9 }
    10 Person.prototype = {
    11     sayName: function() {
    12         console.log(this.name);
    13     }
    14 };
    15 var laoyaoyao = myNew(Person, 'laoyaoyao');
    16 laoyaoyao.sayName();

    说明:上述代码改编于《JS设计模式与开发实践》第20页.
    如果读者没有其他什么面向对象语言基础,
    那么看此文,会觉得new是一个封装委托关系的过程.
    而不是什么模拟java,模拟不彻底啥的.
    所以在我看来,那些号召不要使用new的文章,也未必正确.
    最后说下:这个委托的观点,《你不知道的javascript》有更详细的介绍.

  • 相关阅读:
    【51nod1674】区间的价值 V2(算法效率--位运算合并优化+链表实现)
    【bzoj 2339】[HNOI2011]卡农(数论--排列组合+逆元+递推)
    关于中国剩余定理{附【转】中国剩余定理 }
    JavaScript操作BOM
    学员操作—统计考试平均成绩
    JavaScript基础
    JDBC
    进制
    事务
    复习
  • 原文地址:https://www.cnblogs.com/liubeimeng/p/5798885.html
Copyright © 2011-2022 走看看