js(JavaScript)基础知识3

6 JavaScript函数

函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。通俗来讲:把一段相对独立的具有特定功能的代码块封装起来,形成一个独立实体,就是函数,起个名字(函数名)。 函数的作用就是封装一段代码,将来可以重复使用。

6.1 函数的声明和调用
  • 函数声明
function 函数名(参数列表){
// 函数体
}
  • 调用函数的语法:
函数名();

特点: 函数声明的时候,函数体并不会执行,只要当函数被调用的时候才会执行。

函数的应用分为两步,一是先声明一个函数,再调用该函数。

声明函数:

  1. 声明无参函数语法
  2. 声明有参函数的语法
  3. 声明带有返回值的函数

在JavaScript中,调用函数时,如果没有返回值,就直接用函数方法名()调用。如果有参数,则必须给每 个参数赋值,函数方法名(参数值),如果还有返回值,可以用一个变量来存储这个值。

  • 带参数的函数声明语法:

函数内部是一个封闭的环境,可以通过参数的方式,把外部的值传递给函数内部。

function 函数名(var1, var2...) {
// 函数体
}

上面的var1,var2就是参数,它代表一个不确定的值,这个值要参与函数代码块的运算,在调用函数时, 可以给这些参数赋值。也可以在函数中定义多个参数,每个参数之间逗号 (,) 分隔。 当声明函数时,参数相当于作为变量来声明。 变量和参数必须以一致的顺序出现。第一个变量就是第一个被传递的参数的给定的值,以此类推。

  • 带参数的函数调用:
函数名(实参1, 实参2, 实参3);
形参1 = 实参1
形参2 = 实参2
6.2 形参和实参

形式参数:在声明一个函数的时候,为了函数的功能更加灵活,有些值是固定不了的,对于这些固 定不了的值。我们可以给函数设置参数。这个参数没有具体的值,仅仅起到一个占位置的作用,我 们通常称之为形式参数,也叫形参。

实际参数:如果函数在声明时,设置了形参,那么在函数调用的时候就需要传入对应的参数,我们 把传入的参数叫做实际参数,也叫实参。

需要注意的是,同一个函数,形参和实参是一一对应的。

如何区分实参和形参?

  1. 出现的地方不一样,一个是在函数的声明中,一个出现在函数的调用中。
  2. 代表的意义不一样,一个是声明一个变量,一个是该变量的值。
  • 代码示例:
// 求n个数的最大值?
function getMax(arr) {
// 参数arr 是数组
var max = arr[0];
for (var i = 1; i < arr.length; i++) {
// 判断max和数组中之后的每一个元素进行比较
if (max < arr[i]) {
max = arr[i];
}
}
console.log(max);
}

var array = [12, 2, 45, 1, 10];
getMax(array);
// - 判断一个数是否是素数(又叫质数,只能被1和自身整数的数)
function jdugePrimeNumber(number) {
// 假设number是质数
var isPrime = true;
for (var i = 2; i < number; i++) {
// 判断是否有能被number整数的数
if (number % i === 0) {
// 如果此处执行了。说明不是质数
isPrime = false;
break;
}
}
if (isPrime) {
console.log('质数');
} else {
console.log('不是质数');
}
}

jdugePrimeNumber(13);
  • 冒泡排序:

算法步骤:

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

代码实现:

function bubbleSort(arr) {
    var len = arr.length;
    for (var i = 0; i < len - 1; i++) {
        for (var j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j+1]) {        // 相邻元素两两对比
                var temp = arr[j+1];        // 元素交换
                arr[j+1] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}
6.3 函数的返回值

当函数执行完的时候,并不是所有时候都要把结果打印。我们期望函数给我一些反馈(比如计算的结果 返回进行后续的运算),这个时候可以让函数返回一些东西,也就是返回值。函数通过return返回一个 返回值。

语法如下:

//声明一个带返回值的函数
function 函数名(形参1, 形参2, 形参3...) {
//函数体
return 返回值;
}

//可以通过变量来接收这个返回值
var 变量 = 函数名(实参1, 实参2, 实参3...);

返回值详解:

如果函数没有显式的使用 return语句 ,那么函数有默认的返回值:undefined。

如果函数使用 return语句,那么跟在return后面的值,就成了函数的返回值。

如果函数使用 return语句,但是return后面没有任何值,那么函数的返回值也是:undefined。

函数使用return语句后,这个函数会在执行完 return 语句之后停止并立即退出,也就是说return后 面的所有其他代码都不会再执行。

推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。

  • 函数是一种数据类型

函数作为参数:因为函数也是一种类型,可以把函数作为另一个函数的参数,在另一个函数中调用

函数做为返回值:因为函数是一种类型,所以可以把函数可以作为返回值从函数内部返回。

6.4 JavaScript arguments对象

JavaScript中,arguments对象是比较特别的一个对象,实际上是当前函数的一个内置属性。也就是说所 有函数都内置了一个arguments对象,arguments对象中存储了传递的所有的实参。arguments是一个 伪数组,因此就可以进行遍历。

// 求任意个数的最大值
function getMax() {
    var max = arguments[0];
    for (var i = 1; i < arguments.length; i++) {
        if (max < arguments[i]) {
            max = arguments[i];
        }
    }
    return max;
}
// 求斐波那契数列Fibonacci中的第n个数是多少? 1 1 2 3 5 8 13 21...
function getFib(n) {
// 函数体
var n1 = 1;
var n2 = 1;
var n3;
for (var i = 3; i <= n; i++) {
n3 = n1 + n2;
n1 = n2;
n2 = n3;
}
return n3;
}
var r = getFib(6);
console.log(r);
6.5 JavaScript函数作用域

变量从作用域的角度划分,分为两种: 局部变量 ;全局变量。

(作用域:变量可以起作用的范围)

  • 局部变量:在JavaScript函数内部声明的变量是局部变量,所以只能在函数内部访问它,该变量的作用域是局部的。 可以在不同的函数中使用名称相同的局部变量,因为只有声明过该变量的函数才能识别出该变量。只要 函数运行完毕,局部变量就会被删除。

  • 全局变量:在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。

注意:如果没有使用var声明变量,该变量将被自动作为全局变量声明,不推荐使用。

比如这条语句:carname=“Volvo”;将声明一个全局变量 carname,即使它在函数内部声明。

局部变量和全局变量的区别:

  1. 声明位置不同:局部变量声明在函数内部。全局变量声明在函数外部。
  2. 作用域不一样:局部变量只在某一个局部范围有效,比如函数内部。全局变量在整个页面有效,网 页上的所有脚本和函数都能访问它。
  3. 生命周期不一样:局部变量会在函数运行以后被删除,全局变量会在页面关闭后被删除。

作用域链:只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函 数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个 作用域。 将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。

6.6 匿名函数

匿名函数: 有关键词 function, 有小括号,有大括号,就是没有函数名。

function(a,b){
console.info( a+b );
}

想要执行它,怎么执行?没有名字,怎么调用?

  • 方式一:把它放进一个变量里,这个变量就相当于一个函数名了。没有名字的匿名函数,变成有“名”函数 了,我们把这种方式称之为函数字面量。
var myFun = function( a,b ){
console.info( a+b);
};
myFun( 10,30 );
  • 方式二:干脆不要名字,直接执行。这么做可以在内部形成局部变量和局部函数,防止全局污染。

(匿名函数)();

(匿名函数() );

//注意: 使用改写法一定要注意添加分号
(function(a,b){
console.info( a+b );
})(10,30);

(function(a,b){
console.info( a+b );
}(10,30));

  • 方式三:利用事件去调用。
var btn = document.getElementById("btn"); // 找到页面某个标签

// 添加事件
btn.onclick = function(){
console.info("你点了我!");
}
  • 方法四:作为对象的方法调用。
var myObj = {
name : "John",
sayHello:function(){
console.info("Hello,"+ this.name );
}
};

myObj.sayHello();
  • 方法五:作为另一个函数的参数。
function myFun(fn){
fn();
}

myFun(function(){
console.info("这个匿名函数是个参数");
});
6.7 构造函数

通过 new 函数名() 来实例化对象的函数叫构造函数。任何的函数都可以作为构造函数存在。之所以有构造函数与普通函数之分,主要从功能上进行区别的,构造函数的主要 功能为 初始化对象,特点是和new一起使用。new就是在创建对象,从无到有,构造函数就是在为初始化的对象添加属性和方法。构造函数定义时首字母大写(规范)。

// 1. 构造函数名首字母要大写
// 2. 构造函数的作用就是用来创建对象的,
// 3. 功能上: 普通函数是用来执行某个行为;构造函数是用来创建对象的
// 4. 语法上: 基本没有差别
// 5. 从函数体: 普通函数的函数体里面就是要执行的逻辑代码; 构造函数的函数体里面是用来初始化对象成
员以及对象方法的;
function Person(id,name,age) {
//this关键字: 表示的当前对象
this.id = id; //对象的属性
this.name = name;
this.age = age;
this.eat = function () { //对象方法
alert(this.name+"的吃饭行为");
}
}
//直接通过函数名() 调用的是普通函数
//使用构造函数,必须结合new来使用
//Person()就算是构造函数,它也属于函数的一种
var p1 = new Person(1001,"张三",12); //创建一个Person对象
var p2 = new Person(1002,"李四",12);
document.write("p1的name是:"+p1.name+"<br>");
p1.eat();
6.8 回调函数

字面上的理解,回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完 之后,再执行传进去的这个函数。这个过程就叫做回调。

function modifyArray(arr, callback) {
// 对 arr 做一些操作
arr.push(100);
// 执行传进来的 callback 函数
callback();
}
var arr = [1, 2, 3, 4, 5];
modifyArray(arr, function() {
console.log("array has been modified", arr);
});

上面的代码中,我们先定义了主函数和回调函数,然后再去调用主函数,将回调函数传进去。 定义主函数的时候,我们让代码先去执行callback()回调函数,但输出结果却是后输出回调函数的内容。 这就说明了主函数不用等待回调函数执行完,可以接着执行自己的代码。所以一般回调函数都用在耗时 操作上面。比如ajax请求,比如处理文件等。

6.9 预解析

代码段是指一个script标签就是一个代码段。JS代码在执行时,是一个代码段一个代码段执行。

JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码 的时候,分为两个过程:预解析过程和代码执行过程。

什么是预解析?

浏览器在执行JS代码的时候会分成两部分操作:预解析以及逐行执行代码。也就是说浏览器不会直接执行代码, 而是加工处理之后再执行,这个加工处理的过程,我们就称之为预解析。

预解析过程:

  1. 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
  2. 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
  3. 先提升var,再提升function。

ES5 提升有变量提升和函数提升。

原则:

1、所有声明都会被提升到作用域的最顶上;

2、同一个变量声明只进行一次,并且因此其他声明都会被忽略;

3、函数声明的优先级优于变量声明,且函数声明会连带定义一起被提升。

变量提升:

把变量声明提升到函数的顶部,但是变量赋值不会提升。

console.log(a);
var a = 10;
//输出为undefined

//与上例等价
var a;
console.log(a);
a = 10;

注意:变量未声明,直接使用,输出‘变量 is not defined。

函数提升:

函数提升会将函数声明连带定义一起提升。

在JavaScript中函数的创建方式有三种:函数声明、函数表达式(函数字面量)、函数构造法(动态的,匿名的)。

只有函数声明创建的函数会执行函数提升,字面量定义的函数(实质为变量+匿名函数)会执行变量提升。

test1();
function test1(){
console.log("可以被提升");
}
test2();
var test2 = function(){
console.log("不可以被提升");
}
console.log(test2);
var test2 = function(){
console.log("不可以被提升");
}

函数和变量同时提升:

console.log(test3);
function test3(){console.log('func');}
var test3 = 'Mary';

练习:

<script>
// --------- 原题
g();
var g = function(){
console.log("g函数执行了....");
};
</script>

<script>
// --------- 分析
// g是一个变量 只不这个变量的值是一个函数 函数是一种数据类型
// 进行预编译时,仅仅是提升了var g;
// var g; g的值是und und(); 报错了
g(); // TypeError: g is not a function 只有函数才可以加()调用
var g = function(){
console.log("g函数执行了....");
}
</script>
<script>
// --------- 原题
var a = 666;
fn()
function fn(){
var b = 777;
console.log(a);
console.log(b);
console.log(c);
var a = 888;
var c = 999;
}
</script>

<script>
// --------- 分析
// 提升:
// 全局的:var a; fn整体; 提升到代码段最前面
// fn内部中的var b; var a; var c;都提升; 提升到函数体的最前面
//
var a = 666;
fn()
// fn产生一个局部作用域,它的父级作用域是全局作用域
function fn(){
// var b; var a; var c;都提升了
var b = 777;
// 找a 自己有 使用自己的 如果自己没有 使用父级作用域的数据
console.log(a); // und 自己函数体内如果有数据,就使用自己的数据
console.log(b); // 777
console.log(c); // und
var a = 888;
var c = 999;
}
</script>
<script>
// --------- 原题
console.log(a);
a = 666;
console.log(a);
</script>

<script>
// --------- 分析
// 没有加var的变量不会提升
//
console.log(a); // a is not defined / und
a = 666;
console.log(a); // 在一个代码段中,上面的代码出错了,下面的代码不会执行了
</script>

<script>
// --------- 原题
function fn(){
console.log(a);
a = 666;
console.log(a);
}
fn();
console.log(a);
</script>

<script>
// --------- 分析
// 提升:fn整体
//
function fn(){
console.log(a); // 报错 找a 没a a is not defined
a = 666;
console.log(a); // 不执行
}
fn();
console.log(a); // 不执行
</script>
6.10 防止全局污染

全局污染问题:

JavaScript 可以随意定义保存所有应用资源的全局变量。 但全局变量可以削弱程序灵活性,增大了模块之间的耦合性。在多人协作时,如果定义过多的全局变量 有可能造成全局变量冲突,也就是全局变量污染问题。

解决全局污染:

方式1: 定义全局变量命名空间,只创建一个全局变量,并定义该变量为当前应用容器,把其他全局变量追 加在该命名空间下。

方式2: 利用匿名函数将脚本包裹起来。

6.11 加var的变量和不加var的变量

加var的变量和不加var的变量有什么区别:

  • 加var的变量在预编译期间会提升,不加var的变量在预编译期间不会提升。
<script>
// 加var的变量在预编译期间会提升,不加var的变量在预编译期间不会提升。
    
// console.log(a); // undefined
// var a = 110;
    
console.log(b); // ReferenceError: b is not defined
b = 120;
</script>
  • 不管有没有加var,创建的全局变量,都会放到GO中的,也就是可以通过window.xx。
<script>
// 不管有没有加var,创建的全局变量,都会放到GO中的,也就是可以通过window.xx。
var a = 110;
b = 120;
console.log(window.a); // 110
console.log(window.b); // 120
</script>
  • 加var的变量,可能是全局变量,也可能是局部变量,不加var的变量,只能是全局变量。
  • 加var的局部变量,不会作用window的属性
<script>
function fn(){
var a = 110;
}
fn();
console.log(window.a);
</script>

不加var创建的变量:

不建议使用。 项目中尽量不要使用全局变量。在项目中,不要使用没有加var的变量。

7 JavaScript对象
7.1 JavaScript中的对象

JavaScript语言没有“类”,而改用构造函数(constructor)作为对象的模板。前面说过,“对象”是单个实物的抽象。所以,通常需要一个模板,表示某一类实物的共同特征,然后“对象”根据这个模板生成。所谓“构造函数”,就是专门用来生成“对象”的函数。它提供模板,作为对象的基本结构。比如var date1=new Date()是通过调用Date的构造函数Date()(这里可以理解为一个类)来创建一个日期对象。一个构造函数,可以生成多个对象,这些对象都有相同的属性和行为,但是属性值可以不同。

在 JavaScript 中,不会创建类,也不会通过类来创建对象(就像在其他面向对象的语言中那样),JavaScript 基于 prototype(原型),而不是基于类的。

在Javascript没有类和接口,只有对象,而根据ECMAscript的定义,对象是“无序属性的集合,其属性包含基本值,对象或者函数”。

需要注意的是,在ECMAscrip6.0中,已经使用class来定义类了。

对象object是JavaScript的核心概念,也是最重要的数据类型。JavaScript的所有数据都可以被视为对象。对象是一个容器,封装了属性(propert)和方法(method)。所谓属性,就是对象的静态状态;所谓方法,就是对象的动态行为。

JavaScript的对象是无序属性的集合。

其属性可以包含基本值、对象或函数。对象就是一组没有顺序的值。我们可以把JavaScript中的对象想象成键值对,其中值可以是数据和函数。

对象的行为和特征

特征—属性:事物的特征在对象中用属性来表示。

行为—方法:事物的行为在对象中用方法来表示。

7.2 对象的使用
7.2.1 对象的创建方式

通过对象字面量;new Object() 创建对象;工厂函数创建对象;自定义构造函数。

        // 1.通过对象字面量
        var hero = {
            name: '大乔',
            weapon: '法杖',
            equipment: ['近卫荣耀', '冰霜之杖', '冷静之靴'],
            blood: 8000,
            attack: function () {
                console.log(this.name + ':平A');
            },
            call: function () {
                console.log(this.name + ':召唤队友');
            },
        }
        
        // 获取属性
        console.log(hero.name)
        // 调用方法
        hero.call()
        // 2. new Object() 创建对象
        // 创建一个 Object 类型的一个实例,会在内存中申请一个空间
        var hero = new Object()
        
        // 动态为该对象添加属性和方法
        hero.name = '大乔'
        hero.weapon = '法杖'

        hero.attack = function () {
            console.log(this.name + ':平A');
        }
        hero.call = function () {
            console.log(this.name + ':召唤队友');
        }

        // 获取属性的值
        console.log(hero.name)
        // 调用方法
        hero.call()
// 3.工厂函数创建对象
function createHero(name, weapon, equipment, blood) {
    var hero = new Object()
    hero.name = name
    hero.weapon = weapon
    hero.equipment = equipment
    hero.blood = blood

    hero.attack = function () {
        console.log(this.name + '使用' + this.weapon + '进行攻击');
    }
    return hero
}

var wu = createHero('不知火舞', '扇子', ['回响之杖', '冷静之靴'], '4200')
// 获取属性的值
console.log(wu.name, wu.weapon, wu.blood, wu.equipment)
// 调用方法
wu.attack()

var luo = createHero('伽罗', '弓箭', ['破晓', '抵抗之靴'], '3000')
// 获取属性的值
console.log(luo.name, luo.weapon, luo.blood, luo.equipment)
// 调用方法
luo.attack()
        // 4.自定义构造函数
        function Hero(name, weapon, equipment, blood) {
            // this 动态的给对象增加成员
            // this 指向了当前对象
            this.name = name;
            this.weapon = weapon;
            this.equipment = equipment;
            this.blood = blood;

            this.attack = function () {
                console.log(this.name + '使用'+this.weapon+'发起进攻');
            }
        }

        var sun = new Hero('孙尚香', '炮', ['急速战靴', '无尽战刃'], 3600);
        var bai = new Hero('李白', '剑', ['抵抗之靴', '破军'], 4500);

        // 获取属性的值
        console.log(sun.name,sun.blood)
        // 调用方法
        sun.attack()
        bai.attack()

但是构造函数方有个缺点,就是对象的方法放在了构造函数内部,这样每创建一个方法就会需要多占用 一些内存,所以js给构造函数设计了一个prototype属性,用来存放对象的方法:

        function Hero(name, weapon, equipment, blood) {
            this.name = name;
            this.weapon = weapon;
            this.equipment = equipment;
            this.blood = blood;
        }
        // 将方法放在对象的 prototype 属性中
        Hero.prototype = {
            attack: function () {
                console.log(this.name + '使用' + this.weapon + '发起进攻');
            }
            
        }
        var sun = new Hero('孙尚香', '炮', ['急速战靴', '无尽战刃'], 3600);
        console.log(sun.name, sun.blood)
        sun.attack()
        var bai = new Hero('李白', '剑', ['抵抗之靴', '破军'], 4500);
        console.log(bai.name, bai.blood)
        bai.attack()

        //此时返回true,说明两个对象的attack方法指向的同一个内存空间
        console.log(sun.attack == bai.attack)
7.2.2 属性和方法

如果一个变量属于一个对象所有,那么该变量就可以称之为该对象的一个属性,属性一般是名词,用来 描述事物的特征。 如果一个函数属于一个对象所有,那么该函数就可以称之为该对象的一个方法,方法是动词,描述事物 的行为和功能。

7.2.3 关键字详解
  • new关键字

构造函数 ,是一种特殊的函数。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始 值,总与new运算符一起使用在创建对象的语句中。

  1. 构造函数用于创建一类对象,首字母要大写。
  2. 构造函数要和new一起使用才有意义。

new在执行时会做四件事情 :

new会在内存中创建一个新的空对象 ;

new 会让this指向这个新的对象 ;

执行构造函数(目的:给这个新对象加属性和方法);

new会返回这个新对象;

  • this详解

JavaScript中的this指向问题,有时候会让人难以捉摸,随着学习的深入,我们可以逐渐了解现在我们需要掌握函数内部的this几个特点 :

  1. 函数在定义的时候this是不确定的,只有在调用的时候才可以确定
  2. 一般函数直接执行,内部this指向全局window
  3. 函数作为一个对象的方法,被该对象所调用,那么this指向的是该对象
  4. 构造函数中的this其实是一个隐式对象,类似一个初始化的模型,所有方法和属性都挂载到了这个隐式对象身上,后续通过new关键字来调用,从而实现实例化
7.2.4 对象的使用方法
  • 遍历对象的属性

通过for…in语法可以遍历一个对象

var obj = {
name: '张三',
age: 18,
sex: true,
sayHi: function () {
console.log(this.name);
}
};
for(var key in obj) {
console.log(key + "==" + obj[key]);
}
  • 删除对象的属性
function fun() {
this.name = 'mm';
}
var obj = new fun();
console.log(obj.name); // mm
delete obj.name;
console.log(obj.name); // undefined
  • 简单类型和复杂类型的区别

基本类型又叫做值类型,复杂类型又叫做引用类型 值类型:简单数据类型,基本数据类型,在存储时,变量中存储的是值本身,因此叫做值类型。(Number String Boolean Null Undefined)

引用类型:复杂数据类型,在存储是,变量中存储的仅仅是地址(引用),因此叫做引用数据类 型。(Object Array)

  • 堆和栈

堆栈空间分配区别:

1、栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。

2、堆(操作系统): 存储复杂类型(对象),一般由程序员分配释放, 若程序员不释放,由垃 圾回收机制回收。

(注意:JavaScript中没有堆和栈的概念,此处我们用堆和栈来讲解,目的方便理解和方便以后的学 习。)

8 JavaScript内置对象

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

JavaScript 提供多个内置对象:Math/Array/Date…

对象只是带有属性和方法的特殊数据类型。

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

MDN:https://developer.mozilla.org/zh-CN/
8.1 Array对象
8.1.1 Array构造函数
// new关键字创建空数组
var arr = new Array();
// new关键字创建包含元素的数组
var arr = new Array(1,2.....N);
// new关键字创建指定元素个数的数组
var arr = new Array(数值);

// 也可以使用[]直接创建数组
var arr = [];
var arr = [1,2.....N];
// 可以使用length属性获取数组的长度;并且可以给一个数组长度赋值。

检测一个对象是否是数组:

  • instanceof

  • Array.isArray()

        var arr = [1, 3, 2, 4]
        var num = 3

        console.log(arr instanceof Array)
        console.log(Array.isArray(num))
8.1.2 Array对象方法

程序运行时通常需要读取数组中的数据,有时候需要对数据进行修改。

  • 读取数据:可以使用索引查询获取数组元素和添加数组元素;

  • 添加数据:使用 push()方法 将新元素添加到数组尾部,返回值为新数组的长度;

            var arr = ['西施', '王昭君', '貂蝉', '杨玉环']
            var count = arr.push('大乔')
            console.log(count)//5
            console.log(arr)
    
  • 删除数据:可以使用 delete运算符 删除指定的元素;

    删除指定元素后数组长度不变,被删除的元素被重置为undefined了

            var arr = ['西施', '王昭君', '貂蝉', '杨玉环']
            delete arr[2]
            console.log(arr)
    
  • 删除末尾元素 : pop()方法,该方法会返回删除的元素;

    删除末尾i元素之后,数组长度会改变

            var arr = ['西施', '王昭君', '貂蝉', '杨玉环']
            var person=arr.pop()
            console.log(person)//杨玉环
            console.log(arr)
    
  • 删除顶端的元素:shift()方法;

    删除顶端元素之后,数组长度会改变

            var arr = ['西施', '王昭君', '貂蝉', '杨玉环']
            var person=arr.shift()
            console.log(person)//西施
            console.log(arr)
    
  • 在数组顶端添加元素 : unshift()方法,返回值为新数组的长度;

            var arr = ['西施', '王昭君', '貂蝉', '杨玉环']
            var num=arr.unshift('大乔','小乔')
            console.log(num)//6
            console.log(arr.unshift('孙尚香'))//7
            console.log(arr)
    
  • 字符转换:toString()方法将数组表示为字符串;

            var arr = ['西施', '王昭君', '貂蝉', '杨玉环']
            console.log(arr.toString())
    
  • 数组转字符串:join方法输出数组元素,输出结果会转换成字符串;

            var arr = ['西施', '王昭君', '貂蝉', '杨玉环']
            console.log(arr.join('-'))
    
  • 数组逆序:reverse()方法 颠倒数组元素的顺序;返回值为逆序后的新数组;

            var arr = ['西施', '王昭君', '貂蝉', '杨玉环']
            console.log(arr.reverse());
    
  • 数组排序:sort()方法 可以实现数组排序;

        var arr=[23,3,56,12,44,24]
        arr.sort(function(a,b){return a-b;});//升序,从小到大
        alert(arr)
        
        arr.sort(function(a,b){return b-a;});//降序,从大到小
        alert(arr)
  • 扩充数组:concat()方法 将多个数组的元素合并为一个新的数组;

    concat()连接的是数组名,该方法不会改变现有的数组

            var arr1 = ['西施', '王昭君', '貂蝉', '杨玉环']
            var arr2=['大乔','小乔']
            var arr3=['孙尚香']
            var arr=arr1.concat(arr2,arr3)
            console.log(arr)
    
  • splice方法:删除、替换、插入元素,会更改原数组;

    第一参数为起始位置索引;

    第二参数为切取元素个数;

    第三个参数为插入元素,可选项;

            var arr = ['西施', '王昭君', '貂蝉', '杨玉环']
            var removed=arr.splice(2,1,'大乔','小乔')
            console.log(arr)
            console.log(removed)//返回切取的元素
    
  • 截取数组:slice() 切取数组的一段元素;

    切取部分作为新数组返回,不会对原数组改变。

    第一参数为起始位置索引(包含)。

    第二参数为结束位置索引,注意区分splice(不包含)。

    若省略第二个参数则直接切取到结尾

    var arr = ['西施', '王昭君', '貂蝉', '杨玉环', '大乔', '小乔']
    var removed = arr.slice(1, 3)
    console.log(arr)
    console.log(removed)
    
  • toString()/valueOf()

    toString() 把数组转换成字符串,逗号分隔每一项

    valueOf() 返回数组对象本身

8.1.3 Array对象应用

将一个字符串数组输出为|分割的形式,比如“刘备|张飞|关羽”。

function myJoin(array, seperator) {
if (array.length == 0){
return '';
}
var str = array[0];
for (var i = 1; i < array.length; i++) {
str += seperator + array[i];
}
return str;
}

var array = [6, 3, 5, 6, 7, 8, 0];
console.log(myJoin(array, '-'));
console.log(array.join('-'))

将一个字符串数组的元素的顺序进行反转。

function myReverse(arr) {
if (!arr || arr.length == 0) {
return [];
}
for (var i = 0; i < arr.length / 2; i++) {
var tmp = arr[i];
arr[i] = arr[this.length - i - 1];
arr[arr.length - i - 1] = tmp;
}
return arr;
}

var array = ['a', 'b', 'c'];
console.log(myReverse(array));
console.log(array.reverse());
8.2 Date对象

Date是JavaScript的内置对象,系统在Date对象中封装了与日期和时间相关的属性和方法。 Date使用UTC1970年1月1日0时开始经过的毫秒数来存储时间。

GMT 格林尼治时间;

UTC 国际协调时间;

January(Jan.)一月;February(Feb.)二月;March(Mar.)三月;April(Apr.)四月;May五月;June六月;July(Jul.)七月;August(Aug.)八月;September(Sep.)九月;October(Oct.)十月;November(Nov.)十一月;December(Dec.)十二月

Monday 星期一 ;Tuesday 星期二; Wednesday 星期三 ;Thursday 星期四 ;Friday 星期五; Saturday 星期六; Sunday 星期日

8.2.1 Date构造函数
// 无参数的情况下返回值为当前时间。不同浏览器显示的时间格式会有细微差异
var date= new Date();

// 必选值:year, month, day;
var date = new Date(year, month, day, hours, minutes, seconds, milliseconds);
8.2.2 Date对象方法

通过使用针对日期对象的方法,我们可以很容易地对日期进行操作。

方法名作用方法名作用
getMonth()从 Date 对象返回月份 (0 ~ 11)。setMonth()设置 Date 对象中月份 (0 ~ 11)。
getDate()从 Date 对象返回一个月中的某一天 (1 ~ 31)。setDate()设置 Date 对象中月的某一天 (1 ~ 31)。
getHours()返回 Date 对象的小时 (0 ~ 23)。setHours()设置 Date 对象中的小时 (0 ~ 23)。
getMinutes()返回 Date 对象的分钟 (0 ~ 59)。setMinutes()设置 Date 对象中的分钟 (0 ~ 59)。
getSeconds()返回 Date 对象的秒数 (0 ~ 59)。setSeconds()设置 Date 对象中的秒钟 (0 ~ 59)。

Date对象相关的字符串表示方法:

方法名作用
toSting()获取Date实例的字符串表示
toDateSting()获取Date的日期部分字符串表示
toTimeSting()获取Date的时间部分字符串表示
toLocaleString()据本地时间格式,把 Date 对象转换为字符串。

写一个函数,格式化日期对象,返回yyyy-MM-dd HH:mm:ss的形式

function formatDate(d) {
//如果date不是日期对象,返回
if (!d instanceof Date) {
return;
}
var year = d.getFullYear(),
month = d.getMonth() + 1,
date = d.getDate(),
hour = d.getHours(),
minute = d.getMinutes(),
second = d.getSeconds();
month = month < 10 ? '0' + month : month;
date = date < 10 ? '0' + date : date;
hour = hour < 10 ? '0' + hour : hour;
minute = minute < 10 ? '0' + minute:minute;
second = second < 10 ? '0' + second:second;
return year + '-' + month + '-' + date + ' ' + hour + ':' + minute + ':' +
second;
}

计算时间差,返回相差的天/时/分/秒

function getInterval(start, end) {
var day, hour, minute, second, interval;
interval = end - start;
interval /= 1000;
day = Math.round(interval / 60 / 60 / 24);
hour = Math.round(interval / 60 / 60 % 24);
minute = Math.round(interval / 60 % 60);
second = Math.round(interval % 60);
return {
day: day,
hour: hour,
minute: minute,
second: second
}
}

console.log(getInterval(new Date("2019-12-31"),new Date("2020-5-2")))
8.3 String对象

字符串是非常重要的数据类型,除了基本字符串外,JavaScript还提供了字符串的引用类型–字符串对象。

字符串对象提供了字符串检索、替换、连接等方法…

字符串的不可变

var str = 'abc';
str = 'hello';
// 当重新给str赋值的时候,常量'abc'不会被修改,依然在内存中
// 重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变
// 由于字符串的不可变,在大量拼接字符串的时候会有效率问题
8.3.1 String构造函数

可以通过new 关键字创建字符串对象

var str=”hello”; // 字符串字面量
var str=new String(); // 字符串对象

注:创建出来的类型虽说不同,但是对于内置的方法和属性都是可以使用的。 length 属性返回字符串的长度(字符数)。

8.3.2 String对象方法
方法名作用
slice(start,end)提取字符串n到m之间的片断(不包括m位置的字符串),并在新的 字符串中返回被提取的部分。
substring(star,end)提取字符串中两个指定的索引号之间的字符。大多数情况和上一 个作用相同,当参数为负值时会有不同,但这种情况较少用,不 做讨论。
substr(start,length)从起始索引号提取字符串中指定数目的字符。
split(separator,limit)把字符串分割为字符串数组。
indexOf(subString[, startIndex])检索字符串,返回某个指定的字符串值在字符串中首次出现的位 置。注意,如果查找不到会返回 -1
lastIndexOf(subString[, startIndex])返回指定字符串在字符串最后出现的位置。
replace(rgExp, replaceText)替换与正则表达式匹配的子串,并返回替换后的字符串,注意原 字符串不会改变。

需要注意的是,JavaScript 的字符串是不可变的(immutable),String 类定义的方法都不能改变 字符串的内容。返回的是全新的字符串,而不是修改原始字符串。

//把字符串中所有的o替换成!
var s = 'abcoefoxyozzopp';
var index = -1;
do {
index = s.indexOf('o', index + 1);
if (index !== -1) {
// 替换
s = s.replace('o', '!');
}
} while(index !== -1);
console.log(s);
8.4 Math对象

Math对象不是构造函数,它具有数学常数和函数的属性和方法,都是以静态成员的方式提供。

跟数学相关的运算来找Math中的成员(求绝对值,取整)。

Math 对象并不像 Date 和 String 那样是对象的类,因此没有构造函数 Math()。

方法名/属性名作用
Math.ceil(x)返回大于等于其数字参数的最小整数。
Math.floor(x)返回小于等于其数值参数的最大整数。
Math.round(x)把数四舍五入为最接近的整数。
Math.random()返回介于 0 和 1 之间的伪随机数。 注:产生的伪随机数介于 0 和 1 之间(含 0,不含 1),也就是,返回值可能为0,但总是小于1。
Math.max(x,y)返回 x 和 y 中的最高值。
Math.min(x,y)返回 x 和 y 中的最低值。
Math.abs(x)返回x的绝对值。
        function getRandmInt(min, max) {
            min = Math.ceil(min);
            max = Math.floor(max);
            return Math.floor(Math.random() * (max - min) + min);//不含最大值,含最小值
        }
        //返回一个15到30之间任意一个数值,不包括30,包括15。
        console.log(getRandmInt(15, 30))
8.5 全局对象

1、parseInt

parseInt() 函数可解析一个字符串,并返回一个整数。

2、parseFloat方法

parseFloat()函数可解析一个字符串,并返回一个浮点数。

该函数指定字符串中的首个字符是否是数字。如果是,则对字符串进行解析,直到到达数字的末端为止,然后以数字返回该数字,而不是作为字符串。

如果参数字符串的第一个字符不能被解析成为数字,则 parseFloat 返回 NaN。

3、isNaN()方法

isNaN(x):函数用于检查其参数是否是非数字值。

参数x是要检测的值,如果x是特殊的非数字值NaN(或者能被转换为这样的值),返回的值就是 true。如果 x 是其他值,则返回 false。

isNaN()函数可用于判断其参数是否是NaN,该值表示一个非法的数字(比如被 0 除后得到的结 果),如果把NaN与任何值(包括其自身)相比得到的结果均是false,所以要判断某个值是否是 NaN,不能使用 == 或 === 运算符。正因为如此,isNaN() 函数是必需的。

提示:isNaN()函数通常用于检测parseFloat()和parseInt()的结果,以判断它们表示的是否是合法的数 字。当然也可以用isNaN()函数来检测算数错误,比如用0作除数的情况。

<script>
var loginName = parseInt('amigo1121');
if(isNaN(loginName)) {
//如果loginName不是数值,执行如下语句
alert("parseInt('amigo1121')的结果是: " + loginName);
} else {
alert("parseInt('amigo1121')的结果是数值!");
}
</script>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值