zoukankan      html  css  js  c++  java
  • 面向对象的思想

    面向对象编程:见搜狗:面向对象(mianxiangduixiang) js关键字(jsguanjianzi) apply call  

    一切事物皆对象

    以下使用人和汽车进行解析对象要要素:

    1,人的属性:

    2,人的方法:

    3,人的对象:

    4,原型:prototype属性指向一个内存地址----该地址存放着一个原始对象。

      prototype就是该对象的引用。 即:原型对象。

    汽车的对象解析四要素:

    1,汽车的属性

    2,汽车的方法:

    3,汽车的实例:

      众多汽车中的一辆车

    4,原型:prototype属性指向一个内存地址----该地址存放着一个原始对象。prototype就是该对象的引用。 即:原型对象。

    <script>
    function f(){

    }
    console.log(f.prototype);// 返回 Object
    // a instance of Object 引用数据类型 判断 a 是否是 Object的实例
    // a typeof b 基本数据类型 判断 a 是否是 b的实例
    console.log(f instanceof Object); // 返回 true
    </script>

     

    继承方式分为4种:

    继承分为:原型继承,构造函数继承,call,apply 四种方式

    1,原型继承

    <script type="text/javascript"> 

    //原型:是利用prototype添加属性和方法

    //原型链:JS在创建对象(不论是普通对象还是函数对象)的时候,

    //都有一个__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype

    //原型的值可以是一个对象,也可以是null Object.__proto__指向 null 。

    //js对象有一个__proto__属性,指向它的构造函数的prototype属性

    //js中所有的函数都有一个prototype属性,该属性引用了一个对象,即原型对象,也简称原型

    /*__proto__ 和 prototype 的区别:

    1,__proto__ 是每个对象都有的属性。不是一个规范的属性,火狐有点不同。

    2,prototype 是每个函数都有的属性

    在多数情况下,__proto__ === constructor.prototype 返回 true

    Object.create()创建的对象不适用此等式*/

    //js继承:

    //原型:使用prototype对象来添加属性和方法

    var person = function(){};//创建一个空方法

    var p = new person();

    // 实例化p对象,经历三个阶段:

    // 1,var p={} 实例化一个p对象

    // 2,p.__proto__ = person.prototype,出于原型链含义, __proto__是任何对象都自带的属性。

    // JS在创建对象(不论是普通对象还是函数对象)的时候,

    //都有一个__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype

    // 3,创建对象(初始化), p ==> person.call(p)

    /*console.log(person.prototype);//{constructor: ƒ}  构造函数

    console.log(p.__proto__);//{constructor: ƒ}  构造函数

    console.log(person.prototype instanceof Object);//返回true

    console.log(p.__proto__ instanceof Object);//返回true

    console.log(person.prototype === p.__proto__);//返回true*/

    /////---------

    function pText(){

    this.say=function(){

    alert("111");

    }

    }

    pText.prototype.play=function(){

    alert("22");

    }

    pText.prototype.name="haha";

    var cText=function(){

    this.eat=function(){

    alert("33");

    }

    };

    cText.prototype.name="lala";

    cText.prototype=new pText();

    var person=new cText();

    //注意点:返回的不是 lala,而是 haha,这里先执行name="lala",

    //再继承父元素中的name="haha",所以后面覆盖前面自定义的name。

    console.log(person.name);//返回 haha

    person.eat();//33

    person.say();//11

    person.play();//22

    </script>

    //-----------

    <script>

    //prototype是原型(理解为基本框架), __proto__是原型链

    var a={};//a是一个对象,创建a的构造函数:var a=new Object();

    //根据原型链的定义:js创建任何对象,都内置一个__proto__属性,

    //指向创造它的函数对象的原型对象prototype,即:a.__proto__===Object.prototype.

    console.log(a.__proto__);//页面第一次加载控制台显示:Object,刷新就不是了

    console.log(a.__proto__===Object.prototype);//返回 true

    console.log(a.__proto__===a.constructor.prototype);//返回 true

    console.log(a.prototype);//返回 undefined 未定义,函数才有prototype属性

    var b=function(){};

    var j=new b();

    console.log(j.__proto__);//页面第一次加载控制台显示:Object,刷新就不是了

    console.log(b.prototype);//页面第一次加载控制台显示:Object,刷新就不是了

    ////根据原型链的定义:js创建任何对象,都内置一个__proto__属性,

    //指向创造它的函数对象的原型对象prototype,即:f.__proto__===b.prototype.

    console.log(j.__proto__===b.prototype);//返回 true

    var A = function(){};

    var a = new A();

    // a.say();//不存在say方法会报错的

    // 原型链:a属性中查找---》 a.__proto__ ---》 Object.__proto__===null,不存在就报错。

    // 这就是一条围绕__proto__的原型链。

    // 原型链的顶层就是Object.prototype,而这个对象的是没有原型对象的。

    /*原型链解析:a.say();

    1,首先会在a内部属性中查找 say方法。

    2,没找到,则会在 a.__proto__原型对象 中查找 say方法 

    3,没找到,则会在 Object.__proto__原型对象 中查找 say方法,因为没找到,且Object.__proto__===null,所以

    a.say()就会报错。*/

    console.log(a.__proto__); //A {}(即构造器function A 的原型对象)

    console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)

    //原型链的顶层就是Object.prototype===null

    console.log(a.__proto__.__proto__.__proto__); //null 

    //再继续往下就是语法错误

    console.log(a.__proto__.__proto__.__proto__.__proto__); //报错,不存在该

    //---------

    ////分析:原型链的执行过程

    var person = function(){} //父方法

    person.prototype={

    "name":"zs",

    "age":"18",

    "address":"China",

    "say":function(){

    alert("今天天气特别好!");

    }

    }

    // var p=new person();

    // p.say(); 原型链解析:

    //1,首先到p对象中查找是否有say方法。

    //2,p.__proto__ === person.prototype ,

    //   所以直接到person.prototype中查找是否有say方法。

    //3,最后到Object.prototype中去查找,Object.prototype=null.

    var student=function(){} // 子方法

    //prototype是原型对象,可以随便赋值。

    //p.__proto__是原型链,其赋值对象只能是person.prototype

    student.prototype=new person();//解析为:创建student的实例原型为:person。

    //上面一行已经定义了student.prototype,这里就不能再定义了

    //否则就会覆盖上面的内容。

    //必须注释掉,否则会覆盖上面student.prototype的定义

        //student.prototype={

    // name:"zheng",

    // age:18,

    // address:"China",

    // hello:function(){

    // alert("今天天气真好!");

    // }

    // }

    student.prototype.hello=function(){

    alert("您好啊");

    }

    student.prototype.name="覆盖前面的name";

    var stu=new student();//实例化student对象

    // stu.say();

    //原型链解析:都是在__proto__原型链上进行解析的,stu.__proto__ === student.prototype

    //1,首先在stu本身查看是否有say方法。

    //2,再到stu.__proto__中查看是否有say方法。

    //3,因 stu=new student(); 所以,stu.__proto__ 指向 student.prototype。

    //4,因 student.prototype=new person();

    //   所以,stu.__proto__ 等于直接指向 person.prototype

    //5,直接在person.__proto__中查找say方法

    //6,最后 var person = function(){} 是Object(){}这个函数实例化而来的,如:

    // var person=new Object();,

    // 所以,person.__proto__ 指向 object.prototype=null

    //执行stu.say()时查找say方法的过程:注意查找__proto__对象就等于查找prototype对象。

    //stu-->stu.__proto__-->person.__proto__-->obj.__proto__

    //原型链,可以使用作用域链的模式来理解:

    //1,子对象的属性是由内向外进行查找,存在多个值,取最近的值。如果不存在,报错或者undefined

    console.log(stu.address);//返回 China

    //子对象会继承父对象的属性,且是由内向外进行查找,存在多个值,取最近的值。如果不存在,报错或者undefined

    console.log(stu.name);//返回:覆盖前面的name

    stu.hello();//返回 您好啊

    console.log(person.name);//name是函数的关键字,返回函数名称。

    console.log(person.age);//没有实例化person,所以返回 undefined

    var p=new person();//实例化person对象

    console.log(p.name);//返回 zs

    //---------

    //分析:原型链的执行过程

        function Person(name,age,address){

        this.name=name;

        this.age=age;

        this.address=address;

        }

        Person.prototype.hello=function(){

        return "大家好,我叫:"+this.name+",今年"+this.age+"岁了。家住在:"+this.address;

        }

        function Student(grade,sex){

        this.grade=grade;

        this.sex=sex;

        }

        //谨记:指定prototype原型时,一定要为其父对象以及实际参数。

        //说白了就是以某某为模板(基础)作为创建对象的标准。

        Student.prototype=new Person("zs",18,"清源乡");

        Student.prototype.showInfo=function(){

        return "我读"+this.grade+"年纪了,我的性别是:"+this.sex;

        }

        //Person {name: undefined, age: undefined, address: undefined},没有跟参数,默认undefined

        // console.log(new Person());

        var stu=new Student(3,"male");

        //以下是stu.__proto__本身原型链对象的属性

        console.log(stu.grade);//3

        console.log(stu.sex);//male

        console.log(stu.showInfo());//我读3年纪了,我的性别是:male

        //以下是stu父对象person.__peroto__的原型链对象的属性

        console.log(stu.name);//zs

        console.log(stu.age);//18

        console.log(stu.hello());//大家好,我叫:zs,今年18岁了。家住在:清源乡

        //分析stu.showInfo()原型链的执行过程:

        //1,执行stu.showInfo()时

        //   首先会在stu中查找showInfo方法

        //   再到stu.__proto__中查找showInfo方法 

        //2,因 var stu=new Student(3,"male"); 实例化Student对象

        // 所以 stu.__proto__=Student.prototype。

        //3,因 Student.prototype=new Person("zs",18,"清源乡");

        // 所以 stu.__proto__ = Student.prototype = Person.prototype

        //   即:会在Person.__proto__中查找showInfo方法

        //4,如果还没找到showInfo方法,那么会执行到原型链顶层object.prototype,

        // 原型链的顶层就是Object.prototype,而这个对象的是没有原型对象的。

        //综上所述:原型链就是基于__proto__查找指定属性的过程。

        //上诉原型链为:

        /* stu-->stu.__proto__-->(Student.prototype).__proto__-->

        (Person.prototype).__proto__-->Object.prototype */

    </script>

    <!-- stu.name取值:在原型链中就近原则取值 -->

    <script type="text/javascript"> 

    function person(){

    this.say=function(){

    alert("say");

    }

    this.name="1111";

    //等价于在person里面声明 this.name="1111";

    // person.prototype.name="1111";

    var student=function(){

    this.name="zheng";

    this.age=18;

    /*this.hello=function(){

    console.log("hello");

    }*/

    } // 子方法

    student.prototype.address="china";

    student.prototype.hello=function(){

    console.log("hello");

    }

    student.prototype.name="2222";

    //以下三行代码一起解析:创建student实例的原型为:person,

    //所有的属性和方法都以person函数里面的定义为标准

    //按照程序从上到下执行,查找stu.name的值。

    //1,到stu本身查找。  

    //this.name="zheng";  如果没有定义则继续向外查找

    //2,stu.__proto__ 指向 student.prototype  因student.prototype=new person();

    //3,所以 stu.__proto__ 直接指向 person.prototype

    //person.prototype.name="1111";等价于this.name="1111";如果没有定义就报错或者未定义undefined.

    //4,即:直接在(person.prototype).__proto__ 中查找

    //5,最后到原型链最顶层Object.prototype为空:null.

    //上面的student.prototype.name="2222"; 这句话是没有执行的,所以stu.name不可能为2222.

    //当,如果两行代码的执行先后顺序改变一下,那么stu.name的值就一定会是"2222"。因为给重定义了,如下:先执行 1  再执行 2

    //1,student.prototype=new person();

    //2,student.prototype.name="2222";

    student.prototype=new person();

    var stu=new student();//实例化student对象

    console.log(stu.name);//返回: 1111

    </script>

    ///--------------------

    <!-- 构造函数继承 --> 

    什么是构造函数:就是在函数里面使用 this 关键词来定义属性及其方法

    在子类内部构造父类对象来实现继承:

    child.ob=parent;//把父类对象赋值给子类中的一个属性

    child.ob(name,age,sex);//参数:需要继承父类中的属性,需要继承几个些几个

    <script>

    //父类中的参数一定小于等于子类参数,子类参数即属性一定是大于等于父类属性

    function People(name,age,sex,height){

    this.name=name;

    this.age=age;

    this.sex=sex;

    this.height=height;

    this.say=function(){

    console.log("我的名字叫:"+this.name+",身高为:"+this.height+"年龄:"+this.age+",this.sex:"+this.sex);

    }

    }

    function Student(name,age,height,grade,num){

    this.obj=People;//在子类中构造一个父类对象,赋值给子类的一个属性

    //这里只继承People中的name,age,其中sex没有继承,也没有写该值,默认值为undefined

    this.obj(name,age);//需要继承几个属性就写几个属性的参数

    this.height=height;

    this.grade=grade;

    this.num=num;

    this.hello=function(){

    //父类中的sex属性没有继承,所以this.sex=undefined

    //下面的this.name this.age的值是从父类中继承过来的,其他都是子类自定义的。

    console.log("name:"+this.name+",age:"+this.age+",sex:"+this.sex+",height:"+this.height+",grade:"+this.grade+",num:"+this.num);

    }

    }

    var pe=new People("zs",28,"male",170);

    console.log(pe.height); //返回 170

    pe.say();//我的名字叫:zs,身高为:170年龄:28,this.sex:male

    var stu=new Student("zheng",30,"male",180,"博士",88);

    console.log(stu.height);//返回 180

    console.log(stu.grade);//返回 博士

    console.log(stu.num);//返回 88

    stu.say();//返回:我的名字叫:zheng,身高为:male年龄:30,性别:undefined    sex未定义

    stu.hello();//返回 name:zheng,age:30,sex:undefined,height:male,grade:180,num:博士 

    </script>

    <!-- 使用多种方式进行构造函数继承 -->

    <script>

    function Animal(name,count){

    this.name=name;

    this.count=count;

    this.getInfo=function(){

    console.log("动物名称:"+this.name+",数量:"+this.count);

    }

    }

    //第一种方式继承父元素的所有属性及其方法:

    function Cat(name,count){

    this.obj=Animal;//普通方式继承

    this.obj(name,count);

    }

    //第二种方式继承父元素的所有属性及其方法:

    function Dog(name,count){

    Animal.call(this,name,count);//使用call间接方式继承

    }

    //第三种方式继承父元素的所有属性及其方法:

    function Pig(name,count){

    Animal.apply(this,[name,count]);//使用apply间接方式继承

    }

    var an=new Animal("猴子",88);

    var cat=new Cat("猫",99);

    var dog=new Dog("狗",100);

    var pig=new Pig("猪",200);

    an.getInfo();

    cat.getInfo();

    dog.getInfo();

    pig.getInfo();

    </script>

    //-------------------------

    js中的关键词

    包括:instanceof delete call apply arguments callee this

    所有对象的本质都是Object对象

    delete 只能删除对象的属性,对于其他一概没用。原型链的属性及方法无效。

    callee是arguments的一个属性  指函数本省  

    arguments存在于每个函数中,详见:arguments搜狗

    1,instanceof 

    // a instanceof b  检测a对象是否是b的实例,某种程度上理解是原型proto

    function text(){};

    var t=new text();

    console.log(t instanceof text);//返回 true 解析: t 是 text对象的实例

    var s=text;

    console.log(typeof s);//返回 function

    console.log(typeof text);//返回 function 

    console.log(typeof 1);//number

    var str="woaini";

    console.log(typeof str);//string

    console.log(s === text);//true

    console.log(s instanceof text);//false

    console.log(s instanceof Object);//true  Object首字母大写才表示js中的全局对象,否则object只是一个变量

    2,delete  删除对象的属性,对于删除对象的方法,变量,以及原型链中的属性都是无效的。

           总归一句话:delete只是用来删除对象的属性,其他一概不管。

    function text(name){

    this.name=name;

    this.say=function(){

    console.log(this.name);

    }

    }

    var t=new text("zheng");

    // console.log(t.name);//返回 zheng

    // delete t.name;//删除 t的属性name

    // console.log(t.name);//返回 undefined

    t.say();//返回:zheng , delete只用于删除属性,对方法无效。并且都会执行say里面代码

    delete t.say();//返回:zheng , delete只用于删除属性,对方法无效。并且都会执行say里面代码

    t.say();//返回:zheng , delete只用于删除属性,对方法无效。并且都会执行say里面代码

    //无法删除变量。无法删除原型链中的属性和变量

    var a="love";

    console.log(a);//返回 love

    delete a;

    console.log(a);//返回 love

    3,call apply 

    <script>

    function add(a,b){

    console.log(a+b);

    }

    function substract(a,b){

    console.log(a-b);

    }

    // a.fn.call(b,x1,x2,x3...) == a.fn.apply(b,[x1,x2,x3...])

    // 表示使用b调用a中的fn的方法,跟的参数是x1,x2,x3...

    /*add.call(substract,10,3);//返回 13 

    add.apply(substract,[10,3]);//返回 13 

    add.call(substract,10,3,4,6,7);//返回 13。多余参数直接忽略,不会报错。*/

    function Animal(name){

    this.name=name;

    this.getInfo=function(){

    console.log(this.name);

    }

    }

    function Cat(name){

    this.name=name;

    }

    var ani=new Animal("pig");

    var cat=new Cat("cat");

    //使用cat对象调用ani对象的getInfo方法,即说白了就是:

    /*cat.getInfo=function(){

    console.log(this.name);

    }*/

    ani.getInfo.call(cat);//返回 cat

    ani.getInfo.apply(cat);//返回 cat

    、、、、

        //间接调用:

    //1,对象没有call和apply方法,只有函数有

    //2,apply可以将数组和类数组一次性的传递进函数中,call只能一个一个的传

        //解析:call apply 两个都是调用其他对象的方法。

        //唯一不同的是参数:

        //obj.call(otherObj,a,b,c,d...); call的参数是一个一个传

        //obj.apply(otherObj,[]); apply的参数是数组

        //这里的obj可以是[],{}对象,也可以是全局作用对象window 或者某个局部作用域对象

        var name="xm";

    var person={};

    person.name="xh";

    person.getName=function(){

    return this.name;

    }

    console.log(person.getName());//输出:xh

    //这里的window用于改变person.getName里面的this变成:window,即返回window.name的值

    console.log(person.getName.call(window));//输出:xm

    //这里的window用于改变person.getName里面的this变成:window,即返回window.name的值

    console.log(person.getName.apply(window));//输出:xm

    //解析:person.getName.apply(window),使用window借用person的getName方法:

    // window.getName=function(){

    // return this.name;  

    // }

    // window.name="xm";

    var arr=[2,5];

    function add(a,b){

    return a+b;

    }

    //直接调用

    console.log(add(3,6));

    //使用了间接调用,call(指定作用域对象,argument1,argumen2...)

    console.log(add.call(window,2,5));

    //这里间接调用了window下面的arr的数组值, apply(指定作用域对象,数组)

    console.log(add.apply(window,arr));

    // 解析:add.apply(window,arr); 使用window借用add的方法,这里add本来前面有一个window。因为add方法本来就是一个全局变量。

    // window.add(2,5){

    // return 2+5;

    // }

    </script>

    两个数组使用concat和apply进行合并

    <script>

    var arr1=[1,2,3,4];

    var arr2=["a","b","c","d"];

    alert(arr1.concat.apply(arr2,arr1));

    alert(arr2.concat.apply(arr1,arr2));

    </script>

    4,arugments callee

    <script>

    function demo(){

    console.log(arguments.callee);//返回dome函数体本身。

    //console.log(arguments.callee());//报错,最大堆栈内存溢出,即死循环了

    }

    demo();

    function sum(i){

    if (i<=1) {

    return i=1;

    }else{

    // return i+sum(i-1);等价于下面一行

    return i + arguments.callee(i-1);

    }

    }

    console.log(sum(5));

    </script>

    5,arguments  只有函数才有arguments属性

       arugments.length 参数长度

       arguments[1]  第二个参数

       arguemnts 使用 for循环遍历

    <script>

    function len(){

    console.log(arguments.length);//返回 参数长度

    /*for(var p in arguments){//遍历所有参数

    console.log(p+":"+arguments[p]);//这里表示的是索引,arguments[p]索引对应的值

    }*/

    //上下两种遍历方法都可以

    for (var i = 0; i < arguments.length; i++) {

    console.log(i+":"+arguments[i]);

    }

    console.log(arguments[2]);//输出 c 

    }

    len("a","b","c","d");

    </script>

    6,this 

    a,如果text作为对象在下文实例化,那么this就是实例化后对象本身,

    b,如果当作方法,没有实例化,那么this就window对象

    <script>

    function text(){

    this.x=1;//就是函数的属性

    //如果text作为对象在下文实例化,那么this就是实例化后对象本身,如果当做方法,没有实例化,那么this就window对象

    console.log(this);//这里的this就是下面实例化的对象 t

    }

    text();

    var t=new text();//实例化对象,方法text()中的this就是 t 对象

    console.log(t.x);//输出 1

    //----

    function text1(){//没有实例化,则this就是window对象

    this.x=1;

    console.log(this.x);//没有实例化,则this就是window对象

    }

    text1();//输出 1 //没有实例化,则this就是window对象

    /*var x=1;

    function xx(){//xx本省属于全局变量window.xx

    this.x=0;//等价于把全局变量 window.x=0;

    console.log(this);//window对象

    }

    xx();//执行函数 修改 x=0;

    console.log(x);//输出 0*/

    </script>

    ///call apply  jianjiediaoyong(间接调用)

    <!-- 在call  apply 情况的this  

    this指向的是call apply中的第一个参数

    window.a.call/apply(b,x1,x2...),表示b借用window下面的a方法,

    这里借用的都是call/apply前面的那个方法。 -->

    <script>

    var x=0;

    function text(){

    console.log(this.x);

    console.log(this);

    }

    var o={};

    o.x=1;

    o.m=text;

    //这里的this是window,其实下面的o是全局变量,即:window.o

    o.m.apply();//输出:0 //window.o.m.apply()===>window.x

    //window.o.m.apply(o),表示使用o对象借用window下面的o的m方法,

    //这里的this是o对象,而不是window,window被o取代了。即调用的是o.x=1

    o.m.apply(o);//输出:1 //即:使用o对象这个作用域代替window.o.m.apply()

    </script>

    <!-- 对象冒充 duixiangmaochong -->

    <script>

    function person(name,age){

    this.name=name;

    this.age=age;

    this.say=function(){

    console.log("name:"+this.name+",age:"+this.age);

    }

    }

    person.prototype.walk=function(){

    console.log("walk....");

    }

    function student(name,age,sex){

    this.obj=person;//冒充person,传递特权属性和特权方法给子类

    this.obj(name,age);//传递特权属性和特权方法给子类

    this.sex=sex;

    this.hello=function(){

    console.log("name:"+this.name+",age:"+this.age+",sex:"+this.age);

    }

    }

    //stu是student实例对象,继承了person的所有属性和方法

    var stu=new student("zs",21,"male");

    console.log(stu.name);//zs

    console.log(stu.say);//say函数体

    console.log(stu.walk);//输出undefined,如果执行stu.walk()方法,就会报错,因为不存在walk方法。

    //注意,stu只能继承person中的特权属性和特权方法,不能继承原型对象中的方法和属性。

    //所以上面stu.walk()是无法调用到,会报错,stu.walk is undefined

    </script>

    1,原型继承

    <script type="text/javascript"> //原型:是利用prototype添加属性和方法//原型链:JS在创建对象(不论是普通对象还是函数对象)的时候,//都有一个__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype//原型的值可以是一个对象,也可以是null Object.__proto__指向 null 。//js对象有一个__proto__属性,指向它的构造函数的prototype属性//js中所有的函数都有一个prototype属性,该属性引用了一个对象,即原型对象,也简称原型/*__proto__ 和 prototype 的区别:1,__proto__ 是每个对象都有的属性。不是一个规范的属性,火狐有点不同。2,prototype 是每个函数都有的属性在多数情况下,__proto__ === constructor.prototype 返回 trueObject.create()创建的对象不适用此等式*/

    //js继承://原型:使用prototype对象来添加属性和方法var person = function(){};//创建一个空方法var p = new person();// 实例化p对象,经历三个阶段:// 1,var p={} 实例化一个p对象// 2,p.__proto__ = person.prototype,出于原型链含义, __proto__是任何对象都自带的属性。// JS在创建对象(不论是普通对象还是函数对象)的时候,//都有一个__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype// 3,创建对象(初始化), p ==> person.call(p)/*console.log(person.prototype);//{constructor: ƒ}  构造函数console.log(p.__proto__);//{constructor: ƒ}  构造函数console.log(person.prototype instanceof Object);//返回trueconsole.log(p.__proto__ instanceof Object);//返回trueconsole.log(person.prototype === p.__proto__);//返回true*//////---------function pText(){this.say=function(){alert("111");}}pText.prototype.play=function(){alert("22");}pText.prototype.name="haha";var cText=function(){this.eat=function(){alert("33");}};cText.prototype.name="lala";cText.prototype=new pText();var person=new cText();//注意点:返回的不是 lala,而是 haha,这里先执行name="lala",//再继承父元素中的name="haha",所以后面覆盖前面自定义的name。console.log(person.name);//返回 hahaperson.eat();//33person.say();//11person.play();//22</script>//-----------<script>//prototype是原型(理解为基本框架), __proto__是原型链var a={};//a是一个对象,创建a的构造函数:var a=new Object();//根据原型链的定义:js创建任何对象,都内置一个__proto__属性,//指向创造它的函数对象的原型对象prototype,即:a.__proto__===Object.prototype.console.log(a.__proto__);//页面第一次加载控制台显示:Object,刷新就不是了console.log(a.__proto__===Object.prototype);//返回 trueconsole.log(a.__proto__===a.constructor.prototype);//返回 trueconsole.log(a.prototype);//返回 undefined 未定义,函数才有prototype属性
    var b=function(){};var j=new b();console.log(j.__proto__);//页面第一次加载控制台显示:Object,刷新就不是了console.log(b.prototype);//页面第一次加载控制台显示:Object,刷新就不是了////根据原型链的定义:js创建任何对象,都内置一个__proto__属性,//指向创造它的函数对象的原型对象prototype,即:f.__proto__===b.prototype.console.log(j.__proto__===b.prototype);//返回 true
    var A = function(){};var a = new A();// a.say();//不存在say方法会报错的// 原型链:a属性中查找---》 a.__proto__ ---》 Object.__proto__===null,不存在就报错。// 这就是一条围绕__proto__的原型链。// 原型链的顶层就是Object.prototype,而这个对象的是没有原型对象的。/*原型链解析:a.say();1,首先会在a内部属性中查找 say方法。2,没找到,则会在 a.__proto__原型对象 中查找 say方法 3,没找到,则会在 Object.__proto__原型对象 中查找 say方法,因为没找到,且Object.__proto__===null,所以a.say()就会报错。*/console.log(a.__proto__); //A {}(即构造器function A 的原型对象)console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)//原型链的顶层就是Object.prototype===nullconsole.log(a.__proto__.__proto__.__proto__); //null //再继续往下就是语法错误console.log(a.__proto__.__proto__.__proto__.__proto__); //报错,不存在该//---------////分析:原型链的执行过程var person = function(){} //父方法person.prototype={"name":"zs","age":"18","address":"China","say":function(){alert("今天天气特别好!");}}// var p=new person();// p.say(); 原型链解析://1,首先到p对象中查找是否有say方法。//2,p.__proto__ === person.prototype ,//   所以直接到person.prototype中查找是否有say方法。//3,最后到Object.prototype中去查找,Object.prototype=null.
    var student=function(){} // 子方法//prototype是原型对象,可以随便赋值。//p.__proto__是原型链,其赋值对象只能是person.prototypestudent.prototype=new person();//解析为:创建student的实例原型为:person。//上面一行已经定义了student.prototype,这里就不能再定义了//否则就会覆盖上面的内容。//必须注释掉,否则会覆盖上面student.prototype的定义    //student.prototype={// name:"zheng",// age:18,// address:"China",// hello:function(){// alert("今天天气真好!");// }// }student.prototype.hello=function(){alert("您好啊");}student.prototype.name="覆盖前面的name";var stu=new student();//实例化student对象// stu.say();//原型链解析:都是在__proto__原型链上进行解析的,stu.__proto__ === student.prototype//1,首先在stu本身查看是否有say方法。//2,再到stu.__proto__中查看是否有say方法。//3,因 stu=new student(); 所以,stu.__proto__ 指向 student.prototype。//4,因 student.prototype=new person();//   所以,stu.__proto__ 等于直接指向 person.prototype//5,直接在person.__proto__中查找say方法//6,最后 var person = function(){} 是Object(){}这个函数实例化而来的,如:// var person=new Object();,// 所以,person.__proto__ 指向 object.prototype=null//执行stu.say()时查找say方法的过程:注意查找__proto__对象就等于查找prototype对象。//stu-->stu.__proto__-->person.__proto__-->obj.__proto__//原型链,可以使用作用域链的模式来理解://1,子对象的属性是由内向外进行查找,存在多个值,取最近的值。如果不存在,报错或者undefinedconsole.log(stu.address);//返回 China//子对象会继承父对象的属性,且是由内向外进行查找,存在多个值,取最近的值。如果不存在,报错或者undefinedconsole.log(stu.name);//返回:覆盖前面的namestu.hello();//返回 您好啊console.log(person.name);//name是函数的关键字,返回函数名称。console.log(person.age);//没有实例化person,所以返回 undefinedvar p=new person();//实例化person对象console.log(p.name);//返回 zs//---------//分析:原型链的执行过程    function Person(name,age,address){    this.name=name;    this.age=age;    this.address=address;    }    Person.prototype.hello=function(){    return "大家好,我叫:"+this.name+",今年"+this.age+"岁了。家住在:"+this.address;    }
        function Student(grade,sex){    this.grade=grade;    this.sex=sex;    }    //谨记:指定prototype原型时,一定要为其父对象以及实际参数。    //说白了就是以某某为模板(基础)作为创建对象的标准。    Student.prototype=new Person("zs",18,"清源乡");    Student.prototype.showInfo=function(){    return "我读"+this.grade+"年纪了,我的性别是:"+this.sex;    }    //Person {name: undefined, age: undefined, address: undefined},没有跟参数,默认undefined    // console.log(new Person());    var stu=new Student(3,"male");    //以下是stu.__proto__本身原型链对象的属性    console.log(stu.grade);//3    console.log(stu.sex);//male    console.log(stu.showInfo());//我读3年纪了,我的性别是:male    //以下是stu父对象person.__peroto__的原型链对象的属性    console.log(stu.name);//zs    console.log(stu.age);//18    console.log(stu.hello());//大家好,我叫:zs,今年18岁了。家住在:清源乡    //分析stu.showInfo()原型链的执行过程:    //1,执行stu.showInfo()时    //   首先会在stu中查找showInfo方法    //   再到stu.__proto__中查找showInfo方法     //2,因 var stu=new Student(3,"male"); 实例化Student对象    // 所以 stu.__proto__=Student.prototype。    //3,因 Student.prototype=new Person("zs",18,"清源乡");    // 所以 stu.__proto__ = Student.prototype = Person.prototype    //   即:会在Person.__proto__中查找showInfo方法    //4,如果还没找到showInfo方法,那么会执行到原型链顶层object.prototype,    // 原型链的顶层就是Object.prototype,而这个对象的是没有原型对象的。    //综上所述:原型链就是基于__proto__查找指定属性的过程。    //上诉原型链为:    /* stu-->stu.__proto__-->(Student.prototype).__proto__-->    (Person.prototype).__proto__-->Object.prototype */</script>
    <!-- stu.name取值:在原型链中就近原则取值 --><script type="text/javascript"> function person(){this.say=function(){alert("say");}this.name="1111";} //等价于在person里面声明 this.name="1111";// person.prototype.name="1111";var student=function(){this.name="zheng";this.age=18;/*this.hello=function(){console.log("hello");}*/} // 子方法student.prototype.address="china";student.prototype.hello=function(){console.log("hello");}student.prototype.name="2222";//以下三行代码一起解析:创建student实例的原型为:person,//所有的属性和方法都以person函数里面的定义为标准//按照程序从上到下执行,查找stu.name的值。//1,到stu本身查找。  //this.name="zheng";  如果没有定义则继续向外查找//2,stu.__proto__ 指向 student.prototype  因student.prototype=new person();//3,所以 stu.__proto__ 直接指向 person.prototype//person.prototype.name="1111";等价于this.name="1111";如果没有定义就报错或者未定义undefined.//4,即:直接在(person.prototype).__proto__ 中查找//5,最后到原型链最顶层Object.prototype为空:null.//上面的student.prototype.name="2222"; 这句话是没有执行的,所以stu.name不可能为2222.//当,如果两行代码的执行先后顺序改变一下,那么stu.name的值就一定会是"2222"。因为给重定义了,如下:先执行 1  再执行 2//1,student.prototype=new person();//2,student.prototype.name="2222";student.prototype=new person();var stu=new student();//实例化student对象console.log(stu.name);//返回: 1111</script>

    2,<!-- 构造函数继承 --> 什么是构造函数:就是在函数里面使用 this 关键词来定义属性及其方法在子类内部构造父类对象来实现继承:child.ob=parent;//把父类对象赋值给子类中的一个属性child.ob(name,age,sex);//参数:需要继承父类中的属性,需要继承几个些几个<script>//父类中的参数一定小于等于子类参数,子类参数即属性一定是大于等于父类属性function People(name,age,sex,height){this.name=name;this.age=age;this.sex=sex;this.height=height;this.say=function(){console.log("我的名字叫:"+this.name+",身高为:"+this.height+"年龄:"+this.age+",this.sex:"+this.sex);}}function Student(name,age,height,grade,num){this.obj=People;//在子类中构造一个父类对象,赋值给子类的一个属性//这里只继承People中的name,age,其中sex没有继承,也没有写该值,默认值为undefinedthis.obj(name,age);//需要继承几个属性就写几个属性的参数this.height=height;this.grade=grade;this.num=num;this.hello=function(){//父类中的sex属性没有继承,所以this.sex=undefined//下面的this.name this.age的值是从父类中继承过来的,其他都是子类自定义的。console.log("name:"+this.name+",age:"+this.age+",sex:"+this.sex+",height:"+this.height+",grade:"+this.grade+",num:"+this.num);}}var pe=new People("zs",28,"male",170);console.log(pe.height); //返回 170pe.say();//我的名字叫:zs,身高为:170年龄:28,this.sex:malevar stu=new Student("zheng",30,"male",180,"博士",88);console.log(stu.height);//返回 180console.log(stu.grade);//返回 博士console.log(stu.num);//返回 88stu.say();//返回:我的名字叫:zheng,身高为:male年龄:30,性别:undefined    sex未定义stu.hello();//返回 name:zheng,age:30,sex:undefined,height:male,grade:180,num:博士 </script><!-- 使用多种方式进行构造函数继承 --><script>function Animal(name,count){this.name=name;this.count=count;this.getInfo=function(){console.log("动物名称:"+this.name+",数量:"+this.count);}}//第一种方式继承父元素的所有属性及其方法:function Cat(name,count){this.obj=Animal;//普通方式继承this.obj(name,count);}//第二种方式继承父元素的所有属性及其方法:function Dog(name,count){Animal.call(this,name,count);//使用call间接方式继承}//第三种方式继承父元素的所有属性及其方法:function Pig(name,count){Animal.apply(this,[name,count]);//使用apply间接方式继承}var an=new Animal("猴子",88);var cat=new Cat("猫",99);var dog=new Dog("狗",100);var pig=new Pig("猪",200);an.getInfo();cat.getInfo();dog.getInfo();pig.getInfo();</script>
    3,call apply 继承
    <script>function add(a,b){console.log(a+b);}function substract(a,b){console.log(a-b);}// a.fn.call(b,x1,x2,x3...) == a.fn.apply(b,[x1,x2,x3...])// 表示使用b调用a中的fn的方法,跟的参数是x1,x2,x3.../*add.call(substract,10,3);//返回 13 add.apply(substract,[10,3]);//返回 13 add.call(substract,10,3,4,6,7);//返回 13。多余参数直接忽略,不会报错。*/
    function Animal(name){this.name=name;this.getInfo=function(){console.log(this.name);}}function Cat(name){this.name=name;}var ani=new Animal("pig");var cat=new Cat("cat");//使用cat对象调用ani对象的getInfo方法,即说白了就是:/*cat.getInfo=function(){console.log(this.name);}*/ani.getInfo.call(cat);//返回 catani.getInfo.apply(cat);//返回 cat、、、、    //间接调用://1,对象没有call和apply方法,只有函数有//2,apply可以将数组和类数组一次性的传递进函数中,call只能一个一个的传    //解析:call apply 两个都是调用其他对象的方法。    //唯一不同的是参数:    //obj.call(otherObj,a,b,c,d...); call的参数是一个一个传    //obj.apply(otherObj,[]); apply的参数是数组    //这里的obj可以是[],{}对象,也可以是全局作用对象window 或者某个局部作用域对象
        var name="xm";var person={};person.name="xh";person.getName=function(){return this.name;}console.log(person.getName());//输出:xh//这里的window用于改变person.getName里面的this变成:window,即返回window.name的值console.log(person.getName.call(window));//输出:xm//这里的window用于改变person.getName里面的this变成:window,即返回window.name的值console.log(person.getName.apply(window));//输出:xm//解析:person.getName.apply(window),使用window借用person的getName方法:// window.getName=function(){// return this.name;  // }// window.name="xm";
    var arr=[2,5];function add(a,b){return a+b;}//直接调用console.log(add(3,6));//使用了间接调用,call(指定作用域对象,argument1,argumen2...)console.log(add.call(window,2,5));//这里间接调用了window下面的arr的数组值, apply(指定作用域对象,数组)console.log(add.apply(window,arr));// 解析:add.apply(window,arr); 使用window借用add的方法,这里add本来前面有一个window。因为add方法本来就是一个全局变量。// window.add(2,5){// return 2+5;// }</script>
    两个数组使用concat和apply进行合并<script>var arr1=[1,2,3,4];var arr2=["a","b","c","d"];alert(arr1.concat.apply(arr2,arr1));alert(arr2.concat.apply(arr1,arr2));</script>

    javascript 面向对象的声明:Object是所有对象的基类,根,所有的javascript对象都是Object延伸的。
    1,字面式对象声明方式var obj={  属性名称:属性值,  属性名称:属性值,  属性名称:属性值,  属性名称:属性值,  方法名称:function(){},  方法名称:function(){}   }   <script>      var person={      name:"zhangsan",      age:28,      address:"清源乡",      eat:function(foot){      console.log("我最爱吃:"+foot);      },      play:function(game){      console.log("我最喜欢玩:"+game)      }      }      console.log(person.name);      person.play("篮球");      person.eat("牛排");   </script>
    2,使用new操作符后面跟Object构造函数var obj=new Object();obj.属性名称=属性值;obj.属性名称=属性值;obj.属性名称=属性值;obj.属性名称=属性值;obj.方法=function(str){方法体}<script>   var person=new Object();   person.name="zheng";   person.age=28;   person.eat=function(a){   console.log("我喜欢吃:"+a);   }   console.log(person.age);   person.eat("苹果");</script>
    3,js构造方法声明对象function person([a,b,c]){this.属性名称=a;this.属性名称=b;this.属性名称=c;this.方法名称=function(){方法体...}}    <script>       //function person(a,b,c,d){ 等价下面一句,参数的[]可以省略       function person([a,b,c,d]){       this.name=a;       this.age=b;       this.eat=function(c){       console.log("我在吃:"+c);       };       this.play=function(d){       console.log("我在玩:"+d);       }       }       //第一次实例化       var zs=new person(["zhangsan","18","牛排","game"]);       //var zs=new person("zhangsan","18","牛排","game");上面一句的[]可以省略,等价       console.log(zs.name);       zs.eat("love");       //第二次实例化       var xm=new person(["xiaoming","20","土豆片","王者"]);   xm.play("王者");//注意:this 代表当前对象,zs 和 xm两个实例是独立的,函数内只能使用this 访问属性和方法。//  var num=0; var result=num++; 先赋值再加加 即:result=0,num=0+1=1;//  var num=0; var result=++num; 先加加再赋值 即:num=0+1,result=1       </script>
        <!-- 封装函数,创建object对象的两种方式: -->    <script type="text/javascript">      //工厂模式    function createObject(name,age){    var person = new Object();    person.name=name;//person.name是属性 name是属性值    person.age=age;//person.age是属性 age是属性值    person.say=function(){    alert("大家好,我叫:"+this.name+",今年:"+this.age+"岁!");    };    person.play=function(){    alert("今天天气真好!");    };    return person;//////重点:必须返回person本身//////    }    //实例化一个对象,可以无限实例化对象    var obj1=createObject("zhangsan",18);    console.log(obj1.name);//返回 zhangsan    obj1.say();//返回 大家好,我叫:zhangsan,今年18岁!    //实例化一个对象,可以无限实例化对象    var obj2=new createObject("lisi",29);    console.log(obj2.name);//返回 lisi     obj2.play();//返回 今天天气真好!    //obj1 和 obj2 没有任何关系,都是不同的对象,不同的个体    //任何模式下,同种模式创建出来的不同对象都是独立存在的,彼此之间是没有关联的。
        // 构造函数模式    function per(name,age){    this.name=name;    this.age=age;    this.action=function(){    console.log("大家好,我叫:"+this.name+",今年:"+this.age+"岁了!");    }    }    var p1=new per("zs",29);    console.log(p1.name);    console.log(p1.age);    p1.action();    var p2=new per("ls",88);    console.log(p2.name);    console.log(p2.age);    p2.action();
        /*构造模式 和 工厂模式 创建对象的区别:    1,构造模式:不会显示创建对象,将属性赋值给this,不需要return对象    2,工厂模式:在方法内部创建object对象,返回object对象,属性和方法都是赋值给object对象*/    </script>
        <!-- 工厂模式 中的this是指window,而不是object对象,别弄错了-->    <script type="text/javascript">      function fn(name,age){//window.fn...父级作用域是window,所以里面也是一样    var person=new Object();    person.name=name;    person.age=age;    //this.name=name;//父级作用域是window    //this.age=age;//父级作用域是window    console.log(this);//输出对象是:window,查看控制台    return person;//千万记住要返回person对象,否则都是undefined    }    console.log(fn("zs",18));    console.log(fn("ls",33));    </script>
        <!-- js原型模式声明对象 -->    1,任何方法或者函数都自带prototype属性,且它是一个对象。    2,原型模式的根本:函数本身声明为空内容,利用prototype定义一些属性及方法。    function text(){    执行代码一定是空的。}text.prototype.属性 = 属性值;text.prototype.属性 = 属性值;text.prototype.属性 = 属性值;text.prototype.方法名称 = function(){执行代码}下面是两种方式进行原型模式声明对象<script type="text/javascript"> //js原型模式声明对象function text(){/*一定是空的;*/};text.prototype.name = "ls";text.prototype.age = 18;text.prototype.say=function(){alert("大家好,我的名字叫:"+text.prototype.name+",今年"+text.prototype.age+"岁了!");}//获取name的属性text.prototype.getName=function(){console.log(this);//返回:text {}return text.prototype.name;//这里不能使用text.prototype.name。不然报错。}//重新设置name的属性text.prototype.setName=function(name){return text.prototype.name=name;//这里不能使用text.prototype.name。不然报错。}//原型对象也必须实例化后才进行属性读取和设置。//调用:person.属性名称,中间不用加prototypevar person=new text();//实例化原型对象console.log(person.age);//返回18person.say();//返回:大家好,我的名字叫:ls,今年18岁了!console.log(person.getName());//返回 lsconsole.log(person.setName("zheng"));//设置name的属性:zheng</script><!-- 使用json的方式重写了js原型模式声明对象 --><script type="text/javascript"> function text(){};//这里使用json的方式重写了js原型模式声明对象text.prototype={name:"zs",age:23,say:function(){alert("大家好,我的名字叫:"+text.prototype.name+",今年"+text.prototype.age+"岁了!");},getName:function(){return text.prototype.name;//这里不能使用text.prototype.name。不然报错。},setName:function(name){return text.prototype.name=name;//这里不能使用text.prototype.name。不然报错。}}//原型对象也必须实例化后才进行属性读取和设置。//调用:person.属性名称,中间不用加prototypevar person=new text();//实例化原型对象console.log(person.age);//返回18person.say();//返回:大家好,我的名字叫:ls,今年18岁了!console.log(person.getName());//返回 lsconsole.log(person.setName("zheng"));//设置name的属性:zheng</script>
    <!-- js中使用混合模式声明对象(构造函数模式,原型模式) -->语法:function text(a,b,c){this.a=a;this.b=b;this.c=c;}text.prototype.say=function(){return "使用this读取属性a"+this.a;}text.prototype.setA=function(a){return "重置a的值:"+this.a=a;}var obj=new text("ls",18,"China");console.log(obj.a);console.log(obj.say());<script type="text/javascript"> function person(name,age,address){this.name=name;this.age=age;this.address=address;}/*person.prototype.hello=function(){console.log("大家好,我叫:"+this.name+",今天我"+this.age+"岁了!");}person.prototype.getAdd=function(){return this.address;}person.prototype.setAdd=function(address){return this.address=address;}*///上面代码直接简化如下person.prototype={like:"fruite",//随便添加属性或方法hello:function(){console.log("大家好,我叫:"+this.name+",今天我"+this.age+"岁了!");},getAdd:function(){return this.address;},setAdd:function(address){return this.address=address;}}var per=new person("ls",24,"China");console.log(per.like);//返回 furiteconsole.log(per.name);//返回 lsconsole.log(per.getAdd());// 返回 Chinaconsole.log(per.setAdd("American"));//返回 Americanper.hello();// 返回 大家好,我叫:ls,今天我24岁了!</script>

  • 相关阅读:
    蛙蛙推荐:简单介绍一下托管容器持久性(CMP),顺便征集一下.NET CMP2.0的改进方案
    15分钟内快速构建数据访问层(翻译)
    【蛙蛙推荐】.NET 2.0里使用强类型数据创建多层应用
    蛙蛙推荐:迎接web2.0:写一个RSS.HTC组件
    蛙蛙推荐:web下的授权简单解决方案
    J2me访问c# Web Services
    2006年3月份技术随笔
    声讨vs.net,讨论用户控件,编码等问题
    Hadoop中mapred包和mapreduce包的区别
    hbase MapReduce程序样例入门
  • 原文地址:https://www.cnblogs.com/Knowledge-is-infinite/p/11001240.html
Copyright © 2011-2022 走看看