JavaScript 基础

浏览器

  1. 主流浏览器

    • IE Trident
    • Firefox Gecko
    • Safari Webkit
    • Chrome Webkit/Blink
    • Opera Presto
  2. 浏览器组成部分

    1. shell 部分
    2. 内核部分
      • 渲染引擎(语法规则和渲染)
      • js 引擎
      • 其他模块

JavaScript基础知识

引入方式
  1. 内部脚本

  2. 外链脚本

WEB标准

W3C标准:结构、样式、行为相分离,通常都会采用外链的方式

变量(varible)
  • 变量声明

    • 声明、赋值分解

      var a; //变量声明
      a = 1000;  //变量赋值
      
    • 单一 var

      var a, 
          b, 
          c = 300, 
          d = 400, 
          e = 500;
      a = 100;
      b = 200;
      //...
      
  • 命名规则

    1. 变量名必须以 英文字母 、_ 、$ 开头
    2. 变量名可以包括 英文字母、_ 、$、数字
    3. 不可以使用系统的 关键字、保留字 作为变量名
值类型 - 数据类型
  1. 原始值
    • Number 数值类型
    • String 字符串类型
    • Boolean 布尔类型
    • Undefined 使用的变量定义后未赋值
    • Null 空值,对象占位符
  2. 引用值
    • Array 数组类型
    • Object 对象
    • Function 函数
    • Date 时间函数
    • RegExp 正则表达式
  3. 两种值得区别
    1. 原始值存储于栈(stack)内存中 先进后出(first in last out)

    2. 引用值大部分存储于堆(heap)内存中 (先进先出)

Error
  1. 语法错误

  2. 逻辑错误

  3. 一个代码块发生错误,不会影响其他代码块的执行

运算操作符
  • “ + ”

    1. 数学运算、字符串连接
    2. 任何数据类型与字符串相加都等于字符串
  • “ - “,” * “,” / “," % ",” = “,” () “

    1. 与数学运算相同
    2. ” () “ 优先级最高,” = “ 优先级最低
  • ” ++ “,” -- “,” += “,” -= “,” /= “,” *= “,” %= “

比较运算符
  • ” > “,” < “,” == “,” >= “,” <= “,” != “

  • 比较的结果为 boolean 类型

  • 字符串比较的是 ascii 码

逻辑运算符
  • ” && “,” || “,” ! “

    • data && console.log('数据传递失败');       //短路语句
      
    • var a = 0 || false || 1;
      var handleClick = function(e) {
          var event = e || window.event;   // 做IE浏览器的兼容
      }
      
  • 被认为 false 的值

    • undefined

    • null

    • NaN

    • ""

    • 0

    • false

条件语句
  • if

  • if else

  • while

  • do-while

  • switch case

  • break

  • continue

typeof 六种数据类型
  • number

  • string

  • boolean

  • object

    • 数据、对象和null都会返回object (null 最初是对象占位符,属于历史遗留问题)
  • undefined

  • function

类型换换
  • 显示类型转换

    • Number(num); 将其参数转换为数值类型并返回。 null = 0, undefined = NaN, "123abc" = NaN
    • parseInt(num,基底); 将第一个参数转换为整数类型并返回,第二个参数可以表明第一个参数的基底,然后转换为十进制,进行到非数字位截止。 true/false = NaN, 123.9 = 123 , 123abc = 123
    • parseFloat(num); 转换成浮点类型,识别到非数字位并且只识别一个小数点
    • String(str); 转换为字符串
    • Boolean(); 转换为布尔类型
    • toString(redix); 是用 “.” 的方式调用当前方法,转换成字符串类型, radix 转换成目标进制。 undefined / null 不可以使用当前方法
  • 隐式类型转换

    • isNaN(); 判断是不是不是一个数

      isNaN('abc') -隐式调用-> Number('abc') =然后和NaN进行比较= NaN?  true:false;
      
      
    • ++/-- 、+/-(一元正负)

      //自动隐式调用Number(),强制转换成Number类型
      var a = "123";
      a++;
      // a = 124
      var b = "abc";
      b++;
      // b = NaN
      

      当加号两边有一个是字符串的,则将两边都转换为字符串并连接,如果是数值就做加法运算

    • -、*、/、%

      隐式调用Number()方法,

    • &&、||、!

    • <、>、<=、>=

      比较时数字优先

    • ==、!=

      数值类型

  • 不发生类型转换

    • ===
    • !==
函数
  • 定义

    • 函数声明

      function function_name() {
      }
      
    • 函数表达式

      // 命名函数表达式
      var function_name = function test() {  
          // test不代表函数体,在函数中 function_name.name  == test 
          console.log(function_name.name);   //test
      }
      // 匿名函数表达式 ** 常用 推荐 **
      var function_name = function() {
          
      }
      
  • 组成形式

    • 函数名称

      • 命名规则和变量一致
      • 多个单词使用小驼峰命名法 theIsFunctionName
    • 参数

      • 形参

        // 传递形式参数(形参)
        function function_name(a, b) {
            // 在括号中传递a, b就相当于 隐式的在函数中  var a; var b;
        }
        
      • 实参

        // 传递实际参数(实参)
        function_name(1, 2);
        
      • arguments 实参列表

        一个类数组,保存传进来的实参

        function function_name(a, b, c) {
            console.log(arguments);   // 打印实参列表
            console.log(function_name.length);  // 计算形参的长度
        }
        function_name(1, 2, 4)
        
    • return

      • 终止函数

        return 之后的语句将不会得到执行

      • 返回值

        将内部值返回到外部

递归
  • // 1. 找规律    2. 找出口
    
    // 使用递归实现阶乘和斐波那契数列
    function mul(n) {
        if(n == 1 || n == 0) {
            return 1;
        }
        return n * mul(n - 1);
    }
    console.log(mul(5))
    
    function fb(n) {
        if(n == 1 || n == 2) {
            return 1;
        }
        return fb(n-1) + fb(n-2);
    }
    fb(10);
    
JS执行三部曲(预编译)
  1. 语法分析(通篇扫描是否存在语法错误)

  2. 预编译

    预编译发生在函数执行的前一刻

    函数声明整体提升,变量 声明提升,提升到逻辑的最前

    不够严谨

    • 预编译前奏

      1. imply global 暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为全局对象所有。

        a =  123;   // a 为全局变量
        function ao() {
            var a = b = 123;   // b 为暗示全局变量 
        }
        
      2. 一切声明的全局变量,全是window的属性。

        
        
    • 预编译四部曲

      1. 创建AO()对象
      2. 将形参和变量声明作为AO对象的属性,并赋值undefined
      3. 将实参和形参相统一
      4. 将函数声明作为AO对象的属性,并将函数体作为它的的值
      function fn(a) {
          console.log(a);    // fn() {}
          var a = 123;
          console.log(a);    // 123
          function a() {};
          console.log(a);    // 123
          var b = function() {};
          console.log(b);    // fn() {}
          function d() {};
      }
      fn(1);
      
      /*
         1.创建AO对象
          AO{
          
          }
          
          2.将形参和变量声明作为AO对象的属性,并赋值 undefined
          AO{
             a : undefined   形参和变量相同时后者覆盖
             b : undefined
          }
          
          3.将实参和形参相统一
          AO{
             a : 1,
             b : undefined
          }
          
          4.将函数声明作为AO对象的属性,并赋值函数体
          AO{
             a : fn(){}
             b : undefined
             d : fn(){}
          }
      */
      
  3. 解释执行

作用域
  1. 作用域初探

    作用域定义:变量(变量作用域又称上下文)和函数生效(能被访问)的区域

    • 全局变量

      
      
    • 局部变量

      
      
    • 访问顺序

      内部可以访问外部变量,外部不可以访问内部变量,自内向外

  2. 作用域精解

    • 执行期上下文

      当函数执行时,会创建一个称为 执行期上下文 的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行期上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行期上下文,当函数执行完毕,它所产生的执行期上下文被销毁

    • 查找变量

      从作用域的顶端依次向下查找

    • [[ scope ]]

      每个javascript函数都是一个对象,对象中有些属性我们可以访问(例如: function_name.name),但有些不可以,这些属性仅供javascript引擎存取,[[ scope ]] 就是其中一个。

      [[ scope ]] 指的就是我们所说的作用域,其中存储了执行期上下文的集合。

    • 作用域链

      [[ scope ]] 中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链

    // 每个函数被创建时,会根据当前的执行环境生成作用域链,保存在当前函数的 [[ scope ]] 属性作用域链中
    // 当函数被执行时,会生成自己的作用域放在[[ scope ]]属性作用域链的最顶端
    
    function a() {      // 1. a 函数被定义  [[ scope ]]  0 : GO
        function b() {   // 3. b 函数被定义,拿到当前执行环境的作用域链 [[ scope ]] 0 : AO(a 函                          数的AO), 1 : GO
            var b = 234;
        }
        var a = 123;
        b();         // 4. b 函数被执行,生成自己的执行期上下文(AO对象),存进 [[ scope ]]作                         用域链中  0 : AO(b 函数的), 1 : AO(a 函数的), 2 : GO
    }
    var glob = 100;
    a();  // 2. a 函数 被执行 [[ scope ]] 0 : AO(a 函数的AO对象), 1 : GO
    
  3. 总结案例

    function a() {
        function b() {
            function c() {
                
            }
            c();
        }
         b();
    }
    a();
    // a defined a.[[ scope ]] --> 0 : GO
    
    // a doing   a.[[ scope ]] --> 0 : aAO
    //                             1 : GO
    
    // a 的执行,产生了 b 的定义
    
    // b defined b.[[ scope ]] --> 0 : aAO
    //                             1 : GO
    
    // b doing   b.[[ scope ]] --> 0 : bAO
    //                             1 : aAO
    //                             2 : GO
    
    // b 的执行,产生了 c 的定义
    
    // c defined c.[[ scope ]] --> 0 : bAO
    //                             1 : aAO
    //                             2 : GO
    
    // c defined c.[[ scope ]] --> 0 : cAO
    //                             1 : bAO
    //                             2 : aAO
    //                             3 : GO
    
    // 所有的 GO、aAO、bAO、cAO 都是同一个执行上下文
    // 当一个函数执行完毕时,相对应的执行上下文也会跟着销毁
    
    
闭包
  • 定义

    当内部函数被保存到外部时,将生成闭包。闭包会导致原有作用域链不释放,造成内存泄漏。

  • 作用

    • 实现公有变量(累加器)

      function add() {
          var count = 0;
          function demo() {
              count ++;
              console.log(count);
          }
          return demo;
      }
      var counter = add();
      counter();
      counter();
      counter();
      
    • 做缓存(存储结构)

      function test() {
          var num = 100;
          function a() {
              num ++;
          }
          function b() {
              num --;
          }
          return [a, b];
      }
      var myArr = test();
      myArr[0]();
      myArr[1]();
      
      // -----------------------------------------------------------------------------
      
      function eater() {
          var food = "";
          var obj = {
              eat : function(){
                  console.log("i am eating" + food);
              },
              push : function(myFood) {
                  food = myFood;
              }
          }
          return obj;
      }
      obj.eat();
      
    • 实现封装,属性私有化

      
      
      
    • 模块化开发,防止污染全局变量

  • 案例

    function a() {
        var num = 100;
        function b() {
            num ++;
            console.log(num);
        }
        return b;  // 将 b 返回到外部,导致原有的作用域链不释放
    }
    var demo = a();
    demo();    //101
    demo();    //102
    
立即执行函数
  • 定义

    此类函数没有声明,在一次执行过后释放。适合初始化工作

  • 语法

    // 立即执行函数执执行完之后立即销毁,初次之外和普通函数没有任何不同
    var num = (function (a, b, c) {
        
        return a + b + c;
        
    }(1, 2, 3))
    
  • 拓展

    // 立即函数不同写法
    (function () {}());  // W3C推荐
    (function () {})(); 
    
    // 只有表达式才可以被执行符号执行
    
    function test() {
        console.log('a');
    }();  // 语法错误,此种方式不可以被执行,这种叫做函数声明
    
    // 能被执行符号执行的函数,这个函数的名字就会被自动忽略
    
    var a = function() {  // a 不再代表函数了
        console.log('a');
    }();  // 可以,函数表达式
    
    // ()、+(正)、-(负)、!、&&、|| 都可以将一个函数转换为表达式
    
    - function() {
        console.log('a');
    }();
    // ...
    
    // !!! 注意
    function test(a, b, c) {  // 在这中情况下,系统不会报错,但也不会执行
        console.log(a, b, c)
    }(1, 2, 3);
    // 系统会自动识别成这样
    function test(a, b, c) {
        console.log(a, b, c);
    }
    (1, 2, 3); // 不识别成执行符号,看做一个独立的**逗号表达式(知识点再后续文档中呈现)**
    
    
闭包补充
  1. 闭包的防范

    闭包会导致多个执行函数共用一个公有变量,如果不是特殊需求,尽量防止这种情况发生。

  2. 经典案例

    // 给数组的每一位绑定一个函数,并打印出当前下标
    function test() {
        var arr = [];
        for(var i = 0; i < 10; i ++) {
            arr[i] = function () {      // 赋值函数
                document.write(i + " ")
            }
        }
        return arr;  // 返回到外部,形成了闭包
    }
    var myArr = test();
    for(var j = 0; j < 10; j ++) {
        myArr[j]();
    }
    // 执行结果 10 10 10 10 10 10 10 10 10 10    
    // 形成了闭包,由于在执行数组中的函数时,test 已经执行完毕。 i = 10并不再循环,这是for的判断条件
    // 形成闭包执行,这10个函数访问的 i 在 test的AO里都已经变成了10
    
    // 解决方法
    function test() {
        var arr = [];
        for(var i = 0; i < 10; i ++) {
            (function(n) {    // 使用立即执行函数
                arr[n] = function() {
                    document.write(n + " ")
                }
            }(i))
        }
        return arr;
    }
    var myArr = test();
    for(var j = 0; j < 10; j ++) {
        myArr[j]();
    }
    
逗号操作符
// 逐个审查每一位元素。如果某位元素需要计算,则计算该元素。最后,返回最后一个元素的计算结果
var a = (2, 3);
var f = (
    function f() {
        return '1';
    },
    function g() {
        return 2;
    }
)();
typeof(f);
对象
  1. 是一种基础的变量类型,属于引用值

    var mrZhang = {
        name : 'zs',
        age : 22,
        sex : 'male',
        health : 100,
        smoke : function() {
            console.log('I am somkeing');
            mrZhang.health --; // this.health  this表示当前,第一人称
        }
    }
    
  2. 属性的增、删、改、查

    • mrZhang.wife = 'xiaoliu'
      
    • delete mrZhang.wife
      
    • mrZhang.sex = 'female'
      
    • mrZhang.name
      
  3. 对象的创建方法

    • 字面量

      var obj = {};    // plainObject 对象字面量 / 对象直接量
      
    • 构造函数

      • 系统自带

        new Object();  // 得出相同,且相互独立的对象
        Array();
        Number();
        Boolean();
        string();
        Date();
        
      • 自定义

        function Car(color) { // 为区分自定义函数,使用大驼峰命名法
            this.color = color;
            this.name = 'BMW';
            this.height = '1400';
            this.lang = '4900';
            this.weight = '1000';
            this.health = 100;
            this.run = function() {
                this.health --;
            }
        }
        var car1 = new Car('red');
        var car2 = new Car('green')
        
        
    • 构造函数的内部原理

      // new 之后函数的变化
      function Student(name, age, sex) {
          // var this = {}, AO{ this:{name:'zhagnsan'} }  // 隐式创建一个this对象
          this.name = name;
          this.age = age;
          this.sex = sex;
          this.grade = 2017;
          
          // return this;  隐式 return this;
      }
      var student = new Student('zhangsan', 22, 'male');
      
      //------------------------------------------------------------------------------
      /*
         1. 在函数体最前面隐式的创建 this = {};
         2. 执行 this = xxx;
         3. 隐式的 return this;
             3.1. 可以手动显示 return ({}, [], /..)类型为obj的值,原始值是无效,自动忽略的
         
         !!!并不是最终形式,后续补充
      */
      
      // 模拟构造函数(只是简单模拟,并不推荐使用。因为还有更深层次的东西模拟不了,后续补充)
      function Person(name, height) {
          var that = {};
          that.name = name;
          this.height = height;
          return that; 
      }
      var person1 = Person('xiaowang', 180);
      
包装类
  • Number();

  • String();

  • Boolean();

    // 包装类过程
    
    var num = 4;   
    // 原始值是坚决不能用属性的
    
    num.len = 3;   
    // new Number(4).len = 3;   
    // delete
    
    console.log(num.len)
    // new Number(4).len   undefined
    
原型
  1. 定义:原型式 function 对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承原型的属性和方法,原型也是对象。

    // Person.prototype  -- 原型
    // Person.prototype = {} 祖先
    Person.prototype.name = 'hehe';
    function Person() {
        // this.name = 'zs';  如何构造函数中存在和原型中相同的属性,会调用构造中的
    }
    var person1 = new Person(); // 都继承了原型的 name 属性
    var person2 = new Person();
    
    // 原型的 增、删、改、查
    // Person.prototype.sex = 'male'
    // delete Person.prototype.sex
    // Person.prototype.sex = 'female';  
    // Person.prototype.sex = 'male'
     
    Person.prototype = {   // 也可以这样定义原型
        height : 180,
        //...
    }
    
  1. 利用原型的特点和概念,可以提取共有属性。

    Car.prototype = {   // 将公有部分提取到原型中
        naem : 'BMW',
        height : 1400
        //...
    }
    function Car(color) {
        this.color = color;
    }
    var car1 = new Car('red');
    
  1. 对象如何查看对象的构造函数 -> constructor

    function Car() {
        
    }
    var car1 = new Car();
    console.log(car1.constructor); // 这个方法也是在原型中继承过来的,可以手动更改
    /*
    Car.prototype
     {constructor: ƒ}
         constructor: ƒ Car() 
         __proto__: Object 
    */
    
  2. 对象如何查看原型 -> 隐式属性 __proto__

    //  查看 person1.__proto__
    Person.prototype.name = 'zs';
    function Person() {
        // var this = {
        //    __proto__ : Person.prototype, 当发生 new 的时候,this对象中就会存在__proto__属性
        //                                 也就是说,如果 person1 查找属性,在Person构造中不                                         存在的话,就会通过__proto__属性所绑定的原型来查找,                                        这是系统提供的属性
        // }
    }
    var person1 = new Person(); 
    console.log(person1.name)
    
原型链
  • 如何构成原型链?

    // 手动的更改构造函数的原型,连成一个链,称为原型链
    function Grand() {
        this.grandName = 'grand'
    }
    var grand = new Grand();
    
    Father.prototype = grand;
    function Father() {
        this.fatherName = 'father';
    }
    var father = new Father();
    
    Son.prototype = father;
    function Son() {
        this.sonName = 'son';
    }
    var son = new Son();
    
  • 原型链上属性的增删改查

    增删改当前属性只能使用当前属性的原型来操作

    
    
  • 绝大多数对象最终都会继承自 Object.prototype

    // 执行
    Object.create()
    
    // 错误信息
    VM100:1 Uncaught TypeError: Object prototype may only be an Object or null: undefined
        at Function.create ()
        at :1:8
                            
    Object.create(null);  // 创建出的对象不会继承自 Object.prototype
    
  • Object.create()

    // 创建一个对象并指定原型
    // var obj = object.create(原型)
    
    var obj = {name : 'zs', age : 22, sex : 'male'};
    var student = Object.create(obj);
    
    Person.prototype.name = 'ls';
    function Person() {
    }
    var obj1 = Object.create(Person.prototype);
    

你可能感兴趣的:(JavaScript 基础)