前端——JavaScript

何谓JavaScript?它与Java有什么关系?

JavaScript与HTML、CSS组合使用应用于前端开发,JavaScript是一门独立的语言,浏览器内置了JS的解释器。它除了和Java名字长得相似,没有半毛线关系。

JavaScript的存在形式

1.JavaScript代码的存在形式

  1. 代码写在JS文件中,在html文件头部引入<script type"text/javascript" src="JS文件"></script>
  2. 代码写在html文件头部的<scrpit></script>标签中

2.JavaScript代码存放位置

  • HTML的head中

  • HTML的body代码块底部(推荐)

由于Html代码是从上到下执行,如果Head中的js代码耗时严重,就会导致用户长时间无法看到页面,如果放置在body代码块底部,那么即使js代码耗时严重,也不会影响用户看到页面效果,只是js实现特效慢而已。

变量

JavaScript中变量的声明是一个非常容易出错的点,局部变量必须一个 var 开头,如果未使用var,则默认表示声明的是全局变量。

<script type="text/javascript">
 
    // 全局变量
    name = 'seven';
 
    function func(){
        // 局部变量
        var age = 18;
 
        // 全局变量
        gender = "男"
    }
</script>

JavaScript中代码注释:

  • 单行 //
  • 多行 /*  */

注意:此注释仅在Script块中生效。

数据类型

JavaScript 中的数据类型分为原始类型和对象类型:

  • 原始类型
    • 数字
    • 字符串
    • 布尔值
  • 对象类型
    • 数组
    • “字典”
    • ...

特别的,数字、布尔值、null、undefined、字符串是不可变。

null是JavaScript语言的关键字,它表示一个特殊值,常用来描述“空值”。undefined是一个特殊值,表示变量未定义。

1.数字(Number)

JavaScript中不区分整数值和浮点数值,JavaScript中所有数字均用浮点数值表示。

转换:

  • parseInt(..)    将某值转换成数字,不成功则NaN
  • parseFloat(..) 将某值转换成浮点数,不成功则NaN

特殊值:

  •  NaN,非数字。可使用 isNaN(num) 来判断。
  • Infinity,无穷大。可使用 isFinite(num) 来判断。

2.字符串(String)

字符串是由字符组成的数组,但在JavaScript中字符串是不可变的:可以访问字符串任意位置的文本,但是JavaScript并未提供修改已知字符串内容的方法。

obj.length                           长度
obj.trim()                           移除空白
obj.trimLeft()      
obj.trimRight)
obj.charAt(n)                        返回字符串中的第n个字符
obj.concat(value, ...)               拼接
obj.indexOf(substring,start)         子序列位置
obj.lastIndexOf(substring,start)     子序列位置
obj.substring(from, to)              根据索引获取子序列
obj.slice(start, end)                切片
obj.toLowerCase()                    大写
obj.toUpperCase()                    小写
obj.split(delimiter, limit)          分割
obj.search(regexp)                   从头开始匹配,返回匹配成功的第一个位置(g无效)
obj.match(regexp)                    全局搜索,如果正则中有g表示找到全部,否则只找到第一个。
obj.replace(regexp, replacement)     替换,正则中有g则替换所有,否则只替换第一个匹配项,

3.布尔类型(Boolean)

布尔类型仅包含真假,与Python不同的是其首字母小写。

  • ==      比较值相等
  • !=       不等于
  • ===   比较值和类型相等
  • !===  不等于
  • ||        或
  • &&      且

4.数组(列表)

JavaScript中的数组类似于Python中的列表

obj.length          数组的大小
obj.push(ele)       尾部追加元素
obj.pop()           尾部获取一个元素
obj.unshift(ele)    头部插入元素
obj.shift()         头部移除元素
obj.splice(start, deleteCount, value, ...)  插入、删除或替换数组的元素
obj.splice(n,0,val) 指定位置插入元素
obj.splice(n,1,val) 指定位置替换元素
obj.splice(n,1)     指定位置删除元素
obj.slice( )        切片
obj.reverse( )      反转
obj.join(sep)       将数组元素连接起来以构建一个字符串
obj.concat(val,..)  连接数组
obj.sort( )         对数组元素进行排序

其他

1.序列化

  • JSON.string(obj)      序列化:将对象转化为字符串
  • JSON.parss(str)       反序列化:将字符串转化为对象类型

2.转义

很多时候需要将数据转义后,保存在cookie中。

  • decodeURI( )                       URl中未转义的字符
  • decodeURIComponent( )    URI组件中的未转义字符
  • encodeURI( )                       URI中的转义字符
  • encodeURIComponent( )    转义URI组件中的字符
  • escape( )                              对字符串转义
  • unescape( )                          给转义字符串解码
  • URIError                               由URl的编码和解码方法抛出

3、eval()

JavaScript中的eval是Python中eval()和exec()的合集,既可以编译代码也可以获取返回值。

  • eval() 
  • EvalError   执行字符串中的JavaScript代码

4、正则表达式

1、定义正则表达式

  • /.../  用于定义正则表达式
  • /.../g 表示全局匹配
  • /.../i 表示不区分大小写
  • /.../m 表示多行匹配

JS正则匹配时本身就是支持多行,此处多行匹配只是影响正则表达式^和$,m模式也会使用^$来匹配换行的内容)

var pattern = /^Java\w*/gm;
var text = "JavaScript is more fun than \nJavaEE or JavaBeans!";
result = pattern.exec(text)
result = pattern.exec(text)
result = pattern.exec(text)

注:定义正则表达式也可以  reg= new RegExp()

2、匹配

JavaScript中支持正则表达式,其主要提供了两个功能:

  • test(string)     检查字符串中是否和正则匹配
n = 'uui99sdf'
reg = /\d+/
reg.test(n)  ---> true
 
# 只要正则在字符串中存在就匹配,如果想要开头和结尾匹配的话,就需要在正则前后加 ^和$
  • exec(string)    获取正则表达式匹配的内容,如果未匹配,值为null,否则,获取匹配成功的数组。
获取正则表达式匹配的内容,如果未匹配,值为null,否则,获取匹配成功的数组。
 
非全局模式
    获取匹配结果数组,注意:第一个元素是第一个匹配的结果,后面元素是正则子匹配(正则内容分组匹配)
    var pattern = /\bJava\w*\b/;
    var text = "JavaScript is more fun than Java or JavaBeans!";
    result = pattern.exec(text)
 
    var pattern = /\b(Java)\w*\b/;
    var text = "JavaScript is more fun than Java or JavaBeans!";
    result = pattern.exec(text)
 
全局模式
    需要反复调用exec方法,来一个一个获取结果,直到匹配获取结果为null表示获取完毕
    var pattern = /\bJava\w*\b/g;
    var text = "JavaScript is more fun than Java or JavaBeans!";
    result = pattern.exec(text)
 
    var pattern = /\b(Java)\w*\b/g;
    var text = "JavaScript is more fun than Java or JavaBeans!";
    result = pattern.exec(text)

3、字符串中相关方法

obj.search(regexp)                   获取索引位置,搜索整个字符串,返回匹配成功的第一个位置(g模式无效)
obj.match(regexp)                    获取匹配内容,搜索整个字符串,获取找到第一个匹配内容,如果正则是g模式找到全部
obj.replace(regexp, replacement)     替换匹配替换,正则中有g则替换所有,否则只替换第一个匹配项,
                                        $数字:匹配的第n个组内容;
                                          $&:当前匹配的内容;
                                          $`:位于匹配子串左侧的文本;
                                          $':位于匹配子串右侧的文本
                                          $$:直接量$符号

5、时间操作

JavaScript中提供了时间相关的操作,时间操作中分为两种时间:

  • 时间统一时间
  • 本地时间(东8区)

首先生成Date对象 var d = new Date(); 

 

get 系列:获取时间 

set 系列:设置时间

设置分钟:

设置日期:

设置小时:

等等.....

6.定时器

1.setInterval("执行函数",间隔时间)  功能:每隔固定时间,执行指定函数,无限循环下去。(时间单位:毫秒)

        setInterval(function(){
            console.log();
        },5000),

2.(函数)(时间)  定时执行。在等待指定时间后,执行一次指定函数。(时间单位:秒)

        (function(arg){
            console.log(arg);
        })(1)

基本语法

1.条件语句

1. if...else... 语句

    if(条件){
 
    }else if(条件){
         
    }else{
 
    }

2. switch...case... 语句

    switch(name){
        case '1':
            age = 123;
            break;
        case '2':
            age = 456;
            break;
        default :
            age = 777;
    }

JS的if语句和switch语句和C语言的完全一样。

2.循环语句

JavaScript中支持若干种循环,其中最为常用的有三种循环

1.for循环(方式一)

var names = ["alex", "tony", "rain"];
 
for(var i=0;i<names.length;i++){
    console.log(i);
    console.log(names[i]);
}

2.for循环(方式二)

var names = ["alex", "tony", "rain"];

for(var index in names){
    console.log(index);
    console.log(names[index]);
}

3.while循环

while(条件){
    // break;
    // continue;
}

3.异常处理

try {
    //这段代码从上往下运行,其中任何一个语句抛出异常该代码块就结束运行
}
catch (e) {
    // 如果try代码块中抛出了异常,catch代码块中的代码就会被执行。
    //e是一个局部变量,用来指向Error对象或者其他抛出的对象
}
finally {
     //无论try中代码是否有异常抛出(甚至是try代码块中有return语句),finally代码块中始终会被执行。
}

函数

JavaScript中的函数分三类:普通函数、匿名函数、自执行函数。

1.普通函数

function func(){
     ......  
}

2.匿名函数

匿名函数的存在形式多种多样

// 定义函数时并给函数取名,将匿名函数赋值给变量func 
var func = function(arg){
     return "tony";
 }
//  定时器中的执行函数,可以以匿名函数形式存在
setInterval(function(){
    console.log();
},5000),

3.自执行函数

 由两个括号组成,第一个括号内是执行函数,第二个括号内是等待执行的时间。

    (function(arg){
        console.log(arg);
    })('123')
// 123 秒后自动执行函数

作用域(重点)

作用域在许多程序设计语言中非常重要。通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。

1.以函数作为作用域

其他语言(如C,Java,C#):以代码块作为作用域(代码块即为大括号抱起来的部分)

public static void main ()
{
    if(1==1){
         String name = "seven";
    }
     System.out.println(name);
}
// 报错

Python中:以函数作为作用域

情况一:
def func():
    if 1==1:
        name = 'alex'
    print(name)
     
func()
 // 成功

情况二:
def func():
    if 1==1:
        name = 'alex'
print(name)

func()
print(name)
// 报错

JavaScript中:以函数作为作用域

var name='cc';
function func(){
    if(1==1){
        var name = 'dd';
    }
    console.log(name);
}
func()

2.函数的作用域在被调用之前就已经创建

3.函数的作用域存在作用域链,也是在被调用之前创建

 如果出现嵌套函数,则会出现作用域链;作用域在被执行之前就已经被创建,执行时只需要按照作用域链寻找即可。

同名变量的值,取决于离自己自己最近的作用域的值。(根据作用域链从内到外的优先级寻找,如果内层没有就逐步向上找,直到没找到抛出异常。)

示例1:

xo = 'alex';
  
function Func(){
    var xo = "seven";
    function inner(){
        var xo = 'alvin'; 
        console.log(xo);
    }
    inner();
}
Func();
// 输出结果:alvin

示例2:

xo = 'alex';
 
function Func(){
    var xo = "seven";
    function inner(){
 
        console.log(xo);
    }
    return inner;
}
 
var ret = Func();
ret();
// 输出结果: seven

示例三:

xo = 'alex';
 
function Func(){
    var xo = "eirc";
    function inner(){
 
        console.log(xo);
    }
    xo = 'seven';
    return inner;
}
 
var ret = Func();
ret();
// 输出结果: seven

上述代码和示例一的目的相同,也是强调在函数被调用之前作用域链已经存在:

  • 全局作用域 -> Func函数作用域 -> inner函数作用域

不同的时,在执行【var ret = Func();】时,Func作用域中的xo变量的值已经由 “eric” 被重置为 “seven”,所以之后再执行【ret();】时,就只能找到“seven”。

示例四:

xo = 'alex';
function Bar(){
    console.log(xo);
}
 
function Func(){
    var xo = "seven";
     
    return Bar;
}
 
var ret = Func();
ret();
// 输出结果: alex

上述代码,在函数被执行之前已经创建了两条作用域链:

  • 全局作用域 -> Bar函数作用域
  • 全局作用域 -> Func函数作用域

当执行【ret();】时,ret代指的Bar函数,而Bar函数的作用域链已经存在:全局作用域 -> Bar函数作用域,所以,执行时会根据已经存在的作用域链去寻找。

4.函数内局部变量提前声明

 编译阶段生成作用域链,同时找到所有局部变量,执行var声明操作,但并没有赋值。

在JavaScript中如果不创建变量,直接去使用,则报错:

console.log(xxoo);
// 报错:Uncaught ReferenceError: xxoo is not defined

JavaScript中如果创建值而不赋值,则该值为 undefined,如:

var xxoo;
console.log(xxoo);
// 输出:undefined

在函数内如果这么写:

function Foo(){
    console.log(xo);
    var xo = 'seven';
}
 // 解释过程中: var xo;
Foo();
// 输出:undefined

上述代码,不报错而是输出 undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于上述实例中,函数在“预编译”时,已经执行了var xo;所以上述代码中输出的是undefined

JavaScript面向对象

定义类和实例化示例:

function Foo(n){
        this.name = n;
        this.sayName = function(){
            console.log(this.name);
        }
}

var obj = new Foo("we");
  • Foo是类名
  • this代指对象,相当于Python中的self
  • 创建对象需要用new关键字,区别于函数调用

以上代码可以发现,从外壳来看,类与函数长得很像,它与函数的形式区别在于:1.this的使用2.实例化时的new关键字

在Python中,类实例化若干个对象后,每个对象内存中包含变量,但不包含方法,方法在类中,我们认为这是合理的。然而JavaScript不一样,每个对象中都存在相同的方法,这样浪费内存,不合理。

解决办法是:将方法写在prototype原型中

Foo的原型:
        Foo.prototype = {
            "sayName":function(){
                console.log(this.name);
            }
        }

当创建对象并调用方法时,如果在类中没有找到就会去原型中去寻找。将所有方法写在原型中,就达到了节省内存的目的。

JavaScript词法分析

JS代码执行前有一个类似编译的过程即词法分析(AO分析:active object),词法分析主要有三个步骤:

  1. 分析形式参数;

  2. 分析局部变量;

  3. 分析函数声明表达式;

在这里你可能会有问题:已经明白了作用域为什么还要看词法分析呢?词法分析和作用域在JS代码执行过程中各分担什么作用?带着这些疑问先往下看:

分析过程:

1.首先分析形式参数,赋给AO对象

  先看函数的形式参数,添加到AO的属性,并且这个时候值为undefined

  再看接收的实参,如果有,负载之前的undefined

2.局部变量

  检查局部变量,如果遇到不同名变量,添加属性并赋值为undefined

  如果有遇到同名变量,不做任何修改

3.函数声明表达式(优先级最高)

  遇到函数,添加属性,并把函数赋值给这个属性。

  如果该函数和前面的变量同名,则将变量覆盖,因为函数的优先级更高。

先来看示例一

function t1(age) {
    console.log(age);
    var age = 27;
    console.log(age);
    function age() {}
    console.log(age);
}

t1(3);

首先词法分析:

  1.生成AO对象

  2.分析形参,AO.age = undefined;

    发现实参,赋值AO.age = 3;

  3.分析局部变量发现同名变量age,不做任何修改

  4.分析函数age,因为优先级高,所以覆盖,即AO.age = function age(){}

整个过程只有一个变量名,所以词法分析的结果是:AO.age = function age(){}

执行阶段:

  1.第一行输出age,即词法分析的结果function age(){};

  2.遇到 var age = 27 ,给age赋值为27;

  3.输出age为27

  4.输出age为27

执行完毕,感觉懵逼?多此一举? 要记住,词法分析和执行是两个不同的阶段,词法分析在前,执行在后

继续看示例二

function t1(age) {
        var age;
        console.log(age);
        var age = 23;
        console.log(age);
        function age() {}
        console.log(age);
    }

t1(22)    // 与示例一代码不同之处:在第一次输出之前定义了同名变量,但没有赋值

词法分析阶段:

  1.生成AO对象

  2.分析形参,AO.age = undefined;

   分析实参,赋值,AO.age = 22;

  3.分析局部变量age,与前面同名,不做任何修改

  4.分析局部变量age,虽然赋值23,但因为同名,不做任何修改

  5.分析函数age,覆盖AO.age = function age(){}

分析结果:AO.age = function age(){}

执行阶段:

  1.第一次输出时,没有做赋值,所以输出词法分析结果function age(){}

  2.var age = 23;值被修改

  3.第二次输出:23

  4.第三次输出:23

示例三

function t1(age) {
        var age;
        console.log(age);
        function age() {}
        console.log(age);
        var age = 23;
        console.log(age);
    }

t1(22)  // 与实例二代码区别:将函数位置提前

词法分析阶段:

  1.生成AO对象

  2.分析形参,AO.age = undefined;

   分析实参,AO.age = 22;

  3.分析函数age,覆盖:AO.age = function age(){};

  4.分析局部变量age,虽然被赋值,但在词法分析阶段函数优先级高,故age属性仍然为上一步的值

分析结果:AO.age = function age(){}

执行阶段:

  1.第一次输出,为词法分析结果  function age(){}

  2.第二次输出,为词法分析结果  function age(){}

  3.age被重新赋值,age = 23

  4.第三次输出,为23

示例四:

function t1(age) {
    var age;
    console.log(age);
    age = 23;
    console.log(age);
    function age() {
        console.log(age);
    }
    age();
    console.log(age)
}

t1(22)

词法分析阶段:

  1.生成AO对象

  2.分析形式参数AO.age = undefined;

   分析实参AO.age = 23;

  3.分析局部变量var age,不做改变

  4.分析局部变量var age = 23,不做改变

  5.分析函数,AO.age = function age(){console.log(age)}

分析结果:AO.age = function age(){console.log(age)}

执行阶段:

  1.第一次输出:function age(){console.log(age)}

  2.age被重新赋值,age=23

  3.第二次输出:23

  4.执行 "age()" 代码,但是此时age是普通变量而非函数,因此语法错误,会报错

JavaScript的词法分析介绍到这里,现在对词法分析和作用域的作用做一下梳理:

  • 作用域      是程序执行过程所遵守的规则
  • 词法分析  可以理解为程序执行前的初始化,在程序执行的最开始提供变量的初值

猜你喜欢

转载自www.cnblogs.com/V587Chinese/p/9457831.html