• JavaScript面向对象基础


    初识对象

    • 面向对象的特征

      • 封装性、继承性、多态性
      • 对象是键值对的集合:对象是由属性和方法构成的 (ps:也有说法为:对象里面皆属性,认为方法也是一个属性)
    • 对象属性操作

        var student = {
            name: 'sunny',
            age: 20,
            number: '11034P',
            department: 'newEnergy',
            score: function(){
                return '成绩查询系统!';
            },
            job: function(){
                return '就业查询系统!';
            }
        }
        var arr = [];
    
        // .语法
        // .语法后面不能使用js中的关键字、保留字(class、this、function。。。)
        // .语法后面不能使用数字
        // .语法后面可直接执行方法函数
        console.log(student.name);
        console.log(student.score());
    
        // []语法
        // []内部必须用引号引入变量名 (student['number']
        // ["class"]、["this"]等保留字都可以随意使用
        // [0]、[1]、[2]也可以使用 ? 为什么obj[3]==obj["3"]
        // 甚至还可以这样用:["[object Array]"]  jquery里面就有这样的实现
        // 也可以这样用:["{abc}"]  给对象添加了{abc}属性
        console.log(student['age']);
        console.log(student['job']);
    
        // 添加属性
        student['[object Array]'] = 240;
        student['{object}'] = {'arts':85, 'sports': 95};
        for(key in student){
            arr.push(key);
        }
        console.log(student);
        console.log(arr);
        arr = [];
    
        // 修改属性
        student.gender = 'man';
        student['direction'] = function(){
            return '人工智能与图形操作';
        }
        for(key in student){
            arr.push(key);
        }
        console.log(student);
        console.log(arr);
        arr = [];
    
        // 删除属性
        delete student.number;
        for(key in student){
            arr.push(key);
        }
        console.log(student);
        console.log(arr);
        arr = [];
    
    • 获取对象长度的方法
      • 对象的长度不能用.length获取
      • Object具有一个keys属性,可以返回json对象的key的数组
      • Object可以使用in运算符
        var student = {
            name: 'sunny',
            age: 20,
            number: '11034P',
            department: 'newEnergy',
            score: function(){
                return '成绩查询系统!';
            },
            job: function(){
                return '就业查询系统!';
            }
        }
    
        var arr = [];
    
        arr = Object.keys(student);
        console.log(arr.length);
        arr = [];
    
        for(key in student){
            arr.push(key);
        }
        console.log(arr.length);
        arr = [];
    
        console.log('name' in student);
    
    • 对象的浅拷贝与深拷贝
        // 浅拷贝
        var student = {
            name: 'sunny',
            age: 20,
            number: '11034P',
            department: 'newEnergy',
            score(){
                return '成绩查询系统!';
            },
            job(){
                return '就业查询系统!';
            }
        }
        var simple = obj=>{
            let newObj = {};
            for(let key in obj){
                newObj[key] = obj[key];
            }
            return newObj;
        }
        var sunny = simple(student);
        console.log(sunny);
    
        // 深拷贝
        var student = {
            name: 'sunny',
            age: 20,
            number: '11034P',
            department: 'newEnergy',
            score: {
                arts: 95,
                sports: 85,
                program: 95
            },
            job(){
                return '就业查询系统!';
            }
        }
    
        var deepCopy = obj=>{
            var newObj = {};
            for(let key in obj){
                newObj[key] = (typeof obj[key] === 'object') ? deepCopy(obj[key]) : obj[key];
            }
            return newObj;
        }
        var sunny = deepCopy(student);
        console.log(sunny);
    

    构造函数

    • 构造函数的概念

      • 任何函数都可以当成构造函数
      • 只要把一个函数通过new的方式来进行调用,我们就把这一次函数的调用方式称之为:构造函数的调用
        • new CreateFunc(); 此时CreateFunc就是一个构造函数
        • CreateFunc(); 此时的CreateFunc并不是构造函数
      • new Object()等同于对象字面量{}
    • 构造函数的执行过程

      • var p1=new Person();
      • 创建一个对象 (我们把这个对象称之为Person构造函数的实例)- _p1
      • 创建一个内部对象,this,将this指向该实例(_p1)
      • 执行函数内部的代码,其中,操作this的部分就是操作了该实例(_p1)
      • 返回值:
        • 如果函数没有返回值(没有return语句),那么就会返回构造函数的实例(_p1)
        • 如果函数返回了一个基本数据类型的值,那么本次构造函数的返回值是该实例(_p1)
        • 如果函数返回了一个引用数据类型的值,那么本次函数的返回值就是该值
    • 创建构造函数

        var student = {};
        student.name = 'sunny';
    
    • 内置的构造函数
        var obj = new Object();
        var num = new Number();
        var str = new String();
        var now = new Date();
        var arr = new Array();
        var reg = new RegExp();
        var bool = new Boolean();
        var func = new Function();
        var img = new Image();
    
    
        console.log(obj);
        console.log(obj.constructor);
    
        console.log(num);
        console.log(num.constructor);
    
        console.log(str);
        console.log(str.constructor);
    
        console.log(now);
        console.log(now.constructor);
    
        console.log(arr);
        console.log(arr.constructor);
    
        console.log(reg);
        console.log(reg.constructor);
    
        console.log(bool);
        console.log(bool.constructor);
    
        console.log(func);
        console.log(func.constructor);
    
        console.log(img);
        console.log(img.constructor);
    
    • 自定义构造函数
      • 构造函数的命名推荐采用帕斯卡命名规则,即所有的单词首字母大写。
      • 在构造函数内部,使用this来表示刚刚创建的对象。
        var Computer = function(memory, storage, videoMemory, run){
            this.memory = memory;
            this.storage = storage;
            this.videoMemory = videoMemory;
            this.run = run;
            this.introduce = function(){
                return this.memory;
            }
        }
        var noteBook = {
            memory: '16GB',
            storage: '2TB',
            videoMemory: '4GB',
            run: function(){
                return '你好,世界!';
            }
        }
        var Dell = new Computer(noteBook.memory, noteBook.storage, noteBook.videoMemory, noteBook.run);
        console.log(Dell);
        console.log(Dell.run());
        console.log(Dell.introduce());
    
    • 私有成员
      • 在构造函数中,使用var关键字定义的变量称为私有成员
      • 在实例对象后无法通过“对象成员”的方式进行访问
      • 但是私有成员可以在对象的成员方法中访问
        var Computer = function(memory, storage, videoMemory, run){
            var processor = 'Core i7-4700MQ';
            this.memory = memory;
            this.storage = storage;
            this.videoMemory = videoMemory;
            this.run = run;
            this.introduce = function(){
                return this.memory + processor;
            }
        }
    
        var noteBook = {
            memory: '16GB',
            storage: '2TB',
            videoMemory: '4GB',
            run: function(){
                return '你好,世界!';
            }
        }
        var Dell = new Computer(noteBook.memory, noteBook.storage, noteBook.videoMemory, noteBook.run);
        console.log(Dell);
        console.log(Dell.processor);
        console.log(Dell.run());
        console.log(Dell.introduce());
    
    • 构造函数中的return关键字
      • 构造函数中,return返回一个数组或对象等引用类型数据,则构造函数会直接返回该数据,而不会返回原来创建的对象。
      • 如果返回的是基本类型数据,则返回的数据无效,依然会返回原来创建的对象。
      • 总结:构造函数中的return只能返回引用类型的数组或对象,有合规的返回值返回数据,没有就返回本身的对象数据
        // 返回值是引用类型数据,返回对象本身
        var Computer = function(memory, storage, videoMemory, run){
            var processor = 'Core i7-4700MQ';
            this.memory = memory;
            this.storage = storage;
            this.videoMemory = videoMemory;
            this.run = run;
            this.introduce = function(){
                return this.memory + processor;
            }
            return {say:'你好,世界!'};
        }
    
        var Lenovo = new Computer();
        console.log(Lenovo);
    
        // 返回值是基本类型数据,返回数据无效,返回原来创建的对象
        var Computer = function(memory, storage, videoMemory, run){
            var processor = 'Core i7-4700MQ';
            this.memory = memory;
            this.storage = storage;
            this.videoMemory = videoMemory;
            this.run = run;
            this.introduce = function(){
                return this.memory + processor;
            }
            return 0;
        }
    
        var Lenovo = new Computer();
        console.log(Lenovo);
    

    内置对象

    • 定义:内置对象就是指这个语言自带的一些对象,供开发者使用,这些对象提供了一些常用的或是最基本而必要的功能。
      • Arguments 函数参数集合
      • Array 数组
      • Boolean 布尔对象
      • Date 日期时间
      • Error 异常对象
      • Function 函数构造器
      • Math 数学对象
      • Number 数值对象
      • Object 基础对象
      • RegExp 正则表达式对象

    String对象

    • String()对象
      • length - 获取字符串的长度
      • charAt(index) - 获取index位置的字符,位置从0开始计算
      • indexOf(searchValue) - 获取searchValue在字符串中首次出现的位置,没有返回-1
      • lastIndexOf(searchValue) - 获取searchValue在字符串中最后出现的位置,没有返回-1
      • substring(start[,end]) - 截取从start位置到end位置之间的一个子字符串
      • substr(start[,length]) - 截取从start位置开始到length长度的子字符串
      • toLowerCase() - 获取字符串的小写形式
      • toUpperCase() - 获取字符串的大写形式
      • split(separator[,limit]) - 使用separator分隔符将字符串分割成数组,limit用于限制数量
      • replace(str1,str2) - 使用str2替换字符串中的str1,返回替换结果
        var userName = function(name){
            var flag = 0;
            return function(){
                name.length<3 || name.length>15 ? console.log('用户名长度必须在3~10之间') : 
                    name.toLowerCase().indexOf('admin') !== -1 ? console.log('用户名中不能出现"admin"敏感词') :  
                        flag = 1;
                return flag;
            }
        }
    
        var newName = userName('dministrator');
        console.log(newName());
    

    Number对象

    • Number()对象
      • MAX_VALUE - 在JavaScript中所能表示的最大数值(静态成员)
      • MIN-VALUE - 在JavaScript中所能表示的最小正值(静态成员)
      • toFixed(digits) - 使用定点表示法来格式化一个数值
        var num = 12345.6789;
        num.toFixed();          // 12346
        num.toFixed(1);         // 12345.7
        num.toFixed(6);         //  12345.678900
        Number.MAX_VALUE;       // 1.7976931348623157e+308
        Number.MIN_VALUE;       // 5e-324
    

    Math对象

    • Math()对象:专门封装数学计算常用常量和计算方法的全局对象,Math没有构造函数,不能new!所有API都直接用Math.xxx,
      • Math.PI() - 获取圆周率,结果为3.141592653589793
      • Math.abs() - 获取x的绝对值,可传入普通数值或是用字符串表示的数值
      • Math.max([value1[,value2,...]]) - 获取所有参数中的最大值
      • Math.min([value1[,value2,...]]) - 获取所有参数中的最小值
      • Math.pow(base,exponent) - 获取基数(base)的指数(exponent)次幂
      • Math.sqrt(x) - 获取x的平方根
      • Math.ceil(x) - 获取大于等于x的最小整数,即向上取整
      • Math.floor(x) - 获取小于等于x的最大整数,即向上取整
      • Math.round(x) - 获取x的四舍五入后的整数值
      • Math.random() - 获取大于或等于0.0且小于1.0的随机数
        // 随机数函数
        var randomNum= function(min, max){
            if(arguments.length== 2){
                return Math.floor(Math.random()* (max- min+ 1)+ min);
                // return parseInt(Math.random()* (max- min+ 1)+ min);
            }else if(arguments.length== 1){
                return Math.ceil(Math.random()* min);
            }else{
                return Math.ceil(Math.random()* 100);
            }
        }
        console.log(randomNum());
    
        // 获得数组最大值
        Math.max.apply(Math,[1,2,3,4]);
    

    Date对象

    • Date()对象:封装一个1970年元旦至今的毫秒数(从1970年1月1日0点0分0秒到当前时间的毫秒差),提供了对时间操作的方法
      • get方法用来获得分量的值
        • getFullYear() - 获取表示年份的数字,如2020
        • getMonth() - 获取月份,范围0~11(0表示一月,1表示二月,以此类推)
        • getDate() - 获取月份中的某一天,范围1~31
        • getDay() - 获取星期,范围0~6(0表示星期一,1表示星期二,以此类推)
        • getHours() - 获取小时数,返回0~23
        • getMinutes() - 获取分钟数,范围0~59
        • getSeconds() - 获取秒数,范围0~59
        • getMilliseconds() - 获取毫秒数,范围0~999
        • getTime() - 获取从1970-01-01 00:00:00 距离Date对象所代表时间的毫秒数
      • set方法用来设置分量的值
        • setFullYear(value) - 设置年份
        • setMonth(value) - 设置月份
        • setDate(value) - 设置月份中的某一天
        • setHours(value) - 设置小时数
        • setMinutes(value) - 设置分钟数
        • setSeconds(value) - 设置秒数
        • setMilliseconds(value) - 设置毫秒数
        • setTime(value) - 通过从1970-01-01 00:00:00 计时的毫秒数来设置时间
    • 日期转字符串
      • var date = new Date();
      • date.toString() - GMT格式显示
      • date.toLocaleString() - 操作系统当地时间格式,包含时间和日期
      • date.toLocaleDateString() - 以操作系统当地时间格式,仅包含日期
      • date.toLocaleTimeString() - 以操作系统当地时间格式,仅包含时间
    • Date计算
      • 两日期对象可直接相减,结果是毫秒差!
      • 对每个分量做加减:3步: get分量值,做加减,set回去
      • 一步概括:date.setXXX(date.getXXX()+/-n);
        // 当前系统时间
        var date = new Date();
        // 2012年10月13日12时26分35秒
        var date = new Date(2012, 10, 13, 12, 26, 35);
        // 2012年10月有多少天
        var max = new Date(2012, 10, 0).getDate();
        // 获取当前月份
        var nowMonth = new Date().getMonth()+ 1;
        // 将毫秒数转化为时间
        var date = new Date(1499996760000);
        var dateTime = date.toLocaleString();
    
        // 1970年1月1日午夜以来的毫秒数
        new Date().getTime();   // 提倡使用的
        new Date().valueOf();
        Date.now();             // 直接使用的
        +new Date();            // 相当于隐式转换,将该元素转换成Number类型,如果转换失败,那么将得到 NaN
        new Date()* 1;          // +new Date() 将会调用 Date.prototype 上的 valueOf() 方法,根据MDN,Date.prototype.value方法等同于Date.prototype.getTime()
    
        // 实时时间
        setInterval(
            _=> {
                var date = new Date();
                var formate = (date=> {
                    var week = ['日', '一', '二', '三', '四', '五', '六'];
                    return date.getFullYear()+ '年'+ 
                            (date.getMonth()+ 1)+ '月'+ 
                            date.getDate()+ '日'+' ' + 
                            '星期'+ week[date.getDay()]+ ' '+ 
                            date.toLocaleTimeString();
                })(date);
                console.log(formate);
            },1000);
    

    错误处理与代码调试

    • 错误类型

      • Error - 表示普通错误,其余6种类型的错误对象都继承自该对象
      • EvalError - 调用eval()函数错误,已经弃用,为了向后兼容,低版本还可以使用
      • RangeError - 数值超出有效范围,如"new Array(-1)"
      • ReferenceError - 引用了一个不存在的变量,如"var a=1;a+b;"(变量b未定义)
      • SyntaxError - 解析过程语法错误,如"{;}" "if()" "var a=new;"
      • TypeError - 变量或参数不是预期类型,如调用了不存在的函数或方法
      • URIError - 解析URI编码出错,调用encodeURI()、escape()等URI处理函数时出现
    • 错误处理:发生错误时,保证程序不中断

        try{
            可能发生错误的代码
        }catch(err){//err中发生错误时会自动收到创建的error对象
            err.message: 保存了错误的详细原因
            err.name: 保存了错误对象的名称
        如果发生错误,才执行的错误处理代码
        }[finally{
        无论是否发生错误,都执行的代码
            *一定会在退出*之前*执行*
            一般释放用过的对象资源:xxx=null
        }]
    
    • 手动抛出错误对象
        try{
            // 创建错误对象
            var err = new Error('自定义错误信息');
            // 抛出错误对象
            // 也可以与上一行合并为:throw new Error('自定义错误信息');
            throw err;
        }catch(err){
            // 输出结果,自定义错误信息
            console.log(err.message);
        }
    
    • 执行效率

      • 如果可以提前预知错误的原因:建议使用if代替try catch
      • try中尽量少的包含代码,try的执行效率低,且多创建一个error对象
    • Source面板调试工具

      • Watch - 可以对加入监听列表的变量进行监听
      • Call Stack - 函数调用堆栈,可以在代码暂停时查看执行路径
      • Scope - 查看当前断点所在函数执行的作用域内容
      • Breakpoints - 查看断点列表
      • XHR Breakpoints - 请求断点列表,可以对满足过滤条件的请求进行断点拦截
      • DOM Breakpoints - DOM断点列表,设置DOM断点后满足条件时触发断点
      • Global Listeners - 全局监听列表,显示绑定在window对象上的事件监听
      • Event Listener Breakpoints - 可断点的事件监听列表,可以在触发事件时进入断点

    原型和原型链

    • 原型

      • 原型(prototype):保存所有子对象共有成员的对象
      • 每个构造函数都有一个原型属性,引用了该构造函数对应的原型对象
      • 由构造函数创建的每个对象中都有一个__proto__属性,指向构造函数的原型对象
      • 在访问子对象的成员时,优先在成员本地找,找不到,再去构造函数的原型中查找
    • 创建原型

      • 创建空对象
      • 调用构造函数,为新对象添加成员
      • 设置当前对象的__proto__属性为构造函数的原型对象
      • 每个对象自有的成员,放在构造函数中
      • 所有子对象共有的成员,放在原型对象中
    • 原型链

      • 由各级对象的__proto__逐级向上引用形成的多级继承关系
      • 所有的对象都有一个__proto__属性,指向自己的父对象
    • 原型相关API

      • 判断一个属性是否可用
        • in关键字:"属性名" in 对象
          • 如果"属性名"在当前对象的原型链中,返回true
          • 如果在整条原型链上都没找到,返回false
        • 使用===undefined:说明不包含
          • 简写为(!对象.成员名)
        • 判断是否自有属性:
          • obj.hasOwnProperty("成员");
          • 如果obj本地有指定"成员",则返回true,没有返回false
        • 判断共有属性:
          • 不是自有的,还要存在于原型链上
          • if(!obj.hasOwnProperty("成员")&&"成员" in obj)
      • 获得任意对象的__proto__属性:
        • 获得父级对象
        • var 父对象=Object.getPrototypeOf(对象);
      • 判断父对象是否处在子对象原型链的上级:
        • 父对象.isPrototypeOf(子对象);
        • 只要父对象在子对象的原型链上,就返回true,否则返回false
      • 删除对象中的属性:
        • delete 对象.成员
        • 只能删除自有的成员
        • 只有var声明的全局变量不让delete
        • 使用window.或window[""]增加的全局成员可以delete
      • 判断一个对象是数组的几种方法
        • Array.prototype.isPrototypeOf(obj)
          • 如果返回true,说明是数组,否则不是
        • obj instanceof Array
          • 对象 instanceof 类型名,返回true,说明是数组
          • instancof会查找原型链上所有原型的构造函数
        • Object.getPrototypeOf(obj)==Array.prototype
        • Object.prototype.toString.call(arr)
          • override,子对象觉得父对象的成员不好用
          • 可自己定义同名的自有成员覆盖父对象
        • Object.prototype.toString.apply(arr)
          • call和apply: 在调用方法的一瞬间,替换调用方法的对象
        • Array.isArray(obj)
          • 专门判断对象是否是数组!

    继承

    • 概念

      • 通过【某种方式】让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承 并不是所谓的xxx extends yyy
      • 有些对象会有方法(动作、行为),而这些方法都是函数,如果把这些方法和函数都放在构造函数中声明就会导致内存的浪费
    • 继承的第一种方式:原型链方法继承

        var Person = function(){
            
        };
        Person.prototype.say=function(){
            console.log("你好")
        }
        var sunny = new Person();
        console.log(sunny.say());
    
    • 继承的第二种方式:原型链继承
        // 一般情况下,应该先改变原型对象,再创建对象;
        // 一般情况下,对于新原型,会添加一个constructor属性,从而不破坏原有的原型对象的结构;
        var Person = function(){};
        Person.prototype = {
            //切记不能忘记
            constructor:Person,
            say:function(){
                console.log("你好");
            },
            run:function(){
                console.log("正在进行百米冲刺");
            }
        }
        var sunny = new Person;
        sunny.say();
        console.log(Person.prototype.constructor === Person);
    
    
    • 继承的第三种方式:拷贝继承(混入继承:mixin)
        // 由于拷贝继承在实际开发中使用场景非常多,所以很多库都对此有了实现
        // jquery:$.extend
        var Person = {
            hear: 'black',
            skin: 'yellow',
            eye: 'brown',
        }
        var extend = function (source){
            let target = {};
            for(let key in source){
                target[key] = source[key];
            }
            return target;
        }
        var sunny = extend(Person);
        sunny.hear = 'white';
        console.log(sunny);
    
        // es6中有了 <对象扩展运算符> 仿佛就是专门为了拷贝继承而生
        var Person = {
            hear: 'black',
            skin: 'yellow',
            eye: 'brown',
        }
        var target = {...Person}; 
        console.log(target);
    
    • 继承的第四种方式:原型继承 (道格拉斯在蝴蝶书中提出来的)
        var Person = {
            hear: 'black',
            skin: 'yellow',
            eye: 'brown',
        }
        var sunny = Object.create(Person);
        console.log(sunny.__proto__);
    
    • 继承的第五种方式:借用构造函数实现继承
        var Animal = function(name, age){
            this.name = name;
            this.age = age;
        }
        var Person = function(name, age, address){
            Animal.call(this, name, age);
            this.address = address;
            return this.age;
        }
        console.log(Person('dog', '18', '不告诉你!'));
    
  • 相关阅读:
    多线程 线程队列的实现
    如何使用vagrant在虚拟机安装hadoop集群
    【leetcode】Rotate List
    麒麟(Kylin)与Ubuntu的寓意相通
    山寨APP恶意吸费隐患 门槛底致监管盲点
    2013年软件设计师之考前复习笔记:IP地址
    .gitkeep
    cmd 里面运行git提示“不是内部或外部命令,也不是可运行的程序”的解决办法...
    windows常用命令行命令
    PhpStorm terminal无法输入命令的解决方法
  • 原文地址:https://www.cnblogs.com/SharkJiao/p/13548186.html
Copyright © 2020-2023  润新知