Javascript相关知识

作者: 紫苓 | 来源:发表于2016-09-14 17:04 被阅读27次
    1、函数定义方式
    function add1(num1,num2){
        return num1 + num2;
    }
    
    var add2 = function(num1,num2){
        return num1 + num2;
    }
    
    var add3 = new Function("num1","num2","return num1 + num2");
    
    window.console.log("add1 = " + add1(10,20));
    window.console.log("add2 = " + add2(100,200));
    window.console.log("add3 = " + add3(1000,2000));
    
    2、对象
    var obj = new Object();
    obj.name = "张三丰";
    alert(obj.name)
    
    var obj = Object();
    obj.name="zhangsanfeng";
    alert(obj.name);
    
    var obj = {};
    obj.name = "zhangjunbao";
    alert(obj.name);
    
    var obj = {
        name:"张三丰",
        age:28,
        add:function(num1,num2){
            return num1 + num2;
        }
    };
    alert(obj.name);
    alert(obj['name']);// 以数组的方式来访问属性,必须有单引号或是双引号
    alert(obj.add(10,20));
    
    3、变量作用域和内存

    在JavaScript中,基本数据类型(undefined,null,boolean,number,string)是存储在栈内存,其占据的空间是固定的;而引用类型(Object)是存储在堆内存,其占据的空间是要动态分配的,在栈内存中会保留有引用类型的一个地址,当访问这个引用类型的时候,先到栈空间找到该引用类型的地址,然后通过这个地址找到值;
    基本数据类型是按值来访问的,引用数据类型是按引用访问的;JavaScript中数据都是按值来传递的。

    QQ截图20160914100531.png
    4、面向对象与原型

    在第二节中列举了几种创建对象的方法,那些方法有个问题,就是如果有多个对象的情况下要进行重复实例化,如何解决这个问题,有一下几种方式:
    工厂方法创建对象

    function createObject(name,age){
        var obj = new Object();
        obj.name = name;
        obj.age = age;
        obj.description = function(){
            window.console.log(this.name + "," + this.age + ",来自中国......");
        }
        return obj;
    }
    
    var obj1 = createObject("Jackson",29);
    var obj2 = createObject("黄飞鸿",129);
    obj1.description();
    obj2.description();
    

    工厂方法创建对象解决了重复实例化的问题,但是又带来了新的问题:无法区分出到底是哪个对象的实例。

    构造函数方式

    /**
    * 1、所有的构造函数其实就是Object;
    * 2、构造函数没有new Object,但在后台会自动new Object();
    * 3、this相当于var obj = new Object()中的obj;
    * 4、构造函数不需要返回值
    * --------------------构造函数规范-----------------------------
    * 1、构造函数也是函数,但必须首字母大写;
    * 2、必须new 构造函数创建对象
    */
    function UserInfo(name,age){
        this.name = name;
        this.age = age;
        this.description = function(){
            window.console.log(this.name + "," + this.age + ",来自中国......");
        };
    }
    
    var user1 = new UserInfo("Hello",29);
    var user2 = new UserInfo("word",20);
    user1.description();
    user2.description();
    
    //--------------------------------------------------------
    
    // 寄生构造函数 = 工厂模式 + 构造函数
    // 稳妥构造函数:在构造函数中不能使用this,创建对象的时候不能使用new
    function User(name,age){
        var obj = new Object();
        obj.name = name;
        obj.age = age;
        obj.description = function(){
            window.console.log(name + "," + age + ",来自中国......");
        }
        return obj;
    }
    
    var obj1 = User("Jackson",29);
    obj1.description();
    

    对象冒充

    function UserInfo(name,age){
        this.name = name;
        this.age = age;
        this.description = function(){
            window.console.log(this.name + "," + this.age + ",来自中国......");
        };
    }
    
    var userReplace = new Object();
    UserInfo.call(userReplace,"haha",39);
    userReplace.description();
    

    对象原型
    上述创建对象的方式,解决了诸如重复实例化的问题、无法区分出到底是哪个对象的问题。但是,还是存在一个问题:对象中的方法占用内存问题!对于每个对象来说,其属性值是可变的,但是其方法基本是不变的,如果采用上述方式创建了对象的实例,那么每个实例中的每个方法都独自占据一定的内存,这样就浪费了大量的内存了,这个时候就可以使用对象原型了。在JavaScript中,每个对象都有原型对象,对象都继承原型对象的所有属性,基于这个原理,对于对象中的方法和常量,就可以使用原型来定义了。

    function UserInfo(name,age){
        this.name = name;
        this.age = age;
    }
    
    UserInfo.prototype.description = function(){
        window.console.log(this.name + "," + this.age + ",来自中国......");
    }
    
    var user1 = new UserInfo("张三丰",200);
    user1.description();
    
    function UserInfo(name,age){
        this.name = name;
        this.age = age;
    
        if(typeof this.description != 'function') {
            window.console.log("开始。。。。。。。。。");
            UserInfo.prototype.description = function(){
                window.console.log(this.name + "," + this.age + ",来自中国......");
            }
            window.console.log("结束。。。。。。。。。");
        }   
    
    }
    
    var user1 = new UserInfo("张三丰",200);
    user1.description();
    
    var user2 = new UserInfo("张君宝",200);
    user2.description();
    

    继承
    JavaScript中,所有的对象都有一个原型对象,所有的对象都继承原型对象的属性。
    ** 1)原型链继承 **

    /////////////////原型链继承
    function Human(){
        this.name = "张山峰";
    }
    
    function Man(){
        this.sex = "男";
    }
    
    // Man所有的对象都继承其原型对象,而Man的原型对象被指定为Human,这样就实现了继承了。
    Man.prototype = new Human();
    
    var man = new Man();
    window.console.log(man.name + "," + man.sex);
    

    这种继承有一个问题:无法传参给超类,方法不能共享(原型会被打断)。

    ** 2)借用构造函数实现继承 **

    /////////////////借用构造函数
    function Human(name){
        this.name = name;
    }
    
    function Man(name,sex){
        // 采用对象冒充方式传参
        Human.call(this,name);
        this.sex = sex;
    }
    
    var man = new Man("张三丰99","男");
    window.console.log(man.name + "," + man.sex);
    

    这种继承解决了向超类传参的问题,但是因为没有使用原型,则就无法实现方法等共享问题

    ** 3)组合继承 **

    /////////////////组合继承
    function Human(name){
        this.name = name;
    }
    
    Human.prototype.description = function(){
        window.console.log(this.name + ",我来自于中国......");
    }
    
    function Man(name,sex){
        // 采用对象冒充方式传参
        Human.call(this,name);
        this.sex = sex;
    }
    // Man的原型指向了Human
    Man.prototype = new Human();
    var man = new Man("张三丰88","男");
    window.console.log(man.name + "," + man.sex);
    man.description();
    

    解决了向超类传参问题,使用了原型链,实现了方法共享。

    ** 4)原型式继承 **:不单独使用

    // 临时中转函数
    function transition(obj){
        function F(){};
        // 这里的F继承了obj
        F.prototype = obj;
        return new F();
    }
    // 字面量方式声明一个对象
    var obj = {
        name : "zhangsanfeng",
        age : 100,
        arr:["aa","bb"]
    };
    
    var obj1 = transition(obj);
    obj1.arr.push("cc");
    window.console.log(obj1.arr);// ["aa", "bb", "cc"]
    
    var obj2 = transition(obj);
    // 共享带来的问题:没法独立持有自己的信息了
    window.console.log(obj2.arr);// 是["aa", "bb", "cc"]而不是["aa", "bb"]
    

    ** 5)寄生式继承 **:原生式+工厂模式

    // 临时中转函数
    function transition(obj){
        function F(){};
        // 这里的F继承了obj
        F.prototype = obj;
        return new F();
    }
    
    // 寄生函数
    function create(o){
        var f = transition(obj);
        return f;
    }
    
    
    // 字面量方式声明一个对象
    var obj = {
        name : "zhangsanfeng",
        age : 100,
        arr:["aa","bb"]
    };
    
    var obj1 = create(obj);
    obj1.arr.push("cc");
    window.console.log(obj1.arr);
    
    var obj2 = create(obj);
    // 共享带来的问题:没法独立持有自己的信息了
    window.console.log(obj2.arr);
    

    ** 6)寄生组合继承 **

    // 临时中转函数
    function transition(obj){
        function F(){};
        // 这里的F继承了obj
        F.prototype = obj;
        return new F();
    }
    
    // 寄生函数,子类的原型指向建立的中转对象,中转对象原型指向超类:原生链继承
    function create(parent,child){
        var f = transition(parent.prototype);
        f.constructor = child; // 
        child.prototype = f; // child的原型指向了中转类
    }
    
    
    function Human(name){
        this.name = name;
    }
    
    Human.prototype.run = function(){
        window.console.log(this.name + "..............");
    }
    
    function Man(name,sex){
        // 对象冒充,实现参数传递
        Human.call(this,name);
        this.sex  = sex;
    }
    
    // 寄生组合继承
    create(Human,Man);
    
    var man = new Man("张三丰88","男");
    man.run();
    window.console.log(man.name + "," + man.sex);
    
    5 匿名函数与闭包
    // 匿名函数赋值给变量
    var add = function(){
        window.console.log("hhhhhhhhhhhhhhhhhhh");
    };
    add();
    
    
    // 自运行 (匿名函数)()
    (function(name){
        window.console.log(name + "来自于中国。。。。。。。");
    })("zhangsanfeng");
    
    // 函数里面放置一个匿名函数
    function userInfo (){
        return function(){ // 闭包:在一个函数中创建另外一个函数,通过另外一个函数访问这个函数的局部变量
            return "userInfo"
        }
    }
    
    window.console.log(userInfo()());
    
    function increase(){
        var count = 0;
        return function(){
            count++;
            return count;
        }
    }
    
    window.console.log("count1 = " + increase()());
    window.console.log("count2 = " + increase()());
    window.console.log("count3 = " + increase()());
    var f = increase();
    // 闭包的优点也是缺点:闭包作用域里面的局部变量资源不会被立刻销毁,如果使用不当,会造成内存泄漏
    window.console.log("count11 = " + f());
    window.console.log("count12 = " + f());
    window.console.log("count13 = " + f());
    

    循环中的闭包

    function arrCreate(){
        var arr = [];
        for(var i=0;i<5;i++){
            // 匿名函数自我执行
            arr[i] = (function(num){
                return num;
            })(i);
        }
        return arr;
    }
    
    var arr = arrCreate();
    for(var i=0;i<5;i++){
        window.console.log("arr[" + i + "] = " + arr[i]);
    }
    //////////////////////////////////////////////////////
    function arrCreate(){
        var arr = [];
        for(var i=0;i<5;i++){
            arr[i] = (function(num){
                // 局部变量驻留在内存中
                return function(){
                    return num;
                };
            })(i);
        }
        return arr;
    }
    
    var arr = arrCreate();
    for(var i=0;i<5;i++){
        window.console.log("arr[" + i + "] = " + arr[i]());
    }
    

    闭包引起的内存泄漏问题:

    window.onload = function test(){
        var testDiv = document.getElementById("testDiv");
        testDiv.onclick = function(){
            // 这里的testDiv将驻留在内存中,得不到及时的释放,将会引起内存泄漏
            window.console.log("hhh-->" + testDiv.innerHTML);
        }
    };
    

    模仿块级作用域

    (function test () {
        for (var i = 0; i < 5; i++) {
            
        }
        // 因为JavaScript中并没有块级作用域这种概念,所以这里的i是还能访问到的
            // 即使这里再次声明了i,比如var i;也是没有作用的
        window.console.log("i = " + i);
    })();
    
    (function test () {
        (function(){ // 闭包模仿块级作用域
            for (var i = 0; i < 5; i++) {
                window.console.log("i = " + i);
            }
        })();
        // 这里就访问不到i了
        window.console.log("i = " + i);
    })();
    
    

    相关文章

      网友评论

        本文标题:Javascript相关知识

        本文链接:https://www.haomeiwen.com/subject/topmettx.html