JavaScript|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 doinga.[[ scope ]] --> 0 : aAO //1 : GO// a 的执行,产生了 b 的定义// b defined b.[[ scope ]] --> 0 : aAO //1 : GO// b doingb.[[ 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.healththis表示当前,第一人称 } }

  2. 属性的增、删、改、查

    • mrZhang.wife = 'xiaoliu'


    • delete mrZhang.wife


    • mrZhang.sex = 'female'

    • 【JavaScript|JavaScript 基础】
      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; // deleteconsole.log(num.len) // new Number(4).lenundefined

原型
  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:8Object.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);

    推荐阅读