博客列表 >JavaScript语法基础1--2018-9-12

JavaScript语法基础1--2018-9-12

晓明的博客
晓明的博客原创
2018年09月12日 17:02:23967浏览
  1. javascript是什么? 有什么用?
        (1).javascript是最流行的,而且是唯一的写"前端脚本"的编程语言;
        (2).前端主要是指:html,css,javascript,以及相关的开发框架,函数库等,共同特征就是指可以直接在浏览器中运行;
        (2).脚本语言的一个基本特征是,可以使用标签,以元素的形式直接嵌入到html文档中,例如<script></script>,<?php ?>;
        (3).javascript功能极其强大,强大到令人发指,前后端几乎通吃,但它最主要的功能仍是实现用户与页面的交互操作;

    ---------------------------------------------------------------------------------------------------

    2. 如果将js代码写到html中?
        (1). 使用标签:<script>,它是双标签
        (2). 可以添加一个属性 type="text/javascript"表示脚本的类型,但考虑到js是前端唯一并且是默认脚本,所以推荐省略掉
        (3). js代码可以写到<script></script>标签中,类似css中页内样式,仅限当前文档使用
        (4). 如果想将js代码应用到更多的html文档中,可以在起始标签<script src="js.js">添加src属性,指定一个外部js文件
            类似css中的外部样式表,实现脚本共享,这也是js最常用的方式,写到独立文件中,不仅可页页共享,还能缓存,提升加载速度.
        (5). <script>中引入外部脚本时,其标签内的js代码将会被忽略.
        (6). 浏览器是可以禁用js的,但这种情况极期罕见,毕竟大多应用是基于js,所以大家在学习时可以忽略用户是否禁用js脚本.

    ---------------------------------------------------------------------------------------------------

    3. js运行结果的三种输出方式
        (1). alert()弹窗 let site = 'php中文网'; alert(site);
        (2). write()方法: document.write(site);
        (3). console.log()控制台: console.log(site);

    4.. 基本语法:
        (1).字面量[值]: 'php中文网';  99; js中,字面量非常强大,将功能发挥到了极致,一定要格外重视
        (2).变量[名称/标识符]: 临时存放数据的地方,就是数据的占位符而已,例如:site = 'php中文网'; price = 99;
        (3).操作符:主要有算术运算(+,-,*,/,=)与逻辑运算(==,!==,===,<,>...)二类,重点是操作符对操作数的类型转换;
            例如: 15 + 20 // 35;    '15' + 20 // 1520,字符串拼接;
        (4).注释: 与php类似, 单行//,多行 /* ... */;
        (5).语句: 用分号';'结束,分号并非必须有,可以省略,近些年越多越多的开发者都开始省略分号,但在学习阶段,为了避免入坑,推荐加上;

    5. js脚本的基本组成部分: 变量和函数,下面咱们先聊聊变量:
       (1). 变量使用ESC6标准的: let声明, 函数使用 function 声明;
       (2). 传统的使用var声明,不支持块作用域,并且允许重复声明,let完美的解决以上问题,推荐使用;
       (3). 什么是块作用域? if(){...}, for(){...},之前js只支持一种函数作用域,这和php是一样的;
       (4). php到目前为止,仍不直接支持块作用域,可以使用其它技术来模拟,使用闭包等;
       (5). var 和 let 声明变量的区别:
            1. let支持块作用域,var不支持
            if (true) {
               var n = 100;     // var声明,块作用域外部可以拿到
               let n = 100;     //let声明,块作用域外部拿不到
           }
           console.log(n);
           2. let不允许重复定义,var允许
           let name = 'peter';
           let name = 'zhu';  // 报错
           var salary = 5800;
           var salary = 6800; // 不报错
       (6). let 变量声明时未初始化,默认值为undefined,undefined是一种特殊的类型,一会再说
       (7). let 变量提升时,会报引用错误,而var会输出undefined,所以推荐必须先声明再初始化,或者声明初始化二合一;
       (8). 以后尽可能使用let来声明和使用变量,大家把var 忘了吧

    6. 变量的数据类型
        (1). js数据类型分为二大类: 原始类型与引用类型; js不允许自定义数据类型,因为js是动态的,可以模拟出任何类型,不需要自定义
        (2). 原始类型有五种: String字符串,Number数值(不区分整数和浮点数),Boolean布尔,Undefined未定义,Null类型
        (3). 引用类型:[Object对象, Array数组]重点掌握,Function函数, Date日期,RegExp正则, 包装对象...
        (4). 类型检测: typeof ,只能检测出: 原始类型与函数,其它都返回Object,
            typeof 'abc'    // "string"
            typeof 100      // "number"
            typeof true     // "boolean"
            typeof null     // "object" ,正确应该返回:"null",这是历史遗留问题,暂时无解
            typeof undefined    // "undefined"
            typeof [1,2,3]      // "object"
            typeof {x:1,y:2}    // "object"
            typeof function f1(){}  // "function"

            对于引用类型,应该使用 instanceof

            let o = {x:1,y:2}
            o instanceof Object     // true

            instanceof 检测数组类型是会有问题:
            [1,2,3] instanceof Array    // true
            [1,2,3] instanceof Object   // true,因为数组也是对象,返回true也应该是对的
            正确方法应该是使用Array的isArray()方法
            Array.isArray([1,2,3])      // true
            Array.isArray({x:1,y:3})    // false
            Array是数组对象的构造函数,一会再说

    --------------------------------------------------------------------------------------------------

    ---------------------------------------------------------------------------------------------------

    7. 函数:
        在学习之前,咱们先学点其它的玩意:
        现在跟着我大写朗读三遍: "js中,一切皆对象"
        只是牢记这句话,后面的课程,你才会搞明白,否则从根上就把你干蒙逼了~~~


        (1).函数是js中的一等公民,不仅是代码执行的基本单元,也是创建其它成员的基本类型;
        (2).函数按功能分为二大类: 普通函数,构造函数;
        (3).按创建方式分为: 函数声明,函数表达式,匿名函数,自执行函数;
        (4).函数声明自动提前:因为函数如此重要,所以函数声明会自动提升到代码最前面,不论在脚本的什么地方声明,都可以直接使用;
        (5).函数调用必须使用函数名加上一对圆括号;
        (6).函数中可以使用return 返回结果,如果没有return 语句,函数执行完毕,会返回 undefined ;
            function f1() {}
            f1()    // undefined
            function f2(){return 'php.cn'}
            f2()    // "php.cn"
        (7).每次执行函数,都会自动创建一个函数作用域,与外部临时隔离,函数外部成员在函数作用域内可见,反之则不行;
            let m = 100;        // 该变量声明在函数外部,全局范围内可见
            function f3() {
                return m +50;   //函数外声明的变量全局可见
            }
            f3()    // 150

            function f4(){
                let n = 20; //函数内声明的变量,外部不可见
            }
            m +n    // n 未定义,出错
        (8).函数表达式
            表达式通常会返回一个确定的值,所以可以直接将表达式用到需要值的地方
            let f5 = function (){ return 200; }
            150 + f5()      // 350, f5()可直接看到一个值,内容就是调用f5()函数的结果
        (9).匿名函数:主要用做函数的参数
            [1,2,3,4].filter(function(item,index,array){return item>2;})
        (10).自执行函数:声明完直接运行,不需要调用
            (function(a,b){return a+b;})(20,40)     // 60

      (11)函数的参数问题:
        1. js根本不在乎函数有没有参数,以及参数有多少,是什么类型;
        2. 因为在内部是使用一个数组来接收这些参数,并使用对象 arguments 来访问这个数组
        3. 因此函数中的参数只是一个实际参数的占位符而已,仅起提示作用,所以也叫: "命名参数"
        4. 命名参数仅提供了访问便利,并非必要;
        5. arguments对象, 可以像使用数组一个使用它,例如:arguments[1],但它并不是Array对象的实例;
        6. arguments.length 属性中保存着参数的数量
        7. js中没有函数签名,不存在函数重载(相同的签名,不同的实现)
        7. 但是js可以用动态参数来模拟重载: 案例:根据参数不同,执行不同的操作
            //声明
            function add() {
                var num = arguments.length
                switch (num) {
                    case 0:
                        return '至少要有一个参数'
                        break
                    case 1:
                        return arguments[0]
                        break
                    case 2:
                        return arguments [0]+arguments[1]
                        break
                    case 3:
                        return arguments[0]+arguments[1]+arguments[2]
                        break
                    default:
                        return '参数过多'
                }
            }

            //调用
            add() // '至少要有一个参数'
            add(100) // 100
            add(100,200)  // 300
            add(100,200,300) // 600
            add(100,200,300,400) // '参数过多'


    ---------------------------------------------------------------------------------------------------

    8. 数组 Array


        1. Array 是仅次于 Object 外使用频率最高的引用类型;
        2. Array 是有序列表,每一个数组元素可以保存任何类型的数据;
        3. Array 的长度是可以动态调整的,自动增长;
        4. 与Object类似,创建Array数组也有二种式: 实例化构造函数Array, 字面量

            (1). 构造函数Array
            var arr = new Array()  //实例化Array(),创建空数组
            var arr = new Array(3) // 创建的新数组有三个预置元素,默认值都是undefined
            var arr = new Array(3,5,'a') //一个或一个以上非数值元素,就是创建实际的内容而非长度
            var arr = Array([1,2,3],'php','html') //可省略new,可传入数组等多种类型给构造函数

            (2). 字面量
            var arr = ['html','css','javascript']; //字面量
            var arr = []; // 空数组

            无论使用哪一种方式,都会有二个默认的属性:
            1. length: 数组元素的数量
            2. __proto__:
        5. length 属性的特殊用途:
            (1). Array.length : 是可读可写的,可人为设置,实现数组元素的移除与添加;
            (2). Array.length : 它的值始终比元素最大索引大1,可以用作永远指向下一个元素的索引;
            (3). 添加元素
                var arr = []  // 空数组
                arr[arr.length] = 100  // arr.length = 0,等价于arr[0] = 100
                arr[arr.length] = 200
                arr[arr.length] = 300
            (4). 删除元素
                var arr = ['html','css','javascript','jquery','vue.js']
                arr.length   // 当前数组长度: 5 ,即有5个元素
                arr[arr.length-1]   // 获取最后一个元素的值: 'vue.js'
                arr.length -= 1    // 将数组长度减1, 即当前数组长度更新为: 4
                arr[arr.length-1]  // 获取最后一个元素的值: 'jquery'
        6. 创建新数组
            (1):基于当前数组中的所有项,创建一个新数组: concat()
                var arr = [1,2,3]
                arr.concat(4,5)     //  
                arr.concat([6,7,8]) // 接受数组参数,这个数组会拆开,将每一个元素并入原数组中:[1, 2, 3, 6, 7, 8]
            (2).基于数组的开始与结束的位置来创建: slice() 单词本意: 切开
                slice(起始索引[,结束索引]),如省略结束索引,默认为后面全部数据
                var arr = [10,20,30,40,50]
                arr.slice(2)        // 从索引2开始,获取后面全部内容: [30, 40, 50]
                arr.slice(1,4)      // 从索引1开始,到索引4结束(不含索引4): [20, 30, 40]
            (3).向数组中间插入数据: splice(), 功能主要是: [删除,插入,替换]
                参数说明: splice(start,length,value...)
                1). 删除
                arr.splice(起始,删除数)
                var arr = [10,20,30,40,50]
                arr.splice(0,2)     // 从头部0,开始删除2个,返回删除的元素: [10, 20]

                2). 插入
                arr.splice(起始,0,要插入项)
                arr.splice(1,0,88,99) //第二个参数0,表示插入,插入的数据是第三个参数
                //本例是从第二个元素起,插入二个新元素:88,99:
                arr     // 查看当前数组: [30, 88, 99, 40, 50]

                3). 替换
                arr.splice(起始,删除数,要插入项)//第二个参数1,表示替换,
                arr.splice(2,1,'dog','cat')     // 返回删除项: 99
                arr     // 查看数组: [30, 88, "dog", "cat", 40, 50]

              7. 栈方法
           (1).数组可以模拟栈操作
           (2).栈是一种LIFO(Last_In_First_Out)'后进先出'的数据结构,插入与删除只能是栈顶(一端)进行
           (3).push()入栈, pop()出栈
           (4).举例
               var arr = []     // 创建空数组
               arr.push(10,20)  // 将数组看成栈,入栈二个元素,10先入,20后入,返回数组长度:2
               arr              // 查看当前数组: (2) [10, 20]
               arr.length       // 查看当前数组长度: 2
               arr.push([1,2])  // 入栈一个数组元素,返回长度: 3
               arr              // 查看数组: (3) [10, 20, (2) [1, 2]
               arr.pop()        // 出栈(栈顶元素出栈):  (2) [1, 2]
               arr.pop()        // 继续出栈: 20

           8. 队列方法
           (1).与栈方法相对的是队方法:FIFO(First_In_First_Out):先进先进
           (2).因为栈方法:push()可以从数组未端添加元素,所以只需要一个方法可以从前端获取元素即可
           (3).从数组前端获取元素的方法就是:shift(),并自动将数组长度减1;
           (4):push() + shift() 实现队操作:尾进头出
               var arr = [10,20,30]
               arr.push(40)     // push()尾部入队: 40
               arr.length       // 此时数组长度是: 4
               arr              // 查看队列: (4) [10, 20, 30, 40]
               arr.shift()      // shift()从前端(头部出队),返回出队元素: 10,长度自动减1
           arr.length           // 当前数组长度是: 3
           (5):unshift(),可以在数组前添加任意数组的元素,并更新数组长度,与栈方法pop()配合实现队操作
           (6):unshift() + pop() 实现队操作:头进尾出
               var arr = [10,20,30]
               arr.unshift(3,5)     // unshift()入队操作: 头部添加二个新元素,并自动更新长度
               arr.length           // 新长度: 5
               arr                  // [3,5,10,20,30]
               arr.pop()            // pop()出队操作: 返回出队元素: 30,并更新长度
               arr.length           // 新长度: 4

     9. 重排序方法
            (1).反转: reverse()
            var arr = [1,2,3,4,5]
            arr.reverse()       // 数组元素翻转:(5) [5, 4, 3, 2, 1]

            (2).sort()更加的灵活
            var arr = [10,4,22,8,2]
            arr.sort()      // [10, 2, 22, 4, 8]:显然错误,因为sort()默认将元素视为字符串,'10'显然是小'2'
            //解决方案: sort()可接受一个回调参数,在回调函数中进行比较运算完成正确排序
            function compare(val1,val2){
                if (val1 < val2) {
                    return -1
                } else if (val1 > val2) {
                    return 1
                } else {
                    return 0
                }
            }

            ***对于数值型元素的比较,这个回调函数可以进行简化:
            function compare(val1,val2) {
                return val - val2  //升序
            }

            arr.sort(compare)       // 输出正确结果:[2, 4, 8, 10, 22]
            //如果改为降序排列,只需要改变回调中的返回值即可
            function compare(val1, val2) {
                return val2-val1   //降序: 用第二个参数减去第一个参数即可
            }

            arr.sort(compare)   // 降序: [22, 10, 8, 4, 2]

     10. 位置方法
            (1). indexOf(要查找的项 [,起始位置]): 从头部开始,查找失败返回: -1
            (2). lastIndexOf(要查找的项 [,起始位置]): 从尾部开始,查找失败返回: -1
            (3). 实例:在数组中查找指定元素并返回索引:
                 var arr = [1,2,3,4,5,4,3,2,1]
                 arr.indexOf(4)         // 查找4,返回4在数组中的索引位置: 3
                 arr.indexOf(4,4)       // 传入第二参数,指定从索引4开始查找,返回索引位置: 5
                 arr.lastIndexOf(4)     // 从尾部查找4,返回4第一次出的索引位置: 5
                 arr.lastIndexOf(4,4)   //从尾部查找4,从索引4开始,跳过了5,所以输出索引位置: 3
    11. 迭代方法
            (1). 5个方法都可以接受2个参数:每一顶上运行的回调函数(必选),运行该函数的作用域[可选](影响this的值)
            (2). 这几个方法不会影响到原数组的值
            (3). 五个方法介绍:
                 (1). every():如果每一项运算都返回true,则返回true;
                 (2). some(): 任一项运算返回true,则返回true;
                 (3). filter(): 返回true项组成的新数组;
                 (4). forEach(): 每一项执行给定函数,无返回值;
                 (5). map(): 返回每次执行结果组成的新数组
            (4). 举例:
                 (1). every()
                 var arr = [1,2,3,4,5,6]
                 // 要求每一项都必须大于2,才可以返回true,显示第1,2个元素不符合要求
                 arr.every(function(item,index,array){ return item > 2 })
                 (2). some()
                 // 只要数组元素中有一个元素值大于2,就满足条件并返回true
                 arr.some(function(item,index,array){ return item > 2 })
                 (3). fileter()
                 // 返回数组中元素值大于2的元素,组成的新数组
                 arr.filter(function(item,index,array){ return item > 2 })
                 (4). forEach():注意无返回值,不要使用return ,常用来遍历数组
                 //输出全部的元素值
                 arr.forEach(function(item,index,array){ console.log(item) })
                 //输出元素的索引
                 arr.forEach(function(item,index,array){ console.log(index) })
                 // 输出当前正在遍历的数组元素:注意会把当前数组输出6遍
                 arr.forEach(function(item,index,array){ console.log(array) })


        12. 归并方法
            (1). 本质是数组元素之间的二二计算,并把结果带到下一次的运算中;
            (2). reduce(): 从第一项开始迭代,直到计算出一个最终值;
            (3). reduceRight(): 从最后一项开始迭代,向前遍历直到第一项;
            (4). 都可以接受二个参数: 1迭代的函数,2是可选的归并初始值
            (5). 迭代函数有四个参数: prev前一个,cur当前,index索引,array数组
                var arr = [1,2,3,4,5]
                // 计算:1+2+3+4+5的值
                // 计算过程:
                // 1 + 2 = 3
                // 3 + 3 = 6
                // 6 + 4 = 10
                // 10 + 5 = 15
                arr.reduce(function(prev,cur,index,array){return prev+cur})     // 结果: 15

                //给reduce(callback,init)传入第二参数,计算的初始值: 10
                arr.reduce(function(prev,cur,index,array){return prev+cur},10)  // 结果: 10 + 15 = 25

                // reduceRight()功能与reduce()完全一致,只是计算方向从右边开始
                arr.reduceRight(function(prev,cur,index,array){return prev+cur})    // 15
                arr.reduceRight(function(prev,cur,index,array){return prev+cur},10) // 25

    ---------------------------------------------------------------------------------------------------

    9. Object 类型
        1.创建Object实例:
            (1). 构造函数
             var obj = new Object()
             obj.name = 'Peter'
             obj.age = 29
            (2). 字面量
            var obj = {
                name: 'Peter',
                age: 29
            }
        2. 表达式上下文: 花括号出现在赋值操作右边,就是一个表达式上下文,左花括号就是表达式的开始;
        3. 语句上下文: 花括号出现在语句上下文中,例如 if/while...,则是语句块的开始;
        4. 用字面量创建实例,最后一个属性后不要添加','号;
        5. 属性名可以用字符串: var obj = {'name': 'zhu', 'sex': 'male'}
        6. 可以创建一个只包含默认属性和方法的实例: var obj = {}  // obj只有默认属性和方法,等价于new Object()
        7. 案例,根据参数是否有指定属性,输出对应的内容
        function displayInfo(args) {
            var output = ''

            if (typeof args.name == 'string') {
                output += 'Name: ' + args.name + '\n'
            }

            if (typeof args.age == 'number') {
                output += 'Age: ' + args.age + '\n'
            }

            console.log(output)
        }

        displayInfo({name: '朱老师', age: 30})  // Name: '朱老师' Age: 30
        displayInfo({name: '朱老师'})  //  Name: '朱老师'
        displayInfo({age: 30})  //  Age: 30
        displayInfo({'age': 30})  //  Age: 30
        displayInfo({})   // 空

        可以,无论输入什么,都可以得到正确的结果;
        8. 通常情况下,必选参数使用命名参数比较好,当有多个可选参数时使用对象字面量时行封装会更灵活;

        9. 刚才都是使用的点'.'语法来访问实例中的属性,支持属性名是标识符或字符串,其实也支持方括号;
        10.使用方括号语法与数组类似,但是实例的属性/方法名必须放到引号中: obj['name']
        var obj = {name:'peter', age: 30}
        console.log(obj['name'])
        console.log(obj['age'])
        11.方括号语法还支持变量属性名:
        var a = 'name'
        var obj = {name:'zhu'}
        obj.a // undefined
        obj[a] // 'zhu'

    *******************************************************************************************

    对象的扩展知识:
    一、对象的生成:
        (1).对象字面量
            1. 使用字面量生成对象的三种场景:
                (1): 单例模式(singleton);
                (2): 多值数据(函数的参数与返回值)
                (3): 替代构造函数来生成对象
            2. 场景一:单例模式
                (1).所谓单例:将类的实例对象数量限定为一个;
                (2).类是对象的模板,可以多次实例化,创建多个实例对象;
                (3).如果只需要一个实例对象,但么就没必要去创建类了;
                (4).所以使用字面量直接创建一个单例对象是最方便的啦.
                var obj = {name:'peter', name:30}

            3. 场景二: 多值数据的使用场景[类似于关联数组]
                (1). 给函数传递多个参数
                [传统方式:]
                function getData(x, y, z) {
                    return (x+y+z)
                }
                getData(1,2,3)  // result: 6

                [对象字面量做为函数调用的实参]
                function getData(data) {
                    return (data.x+data.y+data.z)
                }
                getData({x:1, y:2, z:3})  // result: 6

                [对象字面量做为默认参数]
                //如果调用时没有传入实参
                function getData(data) {
                    //函数内修改参数值并不是一个好习惯
                    data = data || {x:1, y:2, z:3}
                    return (data.x+data.y+data.z)
                }
                getData()  // result: 6

                [对象字面量做为函数返回值]
                function func() {
                    return {x:4, y:5, z:6}
                }
                func()  // {x:4, y:5, z:6}

                [扩展知识,返回数组,并实现将数组中元素转为独立变量的技巧]
                function func() {
                    return [4, 5, 6]
                }
                [x,y,z]=func()  // 将数组中的元素转为独立的变量
                x   // x = 4
                y   // y = 5
                z   // z =6

            4. 场景三: 代替构造函数
                (1). 构造函数是用来创建对象的,所以只需要将对象字面量做为函数返回值即可;
                (2). 从语法上看,与返回多值数据基本相同,区别在于执行方式;
                (3). 实例:
                function createObj() {
                    //直接将对象字面量做为返回值
                    return {
                        x: 10,
                        y: 20,
                        z: 30,
                        sum: function () {
                            return this.x + this.y + this.z
                        }
                    }
                }

                var obj = createObj()
                obj.sum()   // 结果: 60
                createObj().sum()   //使用链式调用进行简化

            (2). 构造函数与new表达式
                1. 构造函数是一种必须要通过new表达式调用的特殊函数;
                2. 构造函数的用途是用来创建对象(类的实例化);
                3. 因为类可以被实例化为对象,所以类中必须要有该实例对象的代言人;
                4. 这个特殊的类中对象的代言人,就是伪变量: this
                5. 构造函数基本用法:
                    (1).声明: function MyClass(x, y) {
                                this.x = x
                                this.y = y
                             }
                    (2).调用: var obj = new MyClass(10,20)
                             obj.x  // 10
                             obj.y  // 20
                6. 总结:
                    (1).构造函数本身与普通函数声明形式是相同的;
                    (2).构造函数是通过"new"表达式来调用;
                    (3).new 表达式的值: 新对象的引用
                    (4).new 表过式是通过构造函数内的this引用了新生成的对象

                (一).new 表达式的操作
                    new 操作的完整流程
                    1. new 表达式 首先是新生成一个"操作对象"(可视为一个通用对象,是对象就具备访问属性和调用方法的能力);
                    2. 用这个"操作对象"调用指定的函数(即构造函数);
                    3. 构造函数内部有一个内部指针:this,指向了这个由"new"表达式新生成的操作对象;
                    4. 在构造函数中,可以使用this为当前操作对象添加属性或方法;
                    5. 构造函数执行完成,将会返回该操作对象的引用:this, 做为new 表达式的 "值"
                    6. 即: new 操作 的最终返回值,其实就是构造函数中的: this

                (二).构造函数的调用
                    1. 其实任何函数都可以通过 new 来调用,所以任何函数都可以充当构造函数的角色;
                    2. 但只有一个函数内部使用了this,他才是一个构造函数,可以生成一个新对象;
                    3. 构造函数结尾会隐式一条: return this 语句,返回当前对象的引用;
                    4. js中的构造函数类似于其它语言中的类,但却又比他们难以理解,毕竟new一个函数来生成一个对象比较特殊;
                    5. 而其它语言,都是 new 一个类,而js中没有类的概念,所以构造函数,实际上就起到了"类"的作用;
                    6. 因为构造函数起到了"类"的作用,所以按照惯例,充当构造函数的函数名,首字母应该大写,以示不同;

    ---------------------------------------------------------------------------------------

    八、属性的访问
        1. 属性访问:
            (1).点语法,只能使用标识符: obj.name;
            (2).中括号[],必须使用字符串,可用用字符串字面量,也可以用字符串变量
            var obj = {name:'peter', age:20}
            obj.name    // 'peter'
            obj['age']  // 20
            var p = 'name'
            obj[p]  // 'peter'

            ({x:40,y:50}).x // 40,说明访问属性的是对象的引用
            ({x:40,y:50}).y // 50
            实际开发过程中,可能遇不到直接对字面量对象进行运算,但是在链式调用很方便
        2. 属性设置与访问的规则相同:
            var o = {}
            o.name = 'jack'
            o['age'] = 30

        3. 属性值的更新
            1.将属性表达式写在"="号左侧
            obj.name = 'zhu'    // 如果属性存在则是更新,如果不存在就是创建新属性
            delete obj.name     // 删除对象obj上的属性name
        4.点运算符与中括号运算符的区别
            1. 能使用点运算符"."的场景,一定能使用中括号运算符"[]",反之则不一定;
            2. 访问属性首选点运算符,当"."会产生歧义时,则使用中括号来规避,例如属性名是一个非法标识符
            3. 以下三种情况必须使用中括号:
                (1).使用了非法标识符: 属性名多个单词之间有空格,连接线-或特殊字符$#%.等
                (2).使用了变量属性名: var p = 'name'; obj[p];
                (3).使用了表达式的属性名:
                var obj = {x:10, y:20}
                var m = 5       // 定义变量 m ,初始值为5
                obj[ (m<10)? 'x' : 'y']     // m当前值小于10,返回true,此时输出obj.x的属性值: 10
                var m =13       // 更新m, 使其大于10
                obj[ (m<10)? 'x' : 'y']     // m当前值大于10,返回true,此时输出obj.y的属性值: 20

        5.属性的枚举: for (var key in obj) { console.log(obj.key) }

    *******************************************************************************************

    变量的扩展知识:

    一、变量的声明
        1. 变量可以用来表示某个值,或某个变量;
        2. 变量使用前应该先声明:var m ;
        3. 声明未赋值(初始化); 默认为: undefined;
        4. 对同一个变量可以重复声明;
        推荐语法:
        var a = a || 10;    //已声明则用原值,未声明用默认值
        var a ;     // 已声明未初始化,默认值:undefined
        var a = 40;  // 40  // 初始化40

    --------------------------------------------------------------

    二、变量与引用
        1. 变量分为: 基本类型, 引用类型;
        2. 变量赋值: 值传递, 引用传递;
        3. 基本类型变量也叫值型变量,复制采用值传递,二者是完全独立的;
        4. 引用类型变量与叫引用变量,类似于C语言指针,二者共同指向同一对象;

        基本类型:
        var a = 123;
        var b = a;  // a 值 传递 给 b
        b++ // b 自增1
        b   // b=124
        a   // a无变化

        引用类型
        var a = {x: 10, y: 20};
        b = a;  // 将对象a复制到b中,对象是引用赋值,a和b指向同一个对象
        b.x     // 10
        b.x = 30;  // 将b.x 属性重新设置为30
        a.x         // a.x 属性同步被更新为30
        a = {a: 88, b: 99}  // 改变a变量的值,使其引用另一个对象
        a   // 查看对象a, 它的值已发生变化: {a: 88, b: 99}
        b   // 查看b,发现仍是原来的对象内容:{x:30,y:20}
        此时原对象的引用保存在变量b中,这与证明了对象变量的确是引用类型


        函数的参数
        1. 函数传参是使用值传递方式进行;
        2. 经典案例:交换二个变量的值

        var a = 100;
        var b = 200;
        //swap()实现交换
        function swap(a,b) {
            return [b, a];
        }

        [a,b] = swap(a,b);  //执行交换操作

        a   // a等于200
        b   // b等于100

        字符串与引用
        1. 字符串是基本类型,基本类型的值都是不可改变的;
        2. 字符串内部仍是按引用方式来实现的,但表现为值传递;

        引用总结
        1. 赋值应该是从右向左看: var a = {x:1,y:2};
        2. 应该是先有一个对象{x:1,y:2},然后再声明一个标识符a来引用它;
        3. 所以无论是否存在变量a, 对象{}都是客观存在的;
        4. 因此,即使变量a指向了其它对象: var a = {m:5,n:6},而对象{x:1,y:2}仍存在
        5. 当对象{x:1,y:2}没有任何引用指向时,系统将启动回收机制销毁该对象

    --------------------------------------------------------------

    二、变量与属性

        (1)全局变量与全局对象之间的关系:
            1. 在js中一切皆对象,所有变量就是属性,属性就是变量;
            2. 变量或属性名的用途: 获取值[右值] 或者 被赋值[左值];
            3. 根据作用域: '全局变量' 和 '局部变量(函数参数)';
            4. 全局变量: 函数之外声明的变量;
            5. 局部变量: 函数内部声明的变量;
            6. 全局变量(包括全局函数名)是"全局对象"的属性;
            7. 全局对象: 程序一旦开始运行,就会被自动创建;
            8. 证明: 全局变量 === 全局对象的属性
            var x = 'foo'   // 声明全局变量并初始化'foo'
            x   // 以全局变量方式访问 'foo'
            this    // 查看当前全局对象, 浏览器中的js是: window
            this.x  // 以对象属性方式访问全局变量x

            9. 如果将全局对象,赋值给一个全局变量,做为该对象的引用的话
            var global = this   // 声明全局变量global, 用全局对象this初始化

            10.这时,全局变量,他具有双重身份: 1. 全局变量; 2. 全局对象this的引用
            这就是传说中的: 自己引用自己
            'global' in this    // 返回: true, 说明全局变量global的确是this(全局对象)的属性
            global  // 返回 window对象, 说明 global 本身的确是全局对象

            11. 这种自引用关系,在js中非常常用,例如在客 户端javascript中,就提供了一个引用了全局对象的
            全局变量:window, 这个window 就类似于我们上面创建的全局变量global的作用.
            12. 全局对象和全局变量的生命周期: 从脚本开始运行直到脚本结束(关闭当前页面).

        (2)局部变量与对象之间的关系
            1. 函数内部声明的变量,以及函数的参数都是局部变量;
            2. 与全局变量一样,局部变量也会被隐式的声明为某个对象的属性;
            3. 这个隐式的对象就是: call;
            4. 局部变量的生命周期: 通常从函数调用直到函数执行结束返回调用者;
            5. 可以通过一种称作:"闭包"的技术,打破这个约束,使局部变量离开函数仍可以使用.

    --------------------------------------------------------------

    四、变量的查找
        1. 无论是左值,还是右值操作,都会触发对变量名称的查询操作;
        2. 在最外层代码(函数之外)的变量查找,实际上查找的是全局对象的属性(全局变量与全局函数);
        3. 在函数内部的变量名查找,因为在函数内部可以使用全局变量,所以首先是查找call对象的属性,
            如果没找到,再到全局对象属性上查找,是由内到外的顺序进行: call对象 --> global对象

    --------------------------------------------------------------

    五、对变量或属性是否存在的检测
        (1):对变量是否存在进行检测(以全局变量为例):
            1. 常用语法: var a = a || 10; // a有值由用原值,否则使用默认值:10
            2. 变量复制: var a; var b = a || 10;  // 原理同上
            3. 变量复制: var a; var b = a != undefined ? a : 10; // 判断a是否有值
            4. 利用js没有块级作用域特征,使用typeof 进行再精确的判断
            var a
            if (typeof a != undefined) {
                var b = a
            } else {
                var b = 10
            }
            b++     //因为没有块级作用域,所以这里可以使用变量 b
            5.以上都必须先对a进行声明,其实可以用 'in' 判断是否是某对象的属性来判断:in this
            if ( 'm' in this) {var n = m} else {var n = 20} //然后就可以使用变量n了

        (2):对属性是否存在进行检测:
            1. 属性存在时,与变量一样,返回它的值;
            2. 当属性不存在时,与变量的返回完全不同;
            3. 访问不存在的变量会返回错误,而属性只会返回undefined

            age     // 返回错误
            this.age    // undefined

    ---------------------------------------------------------------------------------------

    js中的流程控制:
    与其它编程语言一样,也有分支与循环二大类,语法与php基本一致
    1. 判断
        (1).单分支: if () {}
        (2).双分支: if(){} else {}
        (3).多分支: if(){} else if () {} else {}
        (4).switch: switch(n) {
                case 1:
                    break;
                ...
                default:
                break;
            }
    2. 循环
        (1). for(let i=0; i<n; i++) {...}
        (2). while(){...}   /  do {...} while()
        (3). for in:   for (let var in obj)


声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议