zoukankan      html  css  js  c++  java
  • 03-js讲义(面向对象-构造函数)

    JS基本介绍

    • JS的用途:Javascript可以实现浏览器端、服务器端(nodejs)。。。
    • 浏览器端JS由以下三个部分组成:
      • ECMAScript:基础语法(数据类型、运算符、函数。。。)
      • BOM(浏览器对象模型):window、location、history、navigator。。。
      • DOM(文档对象模型):div、p、span。。。
    • ECMAScript又名es,有以下重大版本:
      • 旧时代:
        • es1.0。。。es3.1
      • 新时代:
        • es5
        • es6(es2015)
        • es7(es2016)、es8(es2017)

    数据类型

    • 基本数据类型(值类型):(数字、字符串、布尔值、null、undefined)
      • undefined类型?
        1.声明了一个变量,但没有赋值,值默认为undefined, 如 var a;
        2.声明一个变量了,并赋值了一个undefined的值,如 var b = undefined;
        3.一个对象中,获取某个不存在的属性,值为undefined
    • 复杂数据类型(引用类型):(对象)
      • 数组
      • 函数
      • 正则表达式
      • Date

    对象的基本使用

    创建一个对象

        var student={ 
            name:"李白" , //student有一个name属性,值为"李白"
            grade:"初一" ,
            //a、student有一个say属性,值为一个函数
            //b、student有一个say方法
            say:function(){
                console.log("你好");
            },
            run:function(speed){
                console.log("正在以"+speed+"米/秒的速度奔跑");
            }
        }
    

    对象是键值对的集合:对象是由属性和方法构成的 (ps:也有说法为:对象里面皆属性,认为方法也是一个属性)

    • name是属性 grade是属性
    • say是方法 run是方法

    对象属性操作

    获取属性:

    第一种方式:.语法

    • student.name 获取到name属性的值,为:"李白"
    • student.say 获取到一个函数

    第二种方式:[]语法

    • student["name"] 等价于student.name
    • student["say"] 等价于student.say

    注意:2种方式的差异:

    • .语法更方便,但是坑比较多(有局限性),比如:
      • .后面不能使用js中的关键字、保留字(class、this、function。。。)
      • .后面不能使用数字
        var obj={};
        obj.this=5; //语法错误
        obj.0=10;   //语法错误
    
    • []使用更广泛
      • o1[变量name]
      • ["class"]、["this"]都可以随意使用 obj["this"]=10
      • [0]、[1]、[2]也可以使用
        • obj[3]=50 = obj["3"]=50
      • 甚至还可以这样用:["[object Array]"]
        • jquery里面就有这样的实现
      • 也可以这样用:["{abc}"]
        • 给对象添加了{abc}属性

    设置属性

    • student["gender"]="男" 等价于: student.gender="男"
      • 含义:如果student对象中没有gender属性,就添加一个gender属性,值为"男"
      •  如果student对象中有gender属性,就修改gender属性的值为"男"
        
    • 案例1:student.isFemale=true
    • 案例2:student["children"]=[1,2,5]
    • 案例3:
        student.toShanghai=function(){   
            console.log("正在去往上海的路上")   
        }
    

    删除属性

    • delete student["gender"]
    • delete student.gender

    通过构造函数创建对象

    构造函数创建对象的例子:

    • var xiaoming = new Object() --> var xiaoming = {};

    • var now = new Date()

    • var rooms = new Array(1,3,5) --> var rooms = [1,3,5]

    • var isMale=/123/; ==> var isMale=new RegExp("123")

      • isMale是通过RegExp构造函数创建出来的对象
      • isMale是RegExp构造函数的实例
    • 以上例子中,Object、Date、Array都是内置的构造函数

    自定义一个构造函数来创建对象

    • 构造函数
        function Person(name,age){
            this.name=name;
            this.age=age;
        }
        var p1=new Person("赵云",18)
    

    等同于

        function person(name ){
            Object obj = new Object();
            obj.name  = name;
            obj.age  = age;
            return obj;
        }
        var p1 = new Person("赵云",18)
    
    • 说明:p1就是根据【Person构造函数】创建出来的对象

    构造函数的概念

    • 在JavaScript中,用new关键字来调用的函数,称为构造函数。构造函数首字母一般大写(PS:非强制,但这么写有助于区分构造函数和普通函数);
    • 任何函数都可以当成构造函数
      function CreateFunc(){ }
    • 只要把一个函数通过new的方式来进行调用,我们就把这一次函数的调用方式称之为:构造函数的调用
      • new CreateFunc(); 此时CreateFunc就是一个构造函数
      • CreateFunc(); 此时的CreateFunc并不是构造函数
    1)构造函数和普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函数,必须用new 运算符来调用,否则就是普通函数。
    2)this就是代表当前作用域对象的引用。如果在全局范围this 就代表window 对象,如果在构造函数体内,就代表当前的构造函数所声明的对象。
    

    关于new Object()

    • new Object()等同于对象字面量{}

    构造函数 new 的执行过程

    var p1 = new Person();

    • 1、new在内存中创建一个空的对象 (我们把这个对象称之为Person构造函数的实例)- p1
    • 2、让构造函数中的this指向这个新的对象-(p1)
    • 3、执行函数内部的代码,其中,操作this的部分就是操作了该实例(p1)
    • 4、返回值:
      • a、如果函数没有返回值(没有return语句),那么就会返回构造函数的实例(p1)
      • b、如果函数返回了一个基本数据类型的值,那么本次构造函数的返回值是该实例(p1)
          function fn(){
              ···
          }
          var f1 = new fn();    //f1就是fn的实例
      
          function fn2(){
              return "abc";
          }
          var f2 = new fn2();   //f2是fn2构造函数的实例
      
      • c、如果函数返回了一个复杂数据类型的值,那么本次函数的返回值就是该值
          function fn3(){
              return [1,3,5]; 
              //数组是一个对象类型的值,
              //所以数组是一个复杂数据类型的值
              //-->本次构造函数的真正返回值就是该数组
              //-->不再是fn3构造函数的实例
          }
          var f3=new fn3();   //f3还是fn3的实例吗?错
          //f3值为[1,3,5]
      

    注意:
    - f1 和 f2会自动含有一个constructor属性,指向它们的构造函数
    console.log(f1.constructor == fn); //true console.log(f2.constructor == fn2); //true
    - Javascript还提供了一个instanceof运算符,验证原型对象与实例对象之间的关系
    console.log(f1 instanceof fn); //true console.log(f2 instanceof fn2); //true

    构造函数模式的问题

    构造函数方法很好用,但是存在一个泄露内存(浪费内存)的问题。如下:

        function Person(name,age){
            this.name=name;
            this.age=age;
            this.say=function(){}
        }
        var p1=new Person();
        var p2=new Person();
        
        //p1对象和p2对象的say方法是否是同一个方法:false
        console.log(p1.say===p2.say);
        //由于say方法可能功能相似,但是不是同一个方法(没有指向同一块内存,会造成内存浪费)
    
        //解决方案1:(弊端:如果有多个需要共享的函数的话就会造成全局命名空间冲突的问题。)
        function say(){
            ···
        }
        function Person(name,age){
            this.name = name;
            this.age = age;
            this.say = say
        }
    
        //解决方案2:(基本上解决了构造函数的内存浪费问题。但是代码看起来有些许的格格不入···)
        var fns = {
            say: function(){
                ···
            },
            eat: function(){}
        }
        function Person(name,age){
            this.name = name;
            this.age = age;
            this.say = fns.say
        }
    
        //解决方案3(很完美!):把say方法写在他们共同的(父对象)中,他们共同的父对象,就可以通过:Person.prototype来获取
        //-->只要把say方法写在Person.prototype中,那么say方法就是同一个方法(所有对象实例需要共享的属性和方法直接定义在 `prototype` 对象上)
        Person.prototype.run=function(){
            console.log('时速500KM');
        }
        Person.prototype.sex = "男";
        //此时p1和p2都可以访问到run方法
        p1.run();
        p2.run();
        //验证p1.run和p2.run是否是同一个方法?
    
        //这时所有实例的sex属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。
        console.log(p1.run == p2.run); //true 指向同一个方法,这种方法避免了内存的浪费
        console.log(p1.run == Person.prototype.run);//true
    
        var p3=new Person();
        console.log(p3.run == p1.run); //true
        console.log(p3.run === p1.run);//true
        //结论:只要往某个构造函数的prototype对象中添加某个属性、方法,那么这样的属性、方法都可以被所有的构造函数的实例所共享
        //==>这里的【构造函数的prototype对象】称之为原型对象
        //  Person.prototype是 p1 p2 p3 的原型对象
        //  Person.prototype是Person构造函数的【实例】的原型对象
    
        //  Person的原型对象是谁呢?
        //  -->首先要知道Person的构造函数:-->Function
        //  -->所以Person的原型对象是:Function.prototype
    
        //  p1的原型对象是谁呢?
        //  -->首先要知道p1是谁创建的?    -->Person
        //  -->所以p1的原型对象时:     Person.prototype
    

    Prototype模式的验证方法

    为了配合prototype属性,Javascript定义了一些辅助方法,帮助我们使用它。

    • isPrototypeOf() 这个方法用来判断,某个proptotype对象和某个实例之间的关系。
        console.log(Person.prototype.isPrototypeOf(p1)); //true
      
    • hasOwnProperty() 每个实例对象都有一个hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。
        console.log(p1.hasOwnProperty('name')); //true
        console.log(p1.hasOwnProperty('sex')); //false
      
    • in 运算符
      • 可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。
        console.log('name' in p1); //true
        console.log('sex'in p1); //true
      
      • 还可以用来遍历某个对象的所有属性。
        for(var prop in p1) { console.log("p1[" + prop + "]=" + p1[prop]); }
      

    构造函数、原型对象、实例 三者关系:

    • 任何函数都具有一个 prototype 属性,该属性是一个对象
    • 构造函数的 prototype 对象默认都有一个 constructor 属性,指向 prototype 对象所在函数
    • 通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 __proto____proto__ 是非标准属性。)
    • 所有实例都直接或间接继承了原型对象的成员
  • 相关阅读:
    Geogebra指令
    大表修改表结构
    mongodb获取配置参数getParameter
    mysql的binlog增量日志解析,提供增量数据订阅和消费
    chaosblade-exec-os项目的burnio.go文件解读
    mysql的where条件中的字段不要加函数
    mysql释放大表空间的正确之道
    mysql服务器问题
    purge binary logs to 'mysql-bin.039790';
    golang操作mysql数据库的规范
  • 原文地址:https://www.cnblogs.com/vicky123/p/12896186.html
Copyright © 2011-2022 走看看