• JavaScript高级部分概念用法


    一、执行上下文

    也称为可执行代码和执行上下文
    执行代码:1.全局代码 2.函数代码 3.eval代码
    eval("var a = 200;console.log(a)")
    执行上下文 - Context 
    所处的一个环境,环境不同含义也随着改变了
    当可执行代码执行的过程中,都会产生一个可执行环境
    在执行完之后,执行上下文的环境也随着销毁
    执行上下文中变量存在于:
    变量对象:VO - var 声明的一个属性值 - 全局 
    活动对象:AO - 相对于函数创建的对象中的一个声明 - 局部 - 随执行完后销毁
    不管变量在什么地方声明,都会在函数一运行就声明一个函数中的变量
    变量提升:指一个函数上下文创建时,函数中的所有变量都会随函数的创建提升
        var x = 100;
        var outFunc = function(){
            x++;
            console.log(x);//NaN
            var x = 200;
        }
        outFunc();
        console.log(x);//100
    函数中 x 声明提前,但是赋值并没有提前,所有此时的x为undefined,undefined进行运算结果就为NaN
    
    var  outFunc = function(){
        var a = 100;
        var innerHtml = function(){
            var b = 200;
            a = b;//a替换了outFunc()中a var a = 100的值 此时a = 200;
    //      c = a;
        }
        innerHtml();
        console.log(["inner:",a]);//200
    }
    outFunc();//该函数在运行完后函数中的变量随之销毁
    console.log("outer:",a);//not defined
    

    二、作用域 作用域链

    作用域:即为代码的作用范围
    作用域链:函数的变量不使用var声明的情况下,声明变量会一直往上查找该变量的值,直到全局变量还没有就创建一个全局变量
    Scope对象 - 存放上一层中的对象引用 - 属于某一个函数的属性,当函数一创建就已经有该函数的scope对象引用了
    每个函数都包含自己本身的VO、Scope对象、作用域链对象
    var food = "包子";
    var eat = function(){
        console.log(food);//包子
    }
    (function(){
        var food = "油条";
        eat()
    })
    
    var foo = 1;
    function bar(){
        if(!foo){
            var foo = 10;//foo会变量提升到bar函数中,但值不会提升此时提升的foo为undefined !foo 刚好满足条件
        }
        console.log(foo);
    }
    bar();
    
    var a = 1;
    function b(){
        a = 10 ;//a = a()
        return;
        function a(){}//会变量提升到函数的前面
    }
    b();
    console.log(a);
    
    var f = true;
    if(f === true){
        var a = 10;
    }
    function fn(){
        var b = 20;
        c = 30;
    }
    fn();
    console.log(a);//10
    console.log(b);//not definnd
    console.log(c);//30
    
    if('a' in window){
        var a = 10;//变量提升至if判断外,但值不会提升;没有var 不会先变量提升会先判断是否进入判断
    }
    console.log(a);//10
    
    var a = b =3;
    (function(){
        var a = b = 5;//var a = 3; b = 5
    })();
    console.log(a);//3
    console.log(b);//5
    
    var foo = 'A';
    console.log(foo);   //A
    var foo = function(){
        console.log('B');
    }
    console.log(foo);   //function(){console.log('B');}
    foo();              //B
    function foo(){     //函数是在最开始的时候就存在了,但在var foo 声明后被覆盖了,已经被提升;会影响代码的上下顺序
        console.log('C');
    }
    console.log(foo);   //function(){console.log('B');} - 
    foo();              //B
    
    var a = 1;
    function b(){
        console.log(a);//undefined
        a = 2;
        console.log(a);//2
        var a = 3;
        console.log(a);//3
    }
    console.log(a);//1
    b();
    console.log(a);//1
    
    //闭包相关的函数值
    var x = 100;
    var y = 200;
    function funcA(x){
        var y = 201;
        function funcB(){
            console.log(x);//101
            console.log(y);//201
        }
        return funcB;
    }
    var f = funcA(101);
    f();  
    

    三、this关键字

    this 也称为当前对象,是用于对象当中,属于第一人称,所处的环境不一样指代的含义也不同
    如果在对象的方法中只要在嵌套的函数中的this就不会再指向当前对象中的this了
    比如:
    var name = "张三";
    var func = function(){
        console.log(this.name);//此时的this指向的是全局变量
    }
    func();
    fnnc.apply();
    func.call()
    var obj = {
        name:"王五",
        func:function(){
            console.log(this.name);//此时的this 指向的是对象中的name
            (function(){
                console.log(this.name);//此时的this指向的不是对象的name,而是全局变量
            })()
        }
    }
    obj.func();
    
    改变this指向的方法:
    1.call
    2.apply
    两者的作用是相同的,可以帮助完成方法的调用,默认this指向为全局,要想访问嵌套对象,就将其赋值给一个变量
    call() Or apply()可以改变this的对象,第一个参数是不能省的
    区别:
    var sum = function(a,b){console.log(a+b)}
    sum.call(null,100,200) - 采用的是参数列表
    sum.apply(null,[100,200]) - 采用的是数组
    
    ***练习***
    var myObject = {
        foo:"bar",
        func:function(){
            var self = this;
            console.log(this.foo);//bar
            console.log(self.foo);//bar
            (function(){
                console.log(this.foo);//undefined
                console.log(self.foo);//bar
            })()
        }
    }
    myObject.func();
    
    var user = {
        count:1,
        getcount:function(){
            return this.count;
        }
    }
    console.log(user.getcount());//1
    var func = user.getcount;//func就代表user.getcount这个函数
    console.log(func());//undefined - func()已经成为全局,全局中没有count这个变量,所以值为undefined
    

    四、闭包 - closure

    闭包:是指能够访问函数内部变量的函数,定义在函数内部的函数。
    一个函数引用了外部的自由变量,那么这个函数就叫闭包,被引用的函数和引用的函数是一同存在的。
    自由变量 - 跨作用域的变量或父级的变量
    函数必须引用外部变量,函数还必须被引用才能成为闭包
    优点:可以把一个局部变量存在的时间延长,进行持续保存
    缺点:如果大量的使用闭包,持续保存的变量会一直占有内存,造成内存的浪费
    常用:事件处理常常会使用到闭包
    
    var lis = document.getElementsByTagName("li");
    for(var i = 0;i<lis.length;i++){
        //方法实现一
        (function(index){//阻止闭包
            lis[index].onclick = function(){
                console.log("这是选中的地"+(index+1)+"项");
            }
        })(i)
        //方法实现二
        var func = function(index){
        lis[index].onclick = function(){
                console.log("这是选中的地"+(index+1)+"项");
            }
        }
        func(i);
    }
    
    //闭包练习
    function Foo(){
        var i = 0;
        return function(){
            console.log(i++);//i++先赋值再运算
        }
    }
    var f1 = Foo();
    var f2 = Foo();
    f1();//0
    f2();//0
    f2();//1
    

    五、面向对象 - OO - Object Oriented

    语言分类大致分为两大类 - 范式
    1.命令式 - 通过语言告诉计算机应该如何做事情
    比如:java、C语言(为程序语言的发展做出贡献)
    命令式的两种思想:
        1.1.面向过程 - 将过程逐一分解为一个一个的步骤执行 - 计算机的思维方式为主体
        缺点:人的思维有限,如果程序实现的过程很复杂,人会不能完全考虑 
        1.2.面向对象 - 本身就是人的思考方式,人的思维为主体,从自身角度出发 - 特征、行为 - 万物皆对象,对象因关注而产生
    
    2.声明式 - 告诉计算机我想要什么,然后计算机进行相关的动作,然后计算机自己进行运算得到我想要的结果
    比如:Css
    声明式的三大类:
        2.1.领域特定语言 - DSL - 在特定范围的语言 - HTML、Css、SQL、正则表达式
        2.2.函数式编程 - 类似公式,计算机就会按照这个公式进行计算并返回结果 
        与命令式编写相比,函数式编程更为精简,能够完善命令式编程的一些缺陷 - lisp、Haskell
        2.3.逻辑编程 - prolog - 记日志比较好的方法
    
    构建对象的两种方式:
    1.基于类的面向对象 - 拥有相同属性的划分为一类,类是对象的抽象,对象是类的实例
    2.基于原型的面向对象 - JavaScript原型就有一个Object对象,通过一个原型克隆一个对象
    好处:足够灵活
    缺点:随意性太强,对于初学者容易出错
    面向对象三大特征:
    1.封装 - 需重点了解 - 指实现细节隐藏起来的过程就是封装 
        优点: - 但还需要考虑参数的问题
        1.1.隐藏实现的细节
        1.2.重用 - 不变的整合在一起,变化的作为参数
    
        JavaScript中属性都应为私有,方法可以为公共 - 由我们自己控制
        pulic - 公共,其他方法可以访问
        private - 私有,只能自己能够访问
        set/get - 访问器/修改器
    
        var Student = function(name,age,gender){
            this.name = name;
            var _age = age;//添加 _ 可将变量变为私有变量,外部不能随意访问
            var _gender = gender;
            if(!Student._init){
                Student.prototype.getAge = function(){
                    return _age;
                }
                Student.prototype.setAge = function(age){
                    if(age > 20 && age < 30){
                        _age = age;
                        console.log(_age);
                    }else{
                        console.log("年龄修改不能在 20 - 30 之外");
                    }
                }
                Student.prototype.getGender = function(){
                    return _gender;
                }
                Student.prototype.setGender = function(gender){
                    _gender = gender;
                    console.log(_gender);
                }
            }
            Student._init = true;
        }
        var stu = new Student("张飞",20,"男");
        stu.name = "关羽";
        stu.setAge(31);
        console.log(stu.getAge());
        console.log(stu.getGender());
        stu.setGender("无");
    
    2.继承 - 存在于有父与子的关系中 - 出现率较高 - 指采用一个对象的功能并且能够添加新的功能
        优点:
        2.1.复用
        2.2.扩展
        缺点:
        如果继承设计的不够完善,会致使变得复杂,难以操控
        继承的3种方法:
        1.对象冒充法 - instanceof - 判断是否为继承
        2.原型链 - 将自己的原型改变为父级的对象
        3.混合方式 - 
    //  1.对象冒充法
        /*var People = function(name){
            this.name = name;
        }
        People.prototype.intro = function(){
            console.log("HI,我是"+this.name);
        }
        var ChinesePeople = function(name){
            this.inhert = People;
            this.inhert(name)
            delete this.inhert;
        }
        var info = new ChinesePeople("张三");
        console.log(info.name);
        console.log(info instanceof ChinesePeople);*/
    
    //  2.原型链
    /*  var People = function(name){
            this.name = name;
        }
        People.prototype.intro = function(){
            console.log("HI,我是"+this.name);
        }
        var ChinesePeople = function(name){
    
        }
        ChinesePeople.prototype = new People("张三");
        ChinesePeople.prototype.area = function(){
            console.log("我是中国人");
        }
        var info = new ChinesePeople("张三");
        console.log(info.name);
        console.log(info instanceof ChinesePeople);
        info.intro();
        info.area();*/
    
    //  3.混合
        /*var People = function(name){
            this.name = name;
        }
        People.prototype.intro = function(){
            console.log("HI,我是"+this.name);
        }
        var ChinesePeople = function(name){
            People.call(this.name);
        }
        ChinesePeople.prototype = new People("张三");
        ChinesePeople.prototype.area = function(){
            console.log("我是中国人");
        }
        var info = new ChinesePeople("张三");
        console.log(info.name);
        console.log(info instanceof ChinesePeople);
        info.intro();
        info.area();*/
    3.多态 - JavaScript本身就是一个多态的行为
    
    var Student = {
        "name":"张飞",
        "age":20,
        "learn":function(){
            console.log(this.name+"学习JavaScript")
        }
    }
    Student.gander;//访问的属性不存在 值为 undefined
    Student.learn();
    Student.name;
    Student["name"];
    Student["lea"+"rn"];//动态的属性值使用中括号或者字符串拼接
    
    //构造函数
    var Student = function(name,age){
        this.name = name;
        this.age = age;
        this.learn = function(){
            console.log(this.name+" - "+this.age);
            var that = this;
            (function(){
                console.log(that);
            }())
        }
    }
    var stu1 = new Student("张飞",20);//stu1 为一个对象
    var stu2 = new Student("刘备",21);
    Student.prototype.gander = "男";//在原型中添加一个性别的属性
    Student.prototype.play = function(){//在原型中创建一个play 的方法
        console.log(this.name+" - "+this.age+" - "+"喜欢玩游戏");
    }
    stu1.learn();
    console.log(stu1.gander);
    stu1.play();
    stu2.learn();
    Studetn.prototype;//可以改变一个对象真正的原型,但是不能多次调用
    stu1.__proto__; //只是更改了stu1的引用原型,而不是本身的原型,只是对象的一个属性,可以通过属性一层一层的访问到对象的原型
    
    对象 → 自定义对象原型 → Object对象 → Object原型 → Null
    
    if(!Student._int){//首先判断Student._int是否为假,Student._int事先不存在即为假,进入判断,Student._int变为真,不在进入判断,该判断这样就只能判断一次
        Student.prototype.learn = function(){
            console.log(this.name+" - "+this.age);
        }
        Student.prototype.play = function(){//在原型中创建一个play 的方法
            console.log(this.name+" - "+this.age+" - "+"喜欢玩游戏");
        }
        Student._int = true;
    }
    
    两个运算符:new - 创建对象; delete - 删除属性 - delete.stu1.name;//stu1中的name属性就被删除了,只能删除原型创建的而不能删不是原型创建的属性
    两个语句:with - 性能有一定的问题,尽量不使用; for..in - 不拿来循环数组;
    
    var stu1 = new Student("张飞",20);//stu1 为一个对象
    var stu2 = new Student("刘备",21);
    for(var key in stu1){
        console.log([key,stu1[key]]);
    }
  • 相关阅读:
    如果 TCP 是一场恋爱:遇到心动的女孩时,如何去把握?
    再来聊一聊「动态规划」
    如何判断一个数是否在 40 亿个整数中?
    写代码之外,如何再赚一份工资?
    学好这13种数据结构,应对各种编程语言(C++版)
    GitHub 标星 3w+,很全面的算法和数据结构知识
    和程序员小吴学算法文章导航
    Broadcast组件——收发广播应用——捕获屏幕的变更事件——竖屏与横屏切换
    homebrew
    git连接gitlab远程仓库
  • 原文地址:https://www.cnblogs.com/1039595699TY/p/5642080.html
Copyright © 2020-2023  润新知