• js ECMAscript(三)原型,继承,this,bind,闭包,浅/深拷贝,正则表达式


    录:

    1.原型的引入
    2.原型添加方法解决数据共享
    3.实例对象使用的属性和方法层层的搜索
    4.为内置对象的原型对象中添加方法
    5.原型及原型链
    6.原型指向可以改变
    7.原型指向改变如何添加原型方法
    8.实例对象和原型对象属性重名问题
    9.通过原型实现继承
    10.借用构造函数实现继承
    11.组合继承
    12.拷贝继承
    13.函数的角色及函数声明和函数表达式的区别
    14.函数的this的指向问题
    15.严格模式
    16.函数是对象,对象不一定是函数
    17.数组中函数的调用

    -------------- 函数进阶apply、call、bind、闭包、沙箱、递归 --------------
    1.apply()和call()方法
    2.bind()方法
    3.函数中几个成员介绍
    4.函数作为参数
    5.函数作为返回值
    6.案例:电影排序
    7.闭包
    8.闭包的案例
    9.案例:闭包实现点赞
    10.沙箱
    11.递归

    -------------- 内置的方法(深拷贝、浅拷贝、遍历DOM树)、正则表达式 --------------
    1.浅拷贝
    2.深拷贝
    3.遍历DOM树
    4.正则表达式

    1.原型的引入    <--返回
      代码一

    function Person(name, age){
        this.name = name;
        this.age = age;
        this.eat = function() {
            console.log("eat...");
        };
    }
    var per1 = new Person("小白", 10);
    var per2 = new Person("小黑", 10);
    console.log(per1.eat == per2.eat);//false


      如何实现函数共享, 代码二:

    function myEat(){
        console.log("今天吃红烧土豆");
    };
    function Person(name, age){
        this.name = name;
        this.age = age;
        this.eat = myEat;
    }
    var per1 = new Person("小白", 10);
    var per2 = new Person("小黑", 10);
    console.log(per1.eat == per2.eat);//true

      但是代码二不好,因为外面可能定义变量var myEat = 10;造成命名冲突。    
            
    2.原型添加方法解决数据共享    <--返回
      代码:

    function Person(name, age){
        this.name = name;
        this.age = age;
    }
    //通过原型来添加方法
    Person.prototype.eat = function() {
        console.log("eat...");
    };
    var per1 = new Person("zs1", 10);
    var per2 = new Person("zs2", 20);
    console.log(per1.eat == per2.eat);//true    
        
    console.dir(per1);    //通过浏览器查看,发现实例对象中没有eat()方法
    console.dir(per2);    
    console.dir(Person);

           
      之前的写法

    Student.prototype.height="";
    Student.prototype.weight="";
    Student.prototype.study=function(){};
    Student.prototype.eat=function(){};

       
        * 简单的原型语法

    Student.prototype={
        constructor:Student,
        height:"",
        weight:"",
        study:function(){},
        eat:function(){}
    };


    3.实例对象使用的属性和方法层层的搜索    <--返回
      实例对象使用的属性或方法,先在实例中查找,找到了直接使用,找不到,去对应的构造函数的原型对象prototype中查找,找不到,则报错。
            
    4.为内置对象的原型对象中添加方法    <--返回
      我们能否为系统的内置对象的原型中添加方法(相当于改变源码)?  可以

    String.prototype.myReverse=function(){
        for(var i=this.length-1;i>=0;i--){
            console.log(this[i]);
        }
    };
    var str = "abcdefg";    
    str.myReverse();

    5.原型及原型链    <--返回

    function Person(name, age){
        this.name = name;
        this.age = age;
    }
    //通过原型来添加方法
    Person.prototype.eat = function() {
        console.log("eat...");
    };
    
    var per1 = new Person("zs1", 10);
    var per2 = new Person("zs2", 20);
    console.log(per1.eat == per2.eat); // true
    console.log(per1.__proto__ == Person.prototype); // true

      * 原型链: 是一种关系,实例对象和原型对象之间的关系,这个关系是通过原型(__proto__)来联系的
      * 实例对象与原型对象是通过原型__proto__联系的,这个联系就是原型链
      * 原型链最终的指向是Object的prototype中的__proto__是null

    6.原型指向可以改变    <--返回

      代码1

    function Student() {};
    Student.prototype.study = function(){
        console.log("我爱学习");
    };
    
    //Student的原型指向改变了,原型中原来的study()方法没有了
    Student.prototype = {
        eat: function(){
            console.log("我要吃饭");
        }
    };
    
    var stu = new Student();
    console.dir(stu);
    stu.eat();//我要吃饭
    //stu.study();//TypeError: stu.study is not a function

      代码2

    function Person() {};
    Person.prototype.eat = function(){
        console.log("我爱吃饭");
    };
    
    function Student() {};
    Student.prototype.study = function(){
        console.log("我爱学习");
    };
    
    //Student的原型指向改变了,指向了一个实例对象,原型中原来的study()方法没有了
    Student.prototype = new Person();
    
    var stu = new Student();
    console.dir(stu);

      结果一:Student.prototype = new Person();注释掉后

    {}
      __proto__: {…}
        constructor: function Student()
        study: function study()
        __proto__: Object { … }


      结果二:Student.prototype=new Person();没有注释

    {}
      __proto__: {}
        __proto__: {…}
          constructor: function Person()
          eat: function eat()
          __proto__: Object { … }

    7.原型指向改变如何添加原型方法    <--返回

    function Person(age) {
        this.age = age;
    };
    Person.prototype.eat=function(){
        console.log("我爱吃饭");
    };
    
    function Student(sex) {
        this.sex = sex;
    };
    
    //Student的原型指向改变了,原型中原来的study()方法没有了
    Student.prototype = new Person(10);
    //原型指向改变后,再添加方法
    Student.prototype.study = function(){
        console.log("我爱学习");
    };
    var stu = new Student("男");
    stu.study();
    console.dir(stu);

    8.实例对象和原型对象属性重名问题    <--返回

        * 先在实例对象中找,找不到再到原型中找,再找不到,就返回undefined
        * 如果是方法,如果实例对象和原型对象中都没有,报错TypeError: stu.XXXX is not a function
        * 通过实例对象是否可以改变原型对象中的属性值,不能。
        * 通过Student.prototype.sex="改变原型中sex的属性值";来改变原型的属性值

    function Person(age,sex) {
        this.age=age;
        this.sex=sex;
    };
    Person.prototype.eat=function(){
        console.log("我爱吃饭");
    };
    
    function Student(sex) {
        this.sex=sex;
    };
    
    //Student的原型指向改变了,原型中原来的study()方法没有了
    Student.prototype=new Person(10,"女");
    //原型指向改变后,再添加方法
    Student.prototype.study=function(){
        console.log("我爱学习");
    };
    var stu = new Student("男");
    console.log(stu.sex);
    Student.prototype.sex="改变原型中sex的属性值";
    console.dir(stu);

    9.通过原型实现继承    <--返回

        * 面向对象的编程思想:根据需求,分析对象,找到对象有什么特征和行为,通过代码的方式来实现需求,
            要想实现这个需求,就要创建对象,要想创建对象,就应该有构造函数,然后通过构造函数来创建对象,
            通过对象调用属性和方法来实现相应的功能及需求。
        * js不是一门面向对象的语言,js是一门基于对象的语言,那么为什么学习js还要学习面向对象。
            - 因为面向对象的思想适合人的想法,编程起来会更加方便,以及后期的维护。
        * 面向对象的编程语言中有类class的概念,但是js没有类的概念。但是js可以模拟面向对象的思想编程。
            js通过构造函数来模拟类的概念。
            
        * 面向对象的特性:封装、继承、多态
        
        * 封装:就是包装
            - 一个值存储在一个变量中--封装
            - 一些重复代码放在一个函数中--封装
            - 一系列的属性放在一个对象中--封装
            - 一些功能类似的函数(方法)放在一个js文件中--封装
            
        * 继承:首先继承是一种关系,类与类之间的关系。js中没有类,但是可以通过构造函数模拟类,
            然后通过原型类实现继承。继承是为了数据共享,js中的继承也是为了数据共享。
            
        * 原型作用一:实现数据共享,节省内存空间
          原型作用二:实现继承
        
        * 多态:一个对象有不同的行为


        * js通过原型实现继承的代码:

    function Person(name,age,sex) {
        this.name=name;
        this.age=age;
        this.sex=sex;
    };
    Person.prototype.eat=function(){
        console.log("我爱吃饭");
    };
    
    function Student(score) {
        this.score=score;
    };
    //Student的原型指向改变了,原型中原来的study()方法没有了
    Student.prototype=new Person("张三",20,"男");
    //原型指向改变后,再添加方法
    Student.prototype.study=function(){
        console.log("我爱学习");
    };
    
    var stu = new Student(100);
    console.log(stu.name);//张三
    console.log(stu.age);//20
    console.log(stu.sex);//
    console.log(stu.score);//100
    stu.eat();//我爱吃饭
    stu.study();//我爱学习

    10.借用构造函数实现继承    <--返回

    function Person(name,age,sex) {
        this.name=name;
        this.age=age;
        this.sex=sex;
    };
    function Student(name,age,sex,score) {
        Person.call(this,name,age,sex);//借用构造函数实现继承
        this.score=score;
    };
    
    var stu = new Student("张三",20,"男",100);
    console.log(stu.name);//张三
    console.log(stu.age);//20
    console.log(stu.sex);//
    console.log(stu.score);//100

    11.组合继承    <--返回

    function Person(name,age,sex) {
        this.name=name;
        this.age=age;
        this.sex=sex;
    };
    Person.prototype.eat = function() {
        console.log("吃饭饭");
    };
    function Student(name,age,sex,score) {
        Person.call(this,name,age,sex);//借用构造函数实现继承
        this.score=score;
    };
    Student.prototype=new Person();
    var stu = new Student("张三",20,"男",100);
    console.log(stu.name+"===="+stu.age+"===="+stu.sex+"===="+stu.score);//张三
    stu.eat();
    console.log(stu);

    12.拷贝继承    <--返回

        * 拷贝继承:把一个对象中的属性或方法直接复制到另一个对象中。
        * 代码一:

    var obj1={
        name="zs";
        age:20,
        eat:function(){
            console.log("吃土");
        }
    };
    var obj2=obj1;//改变obj2的指向
    console.log(obj2.name,obj2.age);
    obj2.eat();

           
        *代码二:

    var obj1={
        name="zs";
        age:20,
        eat:function(){
            console.log("吃土");
        }
    };
    var obj2={};
    for(var key in obj1){
        obj2[key]=obj1[key];
    };


        * 代码三:

    function Person(){};
    Person.prototype.name="zs";
    Person.prototype.eat=function(){
        console.log("吃饭");
    };
    
    var obj2={};
    for(var key in Person.prototype){
        obj2[key]=Person.prototype[key];
    }

    13.函数的角色及函数声明和函数表达式的区别    <--返回
        * 函数的角色:函数声明和函数表达式
        * 函数声明
            function f1(){
                console.log("函数f1");
            };
        
        * 函数表达式
            var f2=function(){
                console.log("函数f2");
            };

        * 下面代码在IE8中输出"呵呵"。因为函数声明提前了,else里面的代码将前面的覆盖了。
            - 火狐中还是输出"哈哈"
            if(true){
                function f1(){
                    console.log("哈哈");
                };
            }else{
                function f1(){
                    console.log("呵呵");
                };
            }
            f1();

        * 以后尽量使用函数表达式

    14.函数的this的指向问题    <--返回
        * 普通函数中的this
            function f1(){
                console.log(this);
            };
            window.f1();//函数调用,window可以省略不写,结果:this是window
        
        * 定时器中的this
            window.setTimeout(function(  //window可以省略不写
                console.log(this);   //this是window
            ),1000);
        
        * 构造函数或原型方法中的this----当前的实例对象
        
        * 事件绑定方法的this-->指向绑定事件的对象

    15.严格模式    <--返回

    "use strict";//严格模式
    function f1(){
        console.log(this);
    };
    f1();//打印undefined
    window.f1();//打印window

    16.函数是对象,对象不一定是函数    <--返回
        * 对象中有__proto__,函数中有prototype
        * function f1(){};
        console.dir(f1);//有prototype说明是函数,有__proto__说明又是对象
        console.dir(Math);//有__proto__说明是对象,没有prototype说明不是函数
        
        * 所有的函数实际上都是Func的构造函数创建出来的实例对象
            var f1=new Function("num1","num2","return num1+num2");
            console.log(f1(10,20));
        
        等价于<==>
            function f1(num1,num2){
                return num1+num2
            };
            console.log(f1(10,20));

    17.数组中函数的调用    <--返回

    // 函数的类型function
    function f1(){};
    console.log(typeof f1);//类型是function
    
    // 数组可以储存任意类型
    var arr=[
        function(){
            console.log(1);
        },
        function(){
            console.log(2);
        },
        function(){
            console.log(3);
        }
    ];
        
    //数组中函数的调用
    arr.forEach(function(ele){
        ele();
    });

    -------------- 函数进阶apply、call、bind、闭包、沙箱、递归 --------------

    1.apply()和call()方法    <--返回
        * 作用:可以改变this的指向
            //"use strict";
            function f1(x,y){
                console.log("结果是"+(x+y)+"==="+this);
            };
            f1(10,20);//调用函数
        * 上面代码的结果
            结果是30===[object Window]
            采用严格模式时,结果是30===undefined
                
        * 代码一:

    function f1(x,y){
        console.log("结果是"+(x+y)+"==="+this);
    };
    f1(10,20);//结果是30===[object Window]
    
    
    f1.apply(null,[10,20]);//结果是30===[object Window]
    f1.call(null,10,20);//结果是30===[object Window]
    
    f1.apply(this,[10,20]);//结果是30===[object Window]
    f1.call(this,10,20);//结果是30===[object Window]
    
    var obj={
        name:"zs",
        age:20
    };
    f1.apply(obj,[10,20]);//结果是30===[object Object]
    f1.call(obj,10,20);//结果是30===[object Object]


        * 代码二:

    function Person(name,age){
        this.name=name;
        this.age=age;
    };
    Person.prototype.sayHi=function(){
        console.log("hello,"+this.name);
    };
    
    function Student(name){
        this.name=name;
    };
    
    var per=new Person("张三",20);
    per.sayHi();//hello,张三
    var stu=new Student("李四");
    per.sayHi.apply(stu);//hello,李四
    per.sayHi.call(stu);//hello,李四


    2.bind()方法    <--返回
        * bind(thisArg,参数)是复制一份,并且改变this的指向

    function f1(x,y){
        console.log("结果是"+(x+y)+"==="+this);
    };
    var ff = f1.bind(null,10,20);
    ff();//结果是30===[object Window]
    
    var obj={
        name:"zs",
        age:20
    };
    //先复制,后调用,复制时赋值
    var fff=f1.bind(obj,10,20);
    fff();//结果是30===[object Object]
    
    //先复制,后调用,调用时赋值
    var f2=f1.bind(obj);
    f2(20,30);//结果是50===[object Object]


    3.函数中几个成员介绍    <--返回
        * 函数中有一个name属性--函数的名字,name属性是只读的,不能修改
        * 函数中有一个arguments属性--实参的个数
        * 函数中有一个length属性--形参的个数
        * 函数中有一个caller属性--调用(f1函数在f2函数中调用)
            
        * 代码:

    function f1(x,y){
        console.log(f1.name);
        console.log(f1.arguments.length);
        console.log(f1.length);
        console.log(fl.caller);
    }
    f1(10,20,30,40);//调用f1函数
    funct f2(){
        f1(1,2);
    };
    f2();

            
    4.函数作为参数    <--返回
        * 代码一:命名函数作为参数

    function f1(fn){
        console.log("函数f1");
        fn();
    }
    var f2=function (){
        console.log("函数f2");
    };
    f1(f2);

       
        * 代码二:匿名函数作为参数

    function f1(fn){
        console.log("函数f1");
        fn();
    }
    f1(function(){
        console.log("匿名函数");
    });

           
    5.函数作为返回值    <--返回
        * 代码一:

    function f1(){
        return function(){
            console.log("我是函数,是作为返回值使用");
        };
    }
    var ff = f1();//调用f1()函数,返回一个函数
    ff();

       
        * typeof和instanceof

    var n=10;
    console.log(typeof n);//number
    console.log(typeof(n));//number
    
    var obj={};
    console.log(typeof obj);//object
    console.log(typeof(obj));//object
    console.log(obj instanceof Object);//true
    
    function Person(){};
    var per=new Person();
    console.log(typeof per);//object
    console.log(typeof(per));//object
    console.log(per instanceof Object);//true
    console.log(per instanceof Person);//true

           
        * Object.prototype.toString(对象) 获取对象的类型

    console.log(Object.prototype.toString());//[object Object]
    console.log(Object.prototype.toString.call([]));//[object Array]
    console.log(Object.prototype.toString.call(Date));//[object Function]
    console.log(Object.prototype.toString.call(new Date()));//[object Date]

           
        * Object.prototype.toString(对象)用来判断某对象的类型

    function f1(a){
        if(Object.prototype.toString.call(a)=="[object Array]"){
            console.log("参数是一个数组");
        }
    };
    f1([]);//参数是一个数组

               
    6.案例:电影排序    <--返回

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
    <script type="text/javascript">
        function File(name,size,time){
            this.name=name;
            this.size=size;
            this.time=time;
        };
        var f1= new File("jack.avi","400M","1997-12-10");
        var f2= new File("xiaoy.avi","200M","2007-10-10");
        var f3= new File("tom.avi","800M","1996-02-10");
        arr=[f1,f2,f3];
    
        function fn(attr){
            return function getSort(obj1,obj2){
                if(obj1[attr]>obj2[attr]){
                    return 1;
                }else if(obj1[attr]==obj2[attr]){
                    return 0;
                }else{
                    return -1;
                }
    
            };
        };
    
        var ff = fn(prompt("输入name或size或time"));
        arr.sort(ff);
        for(var i=0;i<arr.length;i++){
            console.log(arr[i].name+"--"+arr[i].size+"--"+arr[i].time);
        }
    </script>
    </body>
    </html>


    7.闭包    <--返回
        * 闭包的概念:函数A中,有一个函数B,函数B可以访问函数A定义的变量
        
        * 闭包的模式:函数模式的闭包,对象模式的闭包
        
        * 闭包的作用:缓存事件,延长作用域链
        
        * 闭包的优缺点:优点:缓存数据 缺点:变量占用的内存没有及时释放
        
        * 闭包的应用
       
        * 函数模式的闭包
            (function A(){
                var num=10;
                function B(){
                    console.log(num);
                }
                B();
            })();
          或另一种函数自调用写法
            (function A(){
                var num=10;
                function B(){
                    console.log(num);
                }
                B();
            }());
        
        * 对象模式的闭包
            function f3(){
                var num=20;
                return{
                    age:num
                };
            }
            var obj=f3();
            console.log(obj.age);
            
    8.闭包的案例    <--返回

    function f1(){
        var num = 10;
        return function (){
            num++;
            return num;
        }
    }
    var ff = f1();
    console.log(ff());//11
    console.log(ff());//12
    console.log(ff());//13

      
    9.案例:闭包实现点赞    <--返回

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <ul>
            <li style="list-style-type: none"><img src="a.jpg" style=" 300px"><br/>
                <input type="button" value="点赞(0)" style="font-size: 25px"></li>
            <li style="list-style-type: none"><img src="a.jpg" style=" 300px"><br/>
                <input type="button" value="点赞(0)" style="font-size: 25px"></li>
        </ul>
    <script type="text/javascript">
        var eles = document.getElementsByTagName("input");
        function getValue(){
            var value=0;
            return function (){
                value++;
                this.value="点赞("+value+")";
            };
        };
    
        for(var i=0;i<eles.length;i++){
            eles[i].onclick=getValue();
        }
    </script>
    </body>
    </html>


    10.沙箱    <--返回
        * 沙箱:模拟小环境
            var num=10;
            (function(){
                var num=20;
                console.log(num);
            }());
            
    11.递归    <--返回

    -------------- 内置的方法(深拷贝、浅拷贝、遍历DOM树)、正则表达式 --------------

    1.浅拷贝    <--返回

    var obj1={
        name:"张三",
        age:10
    };
    var obj2={};
    function extend(a,b){
        for(var key in a){
            b[key]=a[key];
        }
    }
    extend(obj1,obj2);
    console.dir(obj2);

           
    2.深拷贝    <--返回

    var obj1={
        name:"张三",
        age:10,
        car:["宝马","奔驰"],
        dog:{
            name:"大黄",
            age:5,
            cat:{
                name:"阿才",
                age:2,
                color:["yellow","white"]
            }
        }
    };
    var obj2={};
    function extend(a,b){
        for(var key in a){
            var item=a[key];
            if(item instanceof Array){
                console.log("复制数组");
                b[key]=[];
                extend(item,b[key]);
            }else if(item instanceof Object){
                console.log("复制对象");
                b[key]={};
                extend(item,b[key]);
            }else{
                console.log("复制属性");
                b[key]=item;
            }
        }
    }
    extend(obj1,obj2);
    console.dir(obj1);
    console.dir(obj2);


    3.遍历DOM树    <--返回

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
    <div>
        <ul>
            <li><a href=""><img src="a-small.jpg"></a></li>
            <li><a href=""><img src="a-small.jpg"></a></li>
        </ul>
    </div>
    <div><a href="">百度</a></div>
    <p><a href="">谷歌</a></p>
        
    <script type="text/javascript">
    
        var htmlObj=document.getElementsByTagName("html")[0];
        function fn(obj){
            for(var i=0;i<obj.children.length;i++){
                console.log(obj.children[i].localName);//输出标签名字
                if(obj.children[i].children){
                    fn(obj.children[i]);
                }
            }
        };
        fn(htmlObj);
    </script>
    </body>
    </html>


    4.正则表达式    <--返回

    ---

  • 相关阅读:
    PostgreSQL数据库((数据库类型介绍)
    postgreSQL(SQL语音操作数据库)
    postgreSQL数据库连接注意事项
    数据库
    Excel函数文本变E+显示怎么办
    无糖可乐不好喝
    通过 命令查看 linux桌面使用的是wayland 还是 X11
    Intel CPU的后缀含义
    互联网缩略语
    linux 下为windows交叉编译 ffmpeg库
  • 原文地址:https://www.cnblogs.com/xy-ouyang/p/12208101.html
Copyright © 2020-2023  润新知