• js


    创建函数,3种:
    1 声明:只有声明方式创建的函数才能被声明提前
    function fun(arg1, arg2, ...){ statement; return value;}
    2 函数直接量:无法被声明提前
    var fun = function(arg1, arg2, ...){ statement; return value;};
    揭示:函数其实是一个对象,函数名仅仅是一个引用函数对象的普通变量。
    3 用new:
    var fun = new Function("arg1", "arg2", ..., "statement; return value;");

    重载(overload):相同函数名,不同参数列表的多个函数,在调用时,根据传入参数的不同,自动选择匹配的函数执行
    目的目的:减少API的数量,减轻调用者的负担

    when:如果多个函数只是流程不同,其实都是一类事,就可以将多个函数命名为同名函数,不同参数
    how:js语法不支持重载!js中后定义的同名函数会覆盖先定义的。
    arguments:函数中自动接收所有传入函数的参数值的类数组对象。
    类数组对象:长得像数组的对象
    类数组对象和数组的相同点:都用[i]方式访问每个元素;length属性记录元素的个数;for循环遍历每个元素。

    对象的创建,3种:
    1 对象直接量:
    var obj = {
    属性名: 属性值;
    ...,
    方法名: function(){},
    ...
    };
    注意:每个属性名和方法名不用加引号,但是底层都是用字符串存储。

    this:引用当前正在调用函数的对象!

      和定义在哪个对象中无关!只和调用时   .  前的对象有关!

      固定场景:a.在对象自己的方法中,访问自己的属性

           b.在构造函数中,指代正在创建的新对象

           c.在原型对象的共有方法中,指代将来调用共有方法的子对象

      注意:不是任何对象直接调用的函数中this默认指window对象。
    when:对象自己的方法中,想访问对象自己的属性必须用 this.属性名
    2 使用new:
    var obj = new Object();//创建一个Object类型的空对象
    obj.属性名 = 属性值;//等效于 obj["属性名"] = 属性值;
    ...
    obj.方法名 = function(){... this.属性名 ...};
    when:如果在创建对象时,暂时不知道包含哪些属性,就先创建一个对象,再添加属性

    注意:js中的对象,可以随时添加新属性,只要给不存在的属性赋值,就自动添加

    本质:js中一切对象都是hash数组:

      a.都可以随时添加新的属性和方法

      b.访问对象中一个不存在的属性,返回undefined

      c.属性名和方法名其实相当于hash数组中的key

      d.都可用for in遍历每个属性
    3 反复创建多个相同类型和结构的对象;
    a.定义构造函数,描述一类对象的统一结构
    构造函数:描述一类对象的统一结构德函数
    when:只要反复创建相同结构的多个对象前,都需要先定义构造函数,再创建对象。
    how:
    function 类型名/构造函数名(属性参数列表){
    this.属性名 = 属性参数值;
    ...
    this.方法名 = function(){
    ... this.属性名...
    }
    }
    b.使用new调用构造函数创建对象并添加属性
    var obj = new 构造函数名(属性值列表);
    构造函数中的this,指new正在创建的对象

    面向对象:
    原型和原型链:
    原型:保存所有子对象的公共成员的父级对象

    每个构造函数,都有一个prototype属性,引用自己的原型对象
    每个子对象,都有一个 __proto__ 属性,继承自构造函数的原型对象

    继承:父对象的成员,自对象无需创建,可直接使用!

    对象创建:
    a.创建空对象
    b.设置新对象的 __proto__ 属性继承构造函数的原型对象
    c.调用构造函数,添加成员
    d.返回地址
    when:同一类型的子对象共享的属性和方法,都要放在构造函数的原型对象中。
    优点:代码重用,节约内存!

    删除属性:
    a.自有属性: delete 对象.属性名;
    b.共有属性:只能通过构造函数的原型对象删除 delete 构造函数.prototype.属性名

    判断自有属性与共有属性:
    a.判断自有属性:判断指定属性是否直接保存在当前对象本地
    var isSelf = obj.hasOwnProperty("属性名");
    true:是自有属性
    false:无法确定是否为共有
    b.判断共有属性:同时满足两条件:
    不是自有: obj.hasOwnProperty("属性名") == false;
    但是在原型中有: obj.属性名 !== undefined

    <script type="text/javascript">
        
    //String类型支持trim(),去掉前后的空格
    //如果当前浏览器不支持trim
    if(String.prototype.trim === undefined){
        console.log("当前浏览器不支持trim(),自定义trim()");
        String.prototype.trim = function(){
            return this.replace(/^s+|s+$/g, "");
        };
    }
    
    var str = "    hello js,  I like  ";
    console.log(":" + str + ":");
    str = str.trim();
    console.log(":" + str + ":");
    
    </script>

    总结:不使用 obj. 方式访问对象,都去作用域链找,只要使用 obj. 访问成员,都去原型链找。

    原型相关API:

    1. 获取原型对象,2种:

      a. 构造函数.prototype

      b. 子对象.__proto__  :内部属性,可能被禁用

        尽量使用Object.getPrototypeOf(子对象);

    2. 判断对象间是否有继承关系:

      var hasInherit = 父对象.isPrototypeOf(子对象); 

    3. instanceof:判断一个对象是否是指定构造函数的实例

      function Student(){};

      var jack = new Student();

      jack instanceof Student -> true

    多态:同一事物,在不同情况下表现出不同样子

      重写:override:如果子对象觉得父对象的成员不好用,可在本地定义同名成员,覆盖父对象的。

    在原型对象中

      如何添加共有属性:只能通过原型对象

        构造函数.prototype.属性名 = 值;

      原型链:由各级对象的 __proto__ 逐级继承形成的链式关系

      规则:在访问对象属性时,只要自己有,就不去父级找,如果自己没有,才去父级找,如果到Object.prototype都没找到,就返回undefined。

      和作用域链的比较:

        作用域链:控制变量的使用顺序:所有不带.的变量,默认都去作用域找

        原型链:控制对象的属性的使用顺序:所有用.访问的对象属性,都去原型链找

      

    每个对象内部有一个属性: class 记录了创建对象时使用的类型名
    访问对象内部的class: 只能调用原生的toString()
    Object.prototype.toString();//"[object Object]"
                                                    对象 class

    强行调用原生toString():

    原生toString.call(替代this的对象)

      call做两件事:a.执行函数;b.替换this

      Object.prototype.toString();     this->Object.prototype

      Object.prototype.toString.call(obj);  this->obj->在执行时,相当于obj.toString()

    <script type="text/javascript">
        
    //判断一个对象是否是数组
    var obj1 = {};//Object
    var obj2 = [];//Array
    var obj3 = function(){};//Function
    var obj4 = {}; obj4.__proto__ = [];
    
    //typeof无法区分数组和对象
    console.log(typeof obj1);//object
    console.log(typeof obj2);//object
    console.log(typeof obj3);//function
    console.log(typeof obj4);//object
    console.log("==================");
    
    //1. isPrototypeOf 不但检查直接父对象,而且检查整个原型链
    console.log(Array.prototype.isPrototypeOf(obj1));//false
    console.log(Array.prototype.isPrototypeOf(obj2));//true
    console.log(Array.prototype.isPrototypeOf(obj3));//false
    console.log(Array.prototype.isPrototypeOf(obj4));//true
    console.log("==================");
    
    //2. constructor 也可检查整个原型链
    console.log(obj1.constructor == Array);//false
    console.log(obj2.constructor == Array);//true
    console.log(obj3.constructor == Array);//false
    console.log(obj4.constructor == Array);//true
    console.log("==================");
    
    //3. instanceof 也可检查整个原型链
    console.log(obj1 instanceof Array);//false
    console.log(obj2 instanceof Array);//true
    console.log(obj3 instanceof Array);//false
    console.log(obj4 instanceof Array);//true
    console.log("==================");
    
    //4. 每个对象内部有一个属性: class 记录了创建对象时使用的类型名
    console.log(Object.prototype.toString.call(obj1) == "[object Array]");//false
    console.log(Object.prototype.toString.call(obj2) == "[object Array]");//true
    console.log(Object.prototype.toString.call(obj3) == "[object Array]");//false
    console.log(Object.prototype.toString.call(obj4) == "[object Array]");//false
    console.log("==================");
    
    //5. ES5: isArray
    if(Array.isArray === undefined){
        console.log("Array.prototype.isArray not exsit.");
        Array.isArray = function(obj){
            return (Object.prototype.toString.call(obj) == "[object Array]");
        };
    }
    console.log(Array.isArray(obj1));//false
    console.log(Array.isArray(obj2));//true
    console.log(Array.isArray(obj3));//false
    console.log(Array.isArray(obj4));//false
    
    </script>

     

    自定义继承:

      a.仅修改一个对象的父对象:

        子对象.__proto__ = 父对象;

        Object.setPrototypeOf(子对象, 父对象);

      b.直接修改构造函数的原型对象,可同时修改之后创建的所有子对象的父对象:

        时机:必须在创建第一个对象之前完成,才能保证对象间的一致性。

      c.两种类型间的继承:即扩展结构(extends),又继承原型(inherit)

        抽象:将多个子类型的相同属性和方法,集中提取到一个公共的父类型中定义。

        how:3步:

          c1. 将多个子类型的相同属性和方法,抽象到一个公共的父类型中集中定义

          c2. 借用构造函数:在子类型构造函数中调用父类型构造函数

            问题:如果直接调用父类型构造函数:this->window

            解决:强行调用,更换this:父类型构造函数.call(this, 参数1, 参数2, ...);

            问题:call要求每个参数都要重复写一遍

            解决:使用apply传入arguments,apply可打散arguments,再单独传入:父类型构造函数.apply(this, arguments);

            总结:只有两个API可打散数组参数: 

              arr1.concat(arr2); -> arr1.concat(arr2[0], arr2[1], ...);

              fun.apply(obj, arr); -> obj.fun(arr[0], arr[1], ...);

          c3. 让子类型的原型继承父类型的原型:Object.setPrototypeOf(子类型的原型, 父类型的原型);

    call和apply:

      相同:都是强行调用一个函数,并替换this

      差别:传入参数的方式:

        call:要求每个参数必须单独传入

        apply:要求所有参数以一个数组的方式整体传入

    <script type="text/javascript">
        
    function Flyer(fname, speed){
        this.fname = fname;
        this.speed = speed;
    }
    Flyer.prototype.fly = function(){
        console.log(this.fname + " is flying, on speed " + this.speed);
    };
    
    function Enemy(fname, speed, score){
        Flyer.call(this, fname, speed);
        this.score = score;
    }
    Enemy.prototype.getScore = function(){
        console.log(this.fname + " score is " + this.score);
    };
    Object.setPrototypeOf(Enemy.prototype, Flyer.prototype);
    
    function Bee(fname, speed, award){
        Flyer.apply(this, arguments);
        this.award = award;
    }
    Bee.prototype.getAward = function(){
        console.log(this.fname + " award is " + this.award);
    };
    Object.setPrototypeOf(Bee.prototype, Flyer.prototype);
    
    var e = new Enemy("enemy001", 50, 20);
    e.fly();
    e.getScore();
    
    var b = new Bee("bee001", 5, 2);
    b.fly();
    b.getAward();
    
    </script>

    *****ES5

    对象的属性:

    对象:属性的集合

    2大类:

      a. 命名属性:自定义的可用,直接访问的属性

        a1. 数据属性:直接保存一个数据的属性

        a2. 访问器属性:专门保护另外一个数据属性的特殊属性,不直接保存数据

      b.内部属性:对象内部自动包含的,无法用.访问到的属性,比如:class

    ***数据属性:

      ES5中规定,每个数据属性都包含4大特性:

        value:时机存储属性值的特性

        writable:控制当前属性是否可修改 bool

        enumerable:控制当前属性能否被 for in 遍历到 bool

        configurable:控制当前属性能否被删除,或能否修改其他特性

      如何访问属性的特性:

        查看属性的特性: var attrs = Object.getOwnPropertyDescriptor(obj, "属性名");

        设置属性的特性: Object.defineProperty(obj, "属性名", {value: 值, writable: true/false, enumerable: true/false, configurable: true/false});

        注意:一般修改特性时,都要将configurable设置为false:不准修改其他特性;不可逆。

      添加一个新属性,并设置四大属性:

        Object.defineProperty(obj, "属性名", {value: 值, writable: true/false, enumerable: true/false, configurable: true/false});

        注意:使用defineProperty添加的新属性,四大特性默认值为false!

          对象直接量中的属性:四大特性默认值为true

      同时定义或添加多个属性,并设置四大特性:

        Object.defineProperty(obj, {

          "属性名": {value: 值, writable: true/false, enumerable: true/false, configurable: true/false},

          ...

          });

    <script type="text/javascript">
        
    var emp = {id:1001, name: "jack", salary: 10000};
    console.log(Object.getOwnPropertyDescriptor(emp, "id"));//Object {value: 1001, writable: true, enumerable: true, configurable: true}
    Object.defineProperty(emp, "id", {writable: false});//修改emp的id属性为只读
    emp.id = 1002;
    Object.defineProperty(emp, "salary", {enumerable: false});//修改emp的salary属性为不可遍历
    for(var key in emp){
        console.log(key + ":" + emp[key]);//id:1001   name:jack
    }
    
    </script>

    静态方法:不需要实例化对象,就直接调用的方法。

    方法定义在原型对象中,还是定义在构造函数上:

      如果只希望当前类型的子对象才能用,就放在原型对象中;

      如果不希望实例化任何对象,就可以直接调用,就放在构造函数上。

  • 相关阅读:
    重构原则
    【重构:改善既有代码的设计】读书笔记——开篇
    C#值参数和引用参数
    使用Aspose.Cells利用模板导出Excel(C#)
    在MVC中使用rdlc格式的报表
    程序员如何高效学习
    IT 圈里有哪些经常被读错的词?
    VS2017生成解决方案报错,提示对路径的访问被拒绝
    JavaScript中的数值转换
    Xadmin的配置及使用
  • 原文地址:https://www.cnblogs.com/skorzeny/p/6515515.html
Copyright © 2020-2023  润新知