JavaScript学习笔记(二)

目录

一、数组

1.1 数组的概念

1.2 创建数组

1.利用new创建数组

2.利用数组字面量创建数组

1.3 获取数组中的元素

数组的索引

1.4 遍历数组

1.5 获取数组长度

⭐数组求和及平均值

⭐求数组最大值

⭐数组转换为分割字符串

1.6 数组中新增元素

1. 通过修改length长度新增数组元素

2.通过修改数组索引新增数组元素

⭐数组新增元素

⭐筛选数组

1.7 数组案例

⭐删除指定数组元素

⭐翻转数组

⭐数组排序(冒泡排序)

二、函数

2.1 函数的概念

2.2 函数的使用

1.声明函数

2.调用函数 

2.3 函数的封装

2.4 函数的参数 

1.形参(声明函数时)

2.实参(调用函数时)

3.形参和实参的执行过程

⭐利用函数求任意两个数的和

⭐利用函数求任意两个数之间的和

4.函数形参和实参个数不匹配的问题

5.小结 

2.5 函数的返回值

1.return语句

⭐求任意两个数的和 

⭐利用函数求任意两个数的最大值(函数值)

⭐求数组中的最大值(函数版)

2.函数没有 return 则返回 undefined

3.break,continue,return的区别

2.6 arguments的使用 

⭐利用函数求任意个数的最大值

⭐利用函数封装方式翻转任意一个数组

⭐利用函数封装方式对数组排序--冒泡排序

⭐利用函数封装实现判断闰年

⭐函数可以调用另外一个函数

⭐用户输入年份,输出当前年份2月份的天数

2.7 函数表达式声明函数的方式

三、JavaScript作用域

3.1 作用域概述

1.全局作用域

2.局部作用域(函数作用域)

3.2 变量的作用域

1.全局变量

2.局部变量

3.全局变量和局部变量的区别

3.3 JavaScript中没有块级作用域

3.4 作用域链

 ⭐作用域链案例

四、JavaScript预解析 

4.1 预解析(面试常问)

1.预解析:

2.代码执行:

预解析案例

案例1

案例2

案例3

案例4(面试常见混淆题)

五、对象 

5.1 对象

5.2 为什么需要对象

5.3 创建对象的三种方式

1.利用字面量创建对象

对象的调用

变量、属性、函数、方法总结 

2. 利用new object创建对象

3.利用构造函数创建对象

4.构造函数和对象的区别

5.new关键字执行过程

6.遍历对象属性

5.4 小结

六、JavaScript内置对象

6.1 内置对象

6.2 查文档

查阅步骤:

6.3 Math

⭐封装自己的数学对象

1.abs,floor,ceil,round方法 

2.随机数方法 random( )

 ⭐猜数字游戏

6.4 日期对象

 3.日期格式化

 ⭐要求封装一个函数返回当前的时分秒 格式 08:08:08

 4. 获取日期的总的毫秒形式

 ⭐京东倒计时案例

七、数组对象的创建 

7.1 数组对象的创建

 7.2 检测是否为数组

 ⭐翻转数组案例  使用判断数组事先判断

 7.3 添加删除数组元素的方法

1.添加元素push

 2.添加元素unshift

3.删除元素pop 

 4.删除元素shift

⭐⭐筛选数组

7.4 数组排序 

 7.5 数组索引的方法

1.indexOf 获取索引 

 2.lastIndexOf

 ⭐⭐数组去重(重点案例)

7.6 数组转化为字符串

1.toString()

2.join('分隔符') 

3.数组中常用其他内置对象 ​

八、字符串类型 

8.1 基本包装类型

8.2 字符串的不可变

8.3 根据字符返回位置

⭐返回字符位置 (经典面试题)

 8.4 根据位置返回字符(重点)

 1.charAt(index)

2.charCodeAt(index)

 3. str[index]

8.5 判断对象中是否有某个属性 

 ⭐判断一个字符串,'abcoefoxyozzopp' 中出现次数最多的字符,并统计其次数

 8.6 字符串操作方法(重点)

1.concat('字符串1','字符串2'....)

2.substr('截取的起始位置', '截取几个字符'); 

8.7 替换字符replace

⭐有一个字符串 'abcoefoxyozzopp'  要求把里面所有的 o 替换为 *

8.8 字符转换为数组 split('分隔符') 

九、JavaScript中的简单数据类型和复杂数据类型

9.1 简单类型和复杂类型

 9.2 堆和栈

9.3 简单类型的内存分配

9.4  简单类型传参

9.5  复杂类型传参


一、数组

1.1 数组的概念

数组是一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素

数组是一种将一组数据存储在单个变量名下的优雅方式。

1.2 创建数组

1.利用new创建数组

var 数组名 = new Array();

var arr  =  new  Array();    //创建一个新的空数组

注意:

  • 这种方式暂且了解,等学完对象再看

  • 注意 Array(),A要大写

2.利用数组字面量创建数组

// 使用数组字面量的方式创建空的数组
        var 数组名 = [];
        // 使用数组字面量方式创建带初始值的数组
        var arr1 = [1, 2, 'pink老师', true];

注意:

  • 数组里面可以放任意的数据类型
  • 数组里面的数据用,分隔
  • 数组里面的数据称为数组元素
  • 这种方式是使用最多的方式 

1.3 获取数组中的元素

数组的索引

索引(下标):用来访问数组元素的序号(数组下标从0开始)。

格式:数组名[索引号]

 var arr2 = ['迪丽热巴', '古丽扎娜', '佟丽丫丫'];
        console.log(arr2[0]);
        console.log(arr2[1]);
        console.log(arr2[2]);
        console.log(arr2[3]); // 因为没有这个数组元素 所以输出的结果是 undefined

1.4 遍历数组

遍历:把数组中每个元素从头到尾访问一次。

<script>
        // 遍历数组:就是把数组的元素从头到尾访问一次
        var arr = ['red', 'green', 'blue'];
        for (var i = 0; i < 3; i++) {
            console.log(arr[i]);
        }
        // 1. 因为我们的数组索引号从0开始 ,所以 i 必须从 0开始  i < 3
        // 2. 输出的时候 arr[i]  i 计数器当索引号来用
    </script>

1.5 获取数组长度

使用“数组名.length”可以访问数组元素的数量(数组长度)

 <script>
        // 数组长度 数组名.length
        var arr = ['关羽', '张飞', '马超', '赵云', '黄忠', '刘备', '姜维', 'pink'];
        for (var i = 0; i < 7; i++) {
            console.log(arr[i]);
        }
        console.log(arr.length);
        for (var i = 0; i < arr.length; i++) {
            console.log(arr[i]);
        }
        // 1. 数组的长度是元素个数  不要跟索引号混淆
        // 2. arr.length 动态监测数组元素的个数
    </script>
  •   for 里面的 i 是计数器,当索引号使用,arr[i]是数组元素,第i个数组元素。

⭐数组求和及平均值

分析:

  • 声明一个求和变量 sum。
  • 遍历这个数组,把里面每个数组元素加到 sum 里面。
  • 用求和变量 sum 除以数组的长度就可以得到数组的平均值。
<script>
        var array = [2,6,1,7,4];
        var sum = 0;
        var avg = 0;
        for (var i = 0; i < array.length; i++){
            sum += array[i];   //我们加的是数组元素,不是计数器
        }
        avg = sum / array.length;
        console.log(sum,avg);
    </script>

⭐求数组最大值

 <script>
        var arr = [2,6,1,77,52,25,7];
        var max =arr[0];
        for (var i = 1; i < arr.length; i++){
            if (arr[i] > max){
               max = arr[i];
            }
        }
        console.log(max);
    </script>

⭐数组转换为分割字符串

要求:将数组['red','green','blue','pink']转换为字符串,并用|或其他分隔符分割

 <script>
        //需要一个新变量用于存放转换完的字符串str
        //遍历原来的数组,分别把里面的数据取出来,加到字符串里面
        //同时在后面多加一个分隔符
        var arr = ['red','blue','green','pink'];
        var str = '';
        var sep = '|';
        for (var i = 0; i < arr.length; i++){
            str += arr[i] + sep ;
        }
        console.log(str);
        alert(str);
    </script>

1.6 数组中新增元素

可以通过修改length长度以及索引和增加数组元素。

1. 通过修改length长度新增数组元素

  • 可以通过修改length长度来实现数组扩容的目的
  • length属性是可读写的

2.通过修改数组索引新增数组元素

  • 可以通过修改数组索引的方式追加数组元素
  • 不能直接给数组名赋值,否则会覆盖掉以前的数据 
<script>
        // 1. 新增数组元素 修改length长度 
        var arr = ['red', 'green', 'blue'];
        console.log(arr.length);
        arr.length = 5; // 把我们数组的长度修改为了 5  里面应该有5个元素 
        console.log(arr);
        console.log(arr[3]); // undefined
        console.log(arr[4]); // undefined

        // 2. 新增数组元素 修改索引号 追加数组元素
        var arr1 = ['red', 'green', 'blue'];
        arr1[3] = 'pink';
        console.log(arr1);
        arr1[4] = 'hotpink';
        console.log(arr1);
        arr1[0] = 'yellow'; // 这里是替换原来的数组元素
        console.log(arr1);
        arr1 = '有点意思';
        console.log(arr1); // 不要直接给 数组名赋值 否则里面的数组元素都没有了
    </script>

 ⭐数组新增元素

新建一个数组,里面存放10个整数(1-10)

分析:

  • 使用循环来追加数组
  • 声明一个空数组arr
  • 循环中的计数器i 可以作为数组元素存入
  • 由于数组的索引号是从0开始的,因此计数器从0开始更合适,存入的数据元素要加+1
  var arr = [];
        for (var i = 0; i < 100; i++) {
            // arr = i; 不要直接给数组名赋值 否则以前的元素都没了
            arr[i] = i + 1;
        }
        console.log(arr);

⭐筛选数组

要求:将数组[2,0,6,1,77,0,52,0,25,7]中大于等于10的元素选出来,放入新数组

 <script>
        //方法1
        var arr = [2,0,6,1,77,0,52,0,25,7];
        var newarr = [];
        var j = 0;
        for (var i = 0; i < arr.length; i++){
            if (arr[i] > 10){
                //新数组的索引号应该从0开始存
                newarr[j] = arr[i];
                j++;
            }
        }
        console.log(newarr);
        //方法2
        var arr = [2,0,6,1,77,0,52,0,25,7];
        var newarr = [];
        // 刚开始的newarr.length为0,length会自动检测元素的变化
        for (var i = 0; i < arr.length; i++){
            if (arr[i] > 10){
                //新数组的索引号应该从0开始存,依次递增
                newarr[newarr.length] = arr[i];
                j++;
            }
        }
        console.log(newarr);

    </script>

1.7 数组案例

⭐删除指定数组元素

要求:将数组[2, 0, 6, 1, 77, 0, 52, 0, 25, 7]中的 0 去掉后,形成一个不包含 0 的新数组。

<script>
        // 将数组[2, 0, 6, 1, 77, 0, 52, 0, 25, 7]中的 0 去掉后,形成一个不包含 0 的新数组。
        // 1、需要一个新数组用于存放筛选之后的数据。
        // 2、遍历原来的数组, 把不是 0 的数据添加到新数组里面(此时要注意采用数组名 + 索引的格式接收数据)。
        // 3、新数组里面的个数, 用 length 不断累加。
       var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
       var newarr = [];
       for (var i = 0; i< arr.length; i++){
           if (arr[i] != 0){
               newarr[newarr.length] = arr[i];
           }
       }
       console.log(newarr);
    </script>

 ⭐翻转数组

将数组 ['red', 'green', 'blue', 'pink', 'purple'] 的内容反过来存放

 <script>
        // 将数组 ['red', 'green', 'blue', 'pink', 'purple'] 的内容反过来存放
        // 1、声明一个新数组 newArr
        // 2、把旧数组索引号第4个取过来(arr.length - 1),给新数组索引号第0个元素 (newArr.length)
        // 3、我们采取 递减的方式  i--
      var arr = ['red', 'green', 'blue', 'pink', 'purple'];
      var newarr = [];
      for (var i = arr.length-1; i >= 0; i--){
          newarr[newarr.length] = arr[i];
      }
      console.log(newarr);
    </script>

 ⭐数组排序(冒泡排序)

冒泡排序:是一种算法,把一系列的数据按照一定的顺序进行排列的显示(从小到大或从大到小)

 <script>
        var arr = [5,4,3,2,1];
        for (var i = 0; i <= arr.length-1; i++){ //外层循环管趟数
            for (var j = 0; j < arr.length-i-1;j++){ //里层循环管每趟的交换次数
                 //内部交换两个变量的值 前一个和后面一个数组元素相比较
                 if (arr[j] > arr[j+1]){
                     var temp = arr[j];
                     arr[j] = arr[j+1];
                     arr[j+1] = temp;
                 }
            }
        }
        console.log(arr);
    </script>

二、函数

2.1 函数的概念

函数计算被封装了一段可以被重复执行调用的代码块。

目的:让大量代码重复使用。

2.2 函数的使用

函数在使用时分为两步:声明函数和调用函数。

1.声明函数

function 函数名() {
         函数体
}
  • function 声明函数的关键字 全部小写
  • 函数是做某件事情,函数名一般是动词
  • 函数不调用自己不执行(只声明函数不调用,函数不执行)

2.调用函数 

函数名();
  • 一定不要忘记小括号

2.3 函数的封装

函数的封装是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口。

⭐利用函数计算1-100之间的累加和

 <script>
        //利用函数求1-100之间累加和
        function getsum(){
            var sum = 0;
            for (var i = 1; i <= 100; i++){
                sum +=i;
            }
            console.log(sum);
        }
        getsum();
    </script>

2.4 函数的参数 

我们可以利用函数的参数实现函数重复不同的代码。

1.形参(声明函数时)

function 函数名(形参1,形参2...) { // 在声明函数的小括号里面是 形参 (形式上的参数)

2.实参(调用函数时)

函数名(实参1,实参2...); // 在函数调用的小括号里面是实参(实际的参数)

3.形参和实参的执行过程

  function cook(aru) { // 形参是接受实参的  aru = '酸辣土豆丝' 形参类似于一个变量
            console.log(aru);

        }
        cook('酸辣土豆丝');
        cook('大肘子');

 函数的参数可以有也可以没有,个数不限

⭐利用函数求任意两个数的和

⭐利用函数求任意两个数之间的和

<script>
        //1.利用函数求任意两个数的和
        function getsum(num1,num2){
            getsum = num1 + num2 ;
            console.log(getsum);
        }
        getsum(1,2);
        //2.利用函数求任意两个数之间的和(如求1-100之间数的和)
        function getsum1(num3,num4){
            var sum1=0;
            for (var i = num3; i <= num4; i++){
                sum1 += i; 
            }
            console.log(parseInt(sum1));
        }
        getsum1(1,10);
        
    </script>

注意点:

  • 多个参数之间用逗号隔开
  • 形参可以看做不用声明的变量
  • 注意有些变量一定要初始化

4.函数形参和实参个数不匹配的问题

<script>
        //函数形参实参个数匹配
        function getsum(num1,num2){
            console.log(num1 + num2);
        }
        //1.如果实参的个数和形参的个数一致,则正常输出结果
        getsum(1,2);
        //2.如果实参的个数多于形参的个数  会取到形参的个数
        getsum(1,2,3);
        //3.如果实参的个数小于形参的个数
        //形参可以看做是不用声明的变量 num2是一个变量但是没有接受值
        getsum(1);
    </script>

5.小结 

  • 函数可以带参数也可以不带参数
  • 声明函数的时候,函数名括号里面的是形参,形参的默认值为 undefined
  • 调用函数的时候,函数名括号里面的是实参
  • 多个参数中间用逗号分隔
  • 形参的个数可以和实参个数不匹配,但是结果不可预计,我们尽量要匹配

2.5 函数的返回值

1.return语句

有的时候,我们会希望函数将值返回给调用者,此时通过使用return语句就可以实现

 function 函数名() {

            return 需要返回的结果;

}

函数名();

  • 我们函数只是实现某种功能,最终的结果需要返回给函数的调用者函数名() 通过return 实现的
  • 只要函数遇到return 就把后面的结果 返回给函数的调用者  函数名() = return后面的结果

 注意事项:

  • return后面的代码不会被执行
  • return只能返回一个值,且返回的结果是最后一个值
  • 若要返回多个值,可以采用数组
 function getResult(num1, num2) {
            return [num1 + num2, num1 - num2, num1 * num2, num1 / num2];
        }
        var re = getResult(1, 2); // 返回的是一个数组
        console.log(re);

⭐求任意两个数的和 

  function getSum(num1, num2) {
            return num1 + num2;
        }
        console.log(getSum(1, 2));

 ⭐利用函数求任意两个数的最大值(函数值)

 <script>
        function getmax (num1,num2) {
            var max = 0;
            if (num1 > num2){
                max = num1;
            } else {
                max = num2;
            } 
            return max;
        }
        console.log(getmax(2,6));
    </script>

 ⭐求数组中的最大值(函数版)

两种输出方法都可以

 <script>
        function getarrmax(arr) {
            var max = arr[0];
            for ( var i = 1 ; i < arr.length; i++){
                if (arr[i] > max){
                    max = arr[i];
                }
            }
            return max;
        }
        // console.log(getarrmax([5,2,99,101,67,77]));
        var re =getarrmax[5,2,99,101,67,77];
        console.log(re);

2.函数没有 return 则返回 undefined

  console.log(re);
        // 4. 我们的函数如果有return 则返回的是 return 后面的值,如果函数么有 return 则返回undefined
        function fun1() {
            return 666;
        }
        console.log(fun1()); // 返回 666
        function fun2() {

        }
        console.log(fun2()); // 函数返回的结果是 undefined

3.break,continue,return的区别

  • break : 结束当前循环体(如 for、while)
  • continue :跳出本次循环,继续执行下次循环(如for、while)
  • return :不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码

2.6 arguments的使用 

当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参

  function fn() {
            console.log(arguments);
        }
        fn(1,2,3);

arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点

  • ​ 具有 length 属性
  • ​ 按索引方式储存数据
  • ​ 不具有数组的 push , pop 等方法

 只有函数才有 arguments 对象,而且是每个函数都内置好了这个arguments。

⭐利用函数求任意个数的最大值

<script>
        function getmax() {
            var max = arguments[0];
            for (var i = 1; i < arguments.length; i++){
                if (arguments[i] > max){
                    max = arguments[i];
                }
            }
            return max;
        }
        console.log(getmax(1,2,3,4,5,6));
    </script>

⭐利用函数封装方式翻转任意一个数组

 <script>
        //利用函数任意数组reverse翻转
        function reverse(arr) {
            var newArr = [];
            for (var i = arr.length; i >= 0 ; i-- ){
                newArr[newArr.length] = arr[i];
            }
            return newArr;
        }
        var arr1 =reverse([1,3,4,6,9]);
        console.log(arr1);
    </script>

 ⭐利用函数封装方式对数组排序--冒泡排序

 <script>
        function sort(arr) {
            for (var i = 0; i < arr.length-1; i++){
                for (var j =0; j < arr.length-i-1; j++){
                    if (arr[j] > arr[j+1]){
                     var temp = arr[j];
                     arr[j] = arr[j+1];
                     arr[j+1] = temp;
                 }
                }
            }
            return arr;
        }
        var arr1 = sort([1,2,3,4,5]); 
        console.log(arr1);
    </script>

 ⭐利用函数封装实现判断闰年

 <script>
        function isRunYear (year) {
            var flag = false;
            if (year % 4 == 0 && year % 100 !== 0 || year %400 == 0){
              flag =true;
            } 
            return flag;
        }
        console.log(isRunYear(2024));
    </script>

⭐函数可以调用另外一个函数

因为每个函数都是独立的代码块,用于完成特殊任务,因此会经常用到函数相互调用的情况。

 <script>
        //函数是可以相互调用的
        function fn1() {
            console.log(11);
            fn2();
        }
        fn1();
        function fn2() {
            console.log(22);
        }
    </script>

⭐用户输入年份,输出当前年份2月份的天数

如果是闰年,则2月份是29天,如果是平年,则二月份是28天

 <script>
        // 用户输入年份,输出当前年份2月份的天数
        function backDay() {
            var year = prompt('请您输入年份:');
            if (isRunYear(year)) { // 调用函数需要加小括号
                alert('当前年份是闰年2月份有29天');
            } else {
                alert('当前年份是平年2月份有28天');
            }
        }
        backDay();
        // 判断是否为闰年的函数
        function isRunYear(year) {
            // 如果是闰年我们返回 true  否则 返回 false 
            var flag = false;
            if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
                flag = true;
            }
            return flag;
        }
    </script>

2.7 函数表达式声明函数的方式

 <script>
        // 函数的2中声明方式
        // 1. 利用函数关键字自定义函数(命名函数)
        function fn() {

        }
        fn();
        // 2. 函数表达式(匿名函数) 
        // var 变量名 = function() {};
        var fun = function(aru) {
            console.log('我是函数表达式');
            console.log(aru);

        }
        fun('pink老师');
        // (1) fun是变量名 不是函数名  
        // (2) 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值 而 函数表达式里面存的是函数
        // (3) 函数表达式也可以进行传递参数
    </script>
  • fun是变量名 不是函数名  
  • 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值 而函数表达式里面存的是函数
  • 函数表达式也可以进行传递参数

三、JavaScript作用域

3.1 作用域概述

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

JavaScript的作用域(es6之前)有两种:

  • 全局作用域
  • 局部作用域

1.全局作用域

整个script标签  或者是一个单独的js文件

2.局部作用域(函数作用域)

在函数内部就是函数作用域,这个代码的名字只在函数内部起效果和作用。

function fn() {

     //  局部作用域

}

3.2 变量的作用域

根据作用域的不同,我们变量分为全局变量和局部变量

1.全局变量

在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量

  • 全局变量在代码的任何位置都可以使用

  • 在全局作用域下 var 声明的变量 是全局变量

  • 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)

注意:如果在函数内部,没有声明直接赋值的变量也属于全局变量

2.局部变量

在局部作用域下的变量    或者说在函数内部的变量就是局部变量

  • 局部变量只能在该函数内部使用

  • 在函数内部 var 声明的变量是局部变量

  • 函数的形参实际上就是局部变量

注意:函数的形参也可以看作是局部变量

注意:

全局变量只有浏览器关闭的时候才会销毁

3.全局变量和局部变量的区别

  • 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存

  • 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间

3.3 JavaScript中没有块级作用域

3.4 作用域链

  • 只要是代码,就至少有一个作用域

  • 写在函数内部的叫局部作用域

  • 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域

  • 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链(就近原则)

<script>
        // 作用域链  : 内部函数访问外部函数的变量,采取的是链式查找的方式来决定取那个值 这种结构我们称为作用域链   就近原则
        var num = 10;

        function fn() { // 外部函数
            var num = 20;

            function fun() { // 内部函数
                console.log(num);

            }
            fun();
        }
        fn();
    </script>

 ⭐作用域链案例

 function f1() {
            var num = 123;

            function f2() {
                var num = 0;
                console.log(num); // 站在目标出发,一层一层的往外查找
            }
            f2();
        }
        var num = 456;
        f1();
//答案为123

  var a = 1;

        function fn1() {
            var a = 2;
            var b = '22';
            fn2();

            function fn2() {
                var a = 3;
                fn3();

                function fn3() {
                    var a = 4;
                    console.log(a); //a的值 ?
                    console.log(b); //b的值 ?
                }
            }
        }
        fn1();
//a=4,b='22'

四、JavaScript预解析 

4.1 预解析(面试常问)

JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。

1.预解析:

js引擎会把js里面所有的var 还有 function 提升到当前作用域的最前面

预解析分为:变量预解析(变量提升)函数预解析(函数提升)

变量提升:就是把所有的变量声明提前到当前的作用域的最前面,不提升赋值操作

函数提升:就是把所有的函数声明提升到当前作用域的最前面, 不调用函数

2.代码执行:

按照代码书写的顺序从上到下执行

下面这一段代码很重要,注意理解里面的坑所在位置:

 <script>
        // 1问  
        console.log(num);

        // 2问
        console.log(num); // undefined  坑 1
        var num = 10;
        // 相当于执行了以下代码
        // var num;
        // console.log(num);
        // num = 10;



        // 3问  
        function fn() {
            console.log(11);
        }
        fn();




        // 4问
        fun(); // 报错  坑2 
        var fun = function() {
                console.log(22);

            }
            // 函数表达式 调用必须写在函数表达式的下面
            // 相当于执行了以下代码
            // var fun;
            // fun();
            // fun = function() {
            //         console.log(22);

        //     }

预解析案例

案例1

//案例1
        var num = 10;
        fun ();
        function fun(){
            console.log(num);
            var num = 20;
        }
        //相当于执行了以下操作
        var num;
        function fun(){
            var num;
            console.log(num);
            num = 20;
        }
        num = 10;
        fun();
        //结果是undefined

案例2

 //案例2
        var num = 10;
        function fn() {
            console.log(num);
            var num = 20;
            console.log(num);
        }
        fn();
         
        //相当于执行了下面代码
        var num;
        function fn() {
            var num;
            console.log(num);
            num = 20;
            console.log(num);
        }
        num = 10;
        fn();
        // undefined 和 20

案例3


        //案例3
        var a = 18;
        f1();

        function f1() {
            var b = 9;
            console.log(a);
            console.log(b);
            var a = '123';
        }

        //相当于执行了下列代码

        var a;
        function f1() {
            var b;
            var a;
            b = 9;
            console.log(a);
            console.log(b);
            a = '123';
        }
        a = 18;
        f1();
// unfined 和 9

案例4(面试常见混淆题)

//案例4
f1();
console.log(c);
console.log(b);
console.log(a);

function f1() {
    var a = b = c = 9;
    console.log(a);
    console.log(b);
    console.log(c);
}

//相当于执行了下列代码
function f1() {
    var a;
    //相当于 var a = 9; b = 9; c = 9;   b和c直接赋值,没有var声明,当全局变量看
    //集体声明 var a = 9, b = 9, c = 9;   注意上面和下面的逗号和分号
    a = b = c = 9;
    console.log(a);
    console.log(b);
    console.log(c);
}
f1();
console.log(c);
console.log(b);
console.log(a);
//结果是   9 9 9 9 9 报错

五、对象 

5.1 对象

在 JavaScript 中,对象是一组无序的相关属性方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。

对象是由属性和方法组成的:

  • 属性:事物的特征,在对象中属性来表示(常用名词
  • 方法:事物的行为,在对象中方法来表示(常用动词

5.2 为什么需要对象

  • 保存一个值时,可以用变量
  • 保存多个值(一组值)时,可以用数组
  • 保存一个人的完整信息 -----用对象

 JS中的对象表达结构更清晰,更强大。

5.3 创建对象的三种方式

在 JavaScript 中,现阶段我们可以采用三种方式创建对象(object):

  • 利用字面量创建对象
  • 利用 new Object创建对象
  • 利用构造函数创建对象

1.利用字面量创建对象

对象字面量:就是花括号{ }里面包含了这个具体事物(对象)的属性和方法。

{ } 里面采取键值对的形式表示

  • 键:相当于属性名
  • 值:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)

对象的调用

  • 对象里面的属性调用 : 对象.属性名 ,这个小点 . 就理解为“  ”

  • 对象里面属性的另一种调用方式 : 对象[‘属性名’],注意方括号里面的属性必须加引号,我们后面会用

  • 对象里面的方法调用:对象.方法名() ,注意这个方法名字后面一定加括号

<script>
        // 1.利用对象字面量创建对象 {}
        // var obj = {};  // 创建了一个空的对象 
        var obj = {
                uname: '张三疯',
                age: 18,
                sex: '男',
                sayHi: function() {
                    console.log('hi~');

                }
            }
            // (1) 里面的属性或者方法我们采取键值对的形式  键 属性名 : 值  属性值 
            // (2) 多个属性或者方法中间用逗号隔开的
            // (3) 方法冒号后面跟的是一个匿名函数
            // 2. 使用对象
            // (1). 调用对象的属性 我们采取 对象名.属性名 . 我们理解为 的
        console.log(obj.uname);
        // (2). 调用属性还有一种方法 对象名['属性名']
        console.log(obj['age']);
        // (3) 调用对象的方法 sayHi   对象名.方法名() 千万别忘记添加小括号
        obj.sayHi();
    </script>

变量、属性、函数、方法总结 

  • 变量:单独声明赋值,单独存在

  • 属性:对象里面的变量称为属性,不需要声明,用来描述该对象的特征

  • 函数:单独存在的,通过==“函数名()”==的方式就可以调用

  • 方法:对象里面的函数称为方法,方法不需要声明,使用==“对象.方法名()”==的方式就可以调用,方法用来描述该对象的行为和功能。

2. 利用new object创建对象

创建格式:

var 对象名 = new Object();

<script>
        //利用new object 创建对象
        var obj = new Object();   //创建了一个空的对象
        obj.uname = '张三丰';
        obj.age = 18;
        obj.sex = '男';
        obj.sayHi = function() {
            console.log('hi');
        }     
        //我们是利用 等号 = 赋值的方法 添加对象的属性和方法
        // 每个属性和方法之间用 分号结束
        console.log(obj.uname);
        console.log(obj.sex);
    </script>

3.利用构造函数创建对象

构造函数 :是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。

 <script>
        // 利用构造函数创建对象
        // 我们需要创建四大天王的对象  相同的属性: 名字 年龄 性别  相同的方法: 唱歌
        // 构造函数的语法格式
        // function 构造函数名() {
        //     this.属性 = 值;
        //     this.方法 = function() {}
        // }
        // new 构造函数名();
        function Star(uname, age, sex) {
            this.name = uname;
            this.age = age;
            this.sex = sex;
            this.sing = function(sang) {
                console.log(sang);

            }
        }
        var ldh = new Star('刘德华', 18, '男'); // 调用函数返回的是一个对象
        // console.log(typeof ldh);
        console.log(ldh.name);
        console.log(ldh['sex']);
        ldh.sing('冰雨');
        var zxy = new Star('张学友', 19, '男');
        console.log(zxy.name);
        console.log(zxy.age);
        zxy.sing('李香兰')

        // 1. 构造函数名字首字母要大写
        // 2. 我们构造函数不需要return 就可以返回结果
        // 3. 我们调用构造函数 必须使用 new
        // 4. 我们只要new Star() 调用函数就创建一个对象 ldh  {}
        // 5. 我们的属性和方法前面必须添加 this
    </script>

4.构造函数和对象的区别

  • 构造函数,如 Stars(),抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class)
  • 创建对象,如 new Stars(),特指某一个,通过 new 关键字创建对象的过程我们也称为对象实例化

我们利用构造函数创建对象的过程就叫做对象的实例化。 

 

5.new关键字执行过程

  1. new 构造函数可以在内存中创建了一个空的对象
  2. this 就会指向刚才创建的空对象
  3. 执行构造函数里面的代码 给这个空对象添加属性和方法
  4. 返回这个对象(所以构造函数里面不需要return)

6.遍历对象属性

  • for...in 语句用于对数组或者对象的属性进行循环操作
for(变量 in 对象名字){
    // 在此执行代码
}

语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。 

 <script>
        // 遍历对象 
        var obj = {
                name: 'pink老师',
                age: 18,
                sex: '男',
                fn: function() {}
            }
        for (var k in obj) {
            console.log(k); // k 变量 输出  得到的是 属性名
            console.log(obj[k]); // obj[k] 得到是 属性值

        }
        // 我们使用 for in 里面的变量 我们喜欢写 k  或者  key
    </script>

5.4 小结

  1. 对象可以让代码结构更加清晰
  2. 对象复杂数据类型object
  3. 本质:对象就是一组无序的相关属性和方法的集合。
  4. 构造函数泛指某一大类,比如苹果,不管是红色苹果还是绿色苹果,都统称为苹果
  5. 对象实例特指某一个事物,比如这个苹果,那个红苹果等等。
  6. for ... in 语句用于对对象的属性进行循环操作。

六、JavaScript内置对象

6.1 内置对象

  • JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象

  • 前面两种对象是JS基础内容,属于ECMAScript;第三个浏览器对象属于JS特有的

  • 内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)

  • 内置对象最大的优点就是帮助我们快速开发

  • JavaScript 提供了多个内置对象:Math、 Date 、Array、String等

6.2 查文档

常用文档MDN/W3C.

MDN:提供了有关开发网络技术(Open Web)的信息,包括HTML、CSS和万维网及HTML5应用的API。

网址:https://developer.mozilla.org/zh-CN/

查阅步骤:

1.查阅该方法的功能 

2.查阅该方法的参数

3.查看返回值的意义及类型

  •  带中括号[ ]表明中括号里面的参数是可以省略的。

4. 通过demo进行测试

6.3 Math

   // Math数学对象 不是一个构造函数 ,所以我们不需要new 来调用 而是直接使用里面的属性和方法即可
        console.log(Math.PI); // 一个属性 圆周率
        console.log(Math.max(1, 99, 3)); // 99
        console.log(Math.max(-1, -10)); // -1
        console.log(Math.max(1, 99, 'pink老师')); // NaN
        console.log(Math.max()); // -Infinity

⭐封装自己的数学对象

<script>
        // 利用对象封装自己的数学对象  里面有 PI 最大值和最小值
        var myMath = {
            PI: 3.1415926,
            max: function (){
                var max = arguments[0];
                for (var i = 1; i < arguments.length; i++) {
                    if (arguments[i] > max) {
                        max = arguments[i];
                    }
                }
                return max;
            } ,
            min : function (){
                var min = arguments[0];
                for (var i = 1; i < arguments.length; i++) {
                    if (arguments[i] < min) {
                        min = arguments[i];
                    }
                }
                return min;
            } 
        }
        console.log(myMath.PI);
        console.log(myMath.max(1,4,9));
        console.log(myMath.min(3,6,1));
    </script>

1.abs,floor,ceil,round方法 

 <script>
        // 1.绝对值方法
        console.log(Math.abs(1));
        console.log(Math.abs(-1));
        console.log(Math.abs('-1'));//隐式转换  会把字符串型 -1 转换为数字型
        console.log(Math.abs('pink'));//NaN
        
        // 2.三个取整方法
        //Math.floor()    向下取整 往小了取值
        console.log(Math.floor(1.1));//1
        console.log(Math.floor(1.9));//1

        //Math.ceil()      向上取整 往大了取值
        console.log(Math.ceil(1.1));//2
        console.log(Math.ceil(1.9));//2

        //Math.round()    四舍五入   但是 .5 特殊  它往大了取
        console.log(Math.round(1.1));//1
        console.log(Math.round(1.5));//2
        console.log(Math.round(1.9));//2
        console.log(Math.round(-1.1));//-1
        console.log(Math.round(-1.5));//这个结果是-1
    </script>

2.随机数方法 random( )

  • 返回一个随机的小数  0 =<  x  <1
  • 这个方法里面不跟参数
<script>
        // 1.Math对象随机数方法   random() 返回一个随机的小数  0 =< x < 1
        // 2. 这个方法里面不跟参数
        // 3. 代码验证 
        console.log(Math.random());
        // 4. 我们想要得到两个数之间的随机整数 并且 包含这2个整数
        // Math.floor(Math.random() * (max - min + 1)) + min;
        function getRandom(min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }
        console.log(getRandom(1, 10));
        // 5. 随机点名  
        var arr = ['张三', '张三丰', '张三疯子', '李四', '李思思', 'pink老师'];
        // console.log(arr[0]);
        console.log(arr[getRandom(0, arr.length - 1)]);
    </script>

 ⭐猜数字游戏

  <script>
        // 猜数字游戏
        // 1.随机生成一个1~10 的整数  我们需要用到 Math.random() 方法。
        // 2.需要一直猜到正确为止,所以需要一直循环。
        // 3.while 循环更简单
        // 4.核心算法:使用 if  else if 多分支语句来判断大于、小于、等于。
       function getRandom(min,max){
        return Math.floor(Math.random() * (max - min + 1)) + min;
       }
       var random = getRandom(1,10);
       while (true) {
           var num = prompt('你来猜,请输入1-10之间的数字');
           if (num > random){
               alert ('数字太大啦,请重新输入');
           } else if (num < random) {
               alert ('数字有点小哦,重新输入吧');
           } else {
               alert ('恭喜你猜对啦');
               break;//退出整个循环,结束程序
           }
       }
    </script>

6.4 日期对象

  • Date 对象和 Math 对象不一样,他是一个构造函数,所以我们需要实例化后才能使用

  • Date 实例用来处理日期和时间

 <script>
        // Date() 日期对象  是一个构造函数 必须使用new 来调用创建我们的日期对象
        var arr = new Array(); // 创建一个数组对象
        var obj = new Object(); // 创建了一个对象实例
        // 1. 使用Date  如果没有参数 返回当前系统的当前时间
        var date = new Date();
        console.log(date);
        // 2. 参数常用的写法  数字型  2019, 10, 01  或者是 字符串型 '2019-10-1 8:8:8'
        var date1 = new Date(2022, 10, 1);
        console.log(date1); // 返回的是 11月 不是 10月 
        var date2 = new Date('2022-01-23 8:8:8');
        console.log(date2);
    </script>

 3.日期格式化

<script>
        // 格式化日期 年月日 
        var date = new Date();
        console.log(date.getFullYear()); // 返回当前日期的年  2019
        console.log(date.getMonth() + 1); // 月份 返回的月份小1个月   记得月份+1 呦
        console.log(date.getDate()); // 返回的是 几号
        console.log(date.getDay()); // 3  周一返回的是 1 周六返回的是 6 但是 周日返回的是 0
        // 我们写一个 2019年 5月 1日 星期三
        var year = date.getFullYear();
        var month = date.getMonth() + 1;
        var dates = date.getDate();
        var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
        var day = date.getDay();
        console.log('今天是:' + year + '年' + month + '月' + dates + '日 ' + arr[day]);
    </script>

 ⭐要求封装一个函数返回当前的时分秒 格式 08:08:08

<script>
        // 格式化日期 时分秒
        var date = new Date();
        console.log(date.getHours()); // 时
        console.log(date.getMinutes()); // 分
        console.log(date.getSeconds()); // 秒
        // 要求封装一个函数返回当前的时分秒 格式 08:08:08
        function getTimer() {
            var time = new Date();
            var h = time.getHours();
            h = h < 10 ? '0' + h : h;
            var m = time.getMinutes();
            m = m < 10 ? '0' + m : m;
            var s = time.getSeconds();
            s = s < 10 ? '0' + s : s;
            return h + ':' + m + ':' + s;
        }
        console.log(getTimer());
    </script>

 4. 获取日期的总的毫秒形式

  • date.valueOf() :得到现在时间距离1970.1.1总的毫秒数
  • date.getTime() :得到现在时间距离1970.1.1总的毫秒数
 <script>
        // 获得Date总的毫秒数(时间戳)  不是当前时间的毫秒数 而是距离1970年1月1号过了多少毫秒数
        // 1. 通过 valueOf()  getTime()
        var date = new Date();
        console.log(date.valueOf()); // 就是 我们现在时间 距离1970.1.1 总的毫秒数
        console.log(date.getTime());
        // 2. 简单的写法 (最常用的写法)
        var date1 = +new Date(); // +new Date()  返回的就是总的毫秒数
        console.log(date1);
        // 3. H5 新增的 获得总的毫秒数
        console.log(Date.now());
    </script>

 ⭐京东倒计时案例

 <script>
        // 倒计时效果
        // 1.核心算法:输入的时间减去现在的时间就是剩余的时间,即倒计时 ,但是不能拿着时分秒相减,比如 05 分减去25分,结果会是负数的。
        // 2.用时间戳来做。用户输入时间总的毫秒数减去现在时间的总的毫秒数,得到的就是剩余时间的毫秒数。
        // 3.把剩余时间总的毫秒数转换为天、时、分、秒 (时间戳转换为时分秒)
        // 转换公式如下: 
        //  d = parseInt(总秒数/ 60/60 /24);    //  计算天数
        //  h = parseInt(总秒数/ 60/60 %24)   //   计算小时
        //  m = parseInt(总秒数 /60 %60 );     //   计算分数
        //  s = parseInt(总秒数%60);            //   计算当前秒数
       function countDown(time) {
         var nowTime = +new Date(); //返回当前时间总的毫秒数
         var inputTime = +new Date(time);//返回的是用户输入时间总的毫秒数
         var times = (inputTime - nowTime) / 1000; //time是剩余时间总的秒数
         var d = parseInt(times/ 60 / 60 / 24);//天
         d = d < 10 ? '0' + d : d;
         var h = parseInt(times/ 60 / 60 %24);//时
         h = h < 10 ? '0' + h : h;
         var m = parseInt(times /60 %60 );//分
         m = m < 10 ? '0' + m : m;
         var s = parseInt(times%60);//当前的秒
         s = s < 10 ? '0' + s : s;
         return d + '天' + h + '时' + m + '分' + s + '秒';
       }
       console.log(countDown('2022-1-23 21:00:00'));
    </script>

七、数组对象的创建 

7.1 数组对象的创建

创建数组对象的两种方式

  • 字面量方式
  • new Array()
<script>
        // 创建数组的两种方式
        // 1. 利用数组字面量
        var arr = [1,2,3];
        console.log(arr[0]);

        // 2. 利用new Array()
        // var arr1 = new Array();  // 创建了一个空的数组
        // var arr1 = new Array(2);  // 这个2 表示 数组的长度为 2  里面有2个空的数组元素 
        var arr1 = new Array(2,3);//等价于 【2,3】 这样写表示 里面有2个数组元素,是2和3
        console.log(arr1);
    </script>

 7.2 检测是否为数组

  • instanceof  运算符,它可以用来检测是否为数组
  • Array.isArray(参数);  H5新增的方法  ie9以上版本支持
  // 检测是否为数组
        // (1) instanceof  运算符 它可以用来检测是否为数组
        var arr = [];
        var obj = {};
        console.log(arr instanceof Array);
        console.log(obj instanceof Array);
        // (2) Array.isArray(参数);  H5新增的方法  ie9以上版本支持
        console.log(Array.isArray(arr));
        console.log(Array.isArray(obj));

 ⭐翻转数组案例  使用判断数组事先判断

// 翻转数组
        function reverse(arr) {
            // if (arr instanceof Array) {
            if (Array.isArray(arr)) {
                var newArr = [];
                for (var i = arr.length - 1; i >= 0; i--) {
                    newArr[newArr.length] = arr[i];

                }
                return newArr;
            } else {
                return 'error 这个参数要求必须是数组格式 [1,2,3]'
            }
        }
        console.log(reverse([1, 2, 3]));
        console.log(reverse(1, 2, 3));

 7.3 添加删除数组元素的方法

1.添加元素push

push() 在我们数组的末尾 添加一个或者多个数组元素

var arr = [1, 2, 3];
        // arr.push(4, 'pink');
        console.log(arr.push(4, 'pink'));
        console.log(arr);
   //结果是[1, 2, 3, 4, 'pink']
  • push 是可以给数组追加新的元素(在数组后面追加)
  • push()参数直接写数组元素就可以了
  • push完毕之后,返回的结果是  新数组的长度
  • 原数组也会发生变化

 2.添加元素unshift

unshift 在我们数组的开头  添加一个或者多个数组元素

  var arr = [1, 2, 3,4,'pink'];
  console.log(arr.unshift('red', 'purple'));
        console.log(arr);
//结果是['red', 'purple', 1, 2, 3, 4, 'pink']
  • unshift是在数组的前面追加新的元素
  • unshift()参数直接写数组元素就可以了
  • unshift完毕之后,返回的结果是  新数组的长度
  • 原数组也会发生变化

3.删除元素pop 

pop()它可以删除数组的最后一个元素

var arr = ['red', 'purple', 1, 2, 3, 4, 'pink'] 
console.log(arr.pop());
        console.log(arr);
//结果是 ['red', 'purple', 1, 2, 3, 4]
  • pop可以删除数组的最后一个元素   记住一次只能删除一个元素
  • pop()没有参数
  • pop完毕之后,返回的结果是  删除的那个元素
  • 原数组也会发生变化

 4.删除元素shift

shift()可以删除数组的第一个元素

var arr = ['red', 'purple', 1, 2, 3, 4];
  console.log(arr.shift());
        console.log(arr);
//结果是  ['purple', 1, 2, 3, 4]
  • shift可以删除数组的第一个元素   记住一次只能删除一个元素
  • shift()没有参数
  • shift完毕之后,返回的结果是  第一个元素的值
  • 原数组也会发生变化

⭐⭐筛选数组

有一个包含工资的数组[1500,1200,2000,2100,1800],要求把数组中工资超过2000的删除,剩余的放到新数组里面

 <script>
        // 有一个包含工资的数组[1500, 1200, 2000, 2100, 1800],要求把数组中工资超过2000的删除,剩余的放到新数组里面
        var arr = [1500, 1200, 2000, 2100, 1800];
        var newArr = [];
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] < 2000) {
                // newArr[newArr.length] = arr[i];
                newArr.push(arr[i]);
            }
        }
        console.log(newArr);
    </script>

7.4 数组排序 

  var arr = ['pink', 'red', 'blue'];
        arr.reverse();
        console.log(arr);
var arr1 = [13, 4, 77, 1, 7];
        arr1.sort(function(a, b) {
            //  return a - b; 升序的顺序排列
            return b - a; // 降序的顺序排列
        });
        console.log(arr1);

 7.5 数组索引的方法

1.indexOf 获取索引 

作用:返回该数组元素的索引号,从前面开始查找

只返回第一个满足条件的索引号。

它如果在该数组里面找不到元素,则返回的是 -1

 var arr = ['red', 'green', 'pink'];
        console.log(arr.indexOf('blue'));

 2.lastIndexOf

作用:返回该数组元素的索引号,从后面开始查找

  var arr = ['red', 'green', 'blue', 'pink', 'blue'];

        console.log(arr.lastIndexOf('blue')); // 4

 ⭐⭐数组去重(重点案例)

数组去重 ['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b']     要求去除数组中重复的元素。

 <script>
        // 数组去重 ['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'] 要求去除数组中重复的元素。
        // 1.目标: 把旧数组里面不重复的元素选取出来放到新数组中, 重复的元素只保留一个, 放到新数组中去重。
        // 2.核心算法: 我们遍历旧数组, 然后拿着旧数组元素去查询新数组, 如果该元素在新数组里面没有出现过, 我们就添加, 否则不添加。
        // 3.我们怎么知道该元素没有存在? 利用 新数组.indexOf(数组元素) 如果返回时 - 1 就说明 新数组里面没有改元素
        // 封装一个 去重的函数 unique 独一无二的 
       function unique(arr){
           var newArr = [];
           for (var i = 0; i < arr.length; i++){
              if (newArr.indexOf(arr[i]) === -1){
                  newArr.push(arr[i]);
              }
           }
           return newArr;
       }
       var demo = unique(['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'] ) ;
       console.log(demo);

    </script>

7.6 数组转化为字符串

1.toString()

// 数组转换为字符串 
        // 1. toString() 将我们的数组转换为字符串
        var arr = [1, 2, 3];
        console.log(arr.toString()); // 1,2,3

2.join('分隔符') 

  // 2. join(分隔符) 
        var arr1 = ['green', 'blue', 'pink'];
        console.log(arr1.join()); // green,blue,pink
        console.log(arr1.join('-')); // green-blue-pink
        console.log(arr1.join('&')); // green&blue&pink

3.数组中常用其他内置对象 

八、字符串类型 

8.1 基本包装类型

就是把 简单数据类型 包装成为了 复杂数据类型,这样基本数据类型就有了属性和方法。

为了方便操作基本数据类型,JavaScript还提供了三个特殊的引用类型:String,Number和Boolean。

 <script>
        // 基本包装类型
        var str = 'andy';
        console.log(str.length);
        // 对象 才有 属性和方法   复杂数据类型才有 属性和方法 
        // 简单数据类型为什么会有length 属性呢? 
        // 基本包装类型:  就是把简单数据类型 包装成为了 复杂数据类型 
        // (1) 把简单数据类型包装为复杂数据类型 
        var temp = new String('andy');
        // (2) 把临时变量的值 给 str
        str = temp;
        // (3) 销毁这个临时变量
        temp = null;
    </script>

8.2 字符串的不可变

指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中开辟了一个内存空间。

<script>
        // 字符串的不可变性
        var str = 'andy';
        console.log(str);
        str = 'red';
        console.log(str);
        // 因为我们字符串的不可变所以不要大量的拼接字符串
        var str = '';
        for (var i = 1; i <= 100; i++) {
            str += i;
        }
        console.log(str);
    </script>

8.3 根据字符返回位置

字符串中所有的方法,都不会修改字符串本身(字符串本身是不可变的),操作完成会返回一个新的字符串。

   // 字符串对象  根据字符返回位置  str.indexOf('要查找的字符', [起始的位置])
        var str = '改革春风吹满地,春天来了';
        console.log(str.indexOf('春'));
        console.log(str.indexOf('春', 3)); // 从索引号是 3的位置开始往后查找

⭐返回字符位置 (经典面试题)

查找字符串"abcoefoxyozzopp"中所有o出现的位置以及次数.

代码思路:

   var str = "abcoefoxyozzopp";
       var index = str.indexOf('o');
       var num = 0;
       while (index !== -1){
           console.log(index);
           num++;
           index = str.indexOf('o',index + 1);
       }
       console.log('o出现的次数是:' + num);

 8.4 根据位置返回字符(重点)

 1.charAt(index)

根据位置返回字符

 // 1. charAt(index) 根据位置返回字符
        var str = 'andy';
        console.log(str.charAt(3));
        // 遍历所有的字符
        for (var i = 0; i < str.length; i++) {
            console.log(str.charAt(i));
        }

2.charCodeAt(index)

获取指定位置处字符的ASCII码(index索引号) 

常用于判断用户按了哪个键。

// 2. charCodeAt(index)  返回相应索引号的字符ASCII值 目的: 判断用户按下了那个键 
        console.log(str.charCodeAt(0)); // 97

 3. str[index]

 // 3. str[index] H5 新增的
        console.log(str[0]); // a

8.5 判断对象中是否有某个属性 

   // 有一个对象 来判断是否有该属性 对象['属性名']
        var o = {
            age: 18
        }
        if (o['sex']) {
            console.log('里面有该属性');

        } else {
            console.log('没有该属性');

        }

 ⭐判断一个字符串,'abcoefoxyozzopp' 中出现次数最多的字符,并统计其次数

 8.6 字符串操作方法(重点)

1.concat('字符串1','字符串2'....)

 // 1. concat('字符串1','字符串2'....)
        var str = 'andy';
        console.log(str.concat('red'));
        //andyred

2.substr('截取的起始位置', '截取几个字符'); 

   var str1 = '改革春风吹满地';
        console.log(str1.substr(2, 2)); // 第一个2 是索引号的2 从第几个开始  第二个2 是取几个字符
// 春风

8.7 替换字符replace

replace('被替换的字符', '替换为的字符')    它只会替换第一个字符

  var str = 'andyandy';
        console.log(str.replace('a', 'b'));

⭐有一个字符串 'abcoefoxyozzopp'  要求把里面所有的 o 替换为 *

 var str1 = 'abcoefoxyozzopp';
        while (str1.indexOf('o') !== -1) {
            str1 = str1.replace('o', '*');
        }
        console.log(str1);

8.8 字符转换为数组 split('分隔符') 

前面我们学过join把数组转换为字符串

  var str2 = 'red, pink, blue';
        console.log(str2.split(','));
        var str3 = 'red&pink&blue';
        console.log(str3.split('&'));

九、JavaScript中的简单数据类型和复杂数据类型

9.1 简单类型和复杂类型

简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。

值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型
string ,number,boolean,undefined,null
引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型
通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等


特殊:

// 简单数据类型 null  返回的是一个空的对象  object 
        var timer = null;
        console.log(typeof timer);
  •   如果有个变量我们以后打算存储为对象,暂时没想好放啥, 这个时候就给 null

 9.2 堆和栈

堆栈空间分配区别:

  • 栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。
  • 其操作方式类似于数据结构中的栈;
  • 简单数据类型存放到栈里面
  • 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放
  • 若程序员不释放,由垃圾回收机制回收。
  • 复杂数据类型存放到堆里面

 JavaScript中没有堆栈的概念,通过堆栈的方式,可以让大家更容易理解代码的一些执行方式,便于将来学习其他语言。

9.3 简单类型的内存分配

  • 值类型(简单数据类型): string ,number,boolean,undefined,null
  • 值类型变量的数据直接存放在变量(栈空间)中

  1. 简单数据类型 是存放在栈里面 里面直接开辟一个空间存放的是值

  2. 复杂数据类型 首先在栈里面存放地址 十六进制表示  然后这个地址指向堆里面的数据

9.4  简单类型传参

函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。

 // 简单数据类型传参
        function fn(a) {
            a++;
            console.log(a);
        }
        var x = 10;
        fn(x);
        console.log(x);

9.5  复杂类型传参

函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。

 <script>
        // 复杂数据类型传参
        function Person(name) {
            this.name = name;
        }

        function f1(x) { // x = p
            console.log(x.name); // 2. 这个输出什么 ?  刘德华   
            x.name = "张学友";
            console.log(x.name); // 3. 这个输出什么 ?   张学友
        }
        var p = new Person("刘德华");
        console.log(p.name); // 1. 这个输出什么 ?   刘德华 
        f1(p);
        console.log(p.name); // 4. 这个输出什么 ?   张学友
    </script>

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值