• js方法和原型继承(一)


    在js语言规范中并不存在方法这一概念,方便起见,将作为对象属性的函数成为方法
    this引用的规则
    a.在最外层代码中,this引用的是全局对象
    b.在函数内,this引用根据函数调用方式不同而不同
    函数内部的this引用 见下表

    函数的调用方式

    this引用的引用对象

    构造函数调用

    所生成的对象

    方法调用

    接收方对象

    apply或call调用

    由apply或call的参数指定的对象

    其它方式调用

    全局对象

    接收方对象是这样一种对象
    通过点运算符或者中括号运算符调用对象方法时,在运算符左侧所指定的对象
    下面是一个关于方法和接收方对象的具体实例

    <script>
    var obj={
        x:3,
        doit:function(){
            p("method is called:  "+this.x);
        }
    };
    obj.doit();//对象obj是接收方对象 doit是方法
    obj['doit']();//对象obj是接收方对象 doit是方法
    //结果一样 method is called: 3
    </script>

    this引用应注意的点
    this的引用的引用对象会随着方法的调用方式不同而不同

    <script>
    var obj={
        x:3,
        doit:function(){
            p("method is called:  "+this.x);
        }
    };
    var fn=obj.doit;//将obj.doit引用的Function对象赋值给全局变量
    fn();//method is called: undefined  函数内的this引用引用了全局变量
    var x=5;
    fn();//method is called: 5
    var obj2={x:4,doit2:fn};//将obj的方法(Function对象的引用)赋值给了另一个对象obj2的属性
    obj2.doit2();//method is called: 4   方法内的this引用引用了对象obj2
    </script>
    <script>
    var obj={
        x:3,
        doit:function(){
            p("doit is called "+this.x);this.doit2();
        },
        doit2:function(){
            p("doit2 is called "+this.x);
        }
    };
    obj.doit();
    //doit is called 3
    //doit2 is called 3  
    //如果将doit2前面的this去掉,则会查找全局里的doit2 嵌套的函数将按照作用域顺序由内到外的顺序查找
    </script>

    apply与call
    在Function对象中包含apply和call这两种方法,通过他们调用的函数的this引用可以指向任意的特定对象,也就是他们可以
    显式指定接收方对象

    <script>
    function f(a){
        p(this.x+":"+a);
    }
    var obj={x:4};
    f.apply(obj,[2]);  //4  通过apply调用f函数内部this指向了obj
    f.call(obj,2);  //4     通过call调用f函数内部this指向了obj
    var obj={
        x:3,
        doit:function(){
            p("method is called:"+this.x);
        }
    };
    var obj2={x:4};
    obj.doit.apply(obj2);//method is called:4
    p(Math.max(4,5,1,2));
    var arr=[1,3,2,0,99];
    var mx=Math.max.apply(null,arr);//没提供第一个参数 则global对象将被用作ths.obj
    p(mx);//99
    </script>

    原型继承
    形式上的理解
    类名.prototype.方法名=function(参数){方法体}

    <script>
    function Myclass(x,y){
        this.x=x;
        this.y=y;
        this.say=function(){
            p(this.x+":"+this.y);
        }
    }
    Myclass.prototype.show=function(){
        p(this.x,this.y);
    }
    var obj1=new Myclass(1,2);
    obj1.show();
    p('show' in obj1);//true
    p(obj1.hasOwnProperty('show')) //false
    p(obj1.hasOwnProperty('say'));  //true
    p('show' in Myclass);//false
    p("say" in Myclass);//false
    p(typeof Myclass);//function
    </script>

    原型链
    原型继承支持一种称为原型链的功能,使用原型链有2个前提
    a.所有的函数(对象)都具有名为prototype的属性(prototype属性所引用的对象则称为prototype对象)
    【对象实例 如上代码中的obj1没有prototype属性】

    <script>
    p( 'prototype' in obj1);//false
    p('__proto__' in obj1);//true
    p('prototype' in Myclass);//true
    p("__proto__" in Myclass);//true
     </script>

    b.所有的对象都含有一个(隐藏的)链接,用以指向在对象生成过程中所使用的构造函数(Function对象)的prototype对象b.所有的对象都含有一个(隐藏的)链接,用以指向在对象生成过程中所使用的构造函数(Function对象)的prototype对象

    <script>
    p(obj1.__proto__===Myclass.prototype);//true
    p(Myclass.__proto__);// function Empty() {}
    p(obj1.prototype);//undefined
    p('x' in Myclass);//false
    
    </script>

    对象(类的实例)对属性的读取 查找顺序
    1.对象自身的属性(通过实例化类获取的属性)
    2.隐式链接所引用的对象(即构造函数的prototype对象)的属性 (obj1.__proto__=Myclass.prototype)
    3.第二项中的对象的隐式链接所引用的对象的属性
    4.反复按照第三步的规则查找直至全部查找完毕(查找的终点是Object.prototype对象)

    当一个函数对象被创建时,Function构造器产生的函数对象会运行类似这样的一些代码
    this.prototype={constructor:this}
    新函数的对象被赋予一个prototype属性,他的值是包含constructor属性且属性值为该新函数的对象,这个prototype对象是存放继承特征的地方,
    因为javascript语言没有提供一种方法去确定哪个函数是打算用来做构造器的,所以每个函数都会得到一个prototype对象
    constructor没什么用
    当采用构造器调用模式,即用new去调用一个函数,函数执行方式将发生改变
    如果new 运算符是一个方法而不是一个运算符,它可能会这样执行

    <script>
    function a(){   }
    p(a.prototype); //[object Object]
    p(a.prototype.constructor);    //function a(){ }
    p(a.prototype.__proto__==Function.prototype);//false
    p(a.prototype.__proto__==Object.prototype);//true
    
    p('method' in Function);//false
    //伪代码
    Function.method('new',function(){
        //创建一个新对象,它继承自构造器函数的原型对象
        var that=Object.create(this.prototype);
        //调用构造器函数,绑定 this到新对象上
        var other=this.apply(that,arguments);
        //如果它的 返回值不是一个对象,就返回该新对象
        return (typeof other==='object' && other)||that;
    });
    </script>
  • 相关阅读:
    世界史上最著名的十大思想实验
    excel 鼠标上下左右移动
    excel 批注
    C# TextWriter类
    C#中的Hashtable
    cython安装、使用
    Java JsonPath grab InvalidPathException in code, you must be catching Java 7's java.nio.file.InvalidPathException instead of JsonPath's com.jayway.jsonpath.InvalidPathExceptio
    Java牛角尖【007】:Java中的Error能不能被Catch
    2016亚洲城市GDP50强出炉
    全国5A级旅游景区已达250家
  • 原文地址:https://www.cnblogs.com/HKUI/p/4122008.html
Copyright © 2020-2023  润新知