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', '不告诉你!'));
原文地址:https://www.cnblogs.com/SharkJiao/p/13548186.html