JavaScript---基础语法(二)

对象

除了5种基本的数据类型(String 字符串、Number 数值、Boolean 布尔值、Undefined 未定义、Null 空值),其它的全都是对象(object)。

基本数据类型都是单一的值, 比如: "itlike" , 123 , true等, 值和值之间没有任何的联系。

对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。

对象分类

对象分类

说明

内建对象

由ES标准中定义的对象,在任何的ES的实现中都可以使用,比如:String Number Boolean Function Object Math ....

宿主对象

由JS的运行环境提供的对象,现在主要指由浏览器提供的对象,比如: BOM对象, DOM对象

自定义对象

自己创建的对象,比如: Person, Dog, ....

常见的创建对象的方式:

(1)对象字面量---一般用于数据传递

使用对象字面量,可以在创建对象时,直接指定对象中的属性。【var 对象 = {属性名:属性值,属性名:属性值....};】

对象字面量的属性名可以加引号也可以不加,建议不加, 如果要使用一些特殊的名字,则必须加引号。

属性名和属性值是一组一组的名值对结构,名值之间使用:连接,多个名值对之间使用,隔开

  var person = {
      name: "xbd",
      age: 20,
      friends: ["dgou", "tong"],
      eat: function() {
          console.log("eat");
      }
  };
  console.log(typeof person); //object
  console.log(person);
  person.name = "张三"; //修改name属性
  console.log(person.name);
  person.eat();

 // 以下对数组进行遍历的方式不适用于对象遍历。
    /*for(var i=0; i<person.length; i++){
        console.log(person[i]);
    }*/

 // 遍历对象
  for (var key in person) {
      console.log(key);
      console.log(person[key]);
  }

运行结果:

(2)new Object()创建对象---缺点:无法量厂

构造函数是专门用来创建对象的函数。使用new关键字调用的函数,可以被称为构造函数(constructor)【var obj = new Object();】

  var obj = new Object();
   // 属性
   obj.name = "xbd";
   obj.age = 18;
   obj.sex = "female";
   console.log(typeof obj)
   console.log(obj)

运行结果:

(3)工厂函数创建对象

new Object()---new后面调用函数,我们称为构造函数。Object() 我们把它视为一个构造函数,构造函数的本质就是一个函数,只不过构造函数的目的是为了创建新对象,为新对象进行初始化(设置对象的属性)。

通过工厂方法可以大批量的创建对象,使用工厂方法创建的对象,使用的构造函数都是Object,所以创建的对象都是Object这个类型,就导致我们无法区分出多种不同类型的对象。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <script>
    function Dog(name, age, dogFriends) {
        var d = new Object(); //原料
        // 属性
        d.name = name;  //加工
        d.age = age;
        d.dogFriends = dogFriends;
        d.doSomething = function() {
            console.log("do something")
        };
        return d;  //出厂
    }

    var d1 = Dog("小花", 1);
    var d2 = Dog("大花", 5, ["大大", "小小"]);
    console.log(d1);
    d1.doSomething();
    console.log(d2);
    console.log(d1 === d2);
    </script>
</body>

</html>

在浏览器中打开,点击f12,查看Console:

(4)自定义构造函数

构造函数就是一个普通的函数,创建方式和普通函数没有区别,  不同的是构造函数习惯上首字母大写。

构造函数和普通函数的区别就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。

构造函数执行流程:

  • 1. 立刻创建一个新的对象
  • 2. 将新建的对象设置为函数中this, 在构造函数中可以使用this来引用新建的对象
  • 3. 逐行执行函数中的代码
  • 4. 将新建的对象作为返回值返回
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <script>
    // 1. 构造函数
    function Dog(name, age, dogFriends) {
        // 1.1 属性
        this.name = name;
        this.age = age;
        this.dogFriends = dogFriends;

        // 1.2 方法
        this.eat = function(someThing) {
            console.log(this.name + "在吃" + someThing);
        };
        this.run = function(someWhere) {
            console.log(this.name + "跑" + someWhere);
        }
    }

    // 小狗
    var smallDog = new Dog("小花", 1);
    smallDog.age = 2;
    console.log(smallDog);

    smallDog.eat("奶");
    smallDog.run("广场");

    // 大狗
    var bigDog = new Dog("大花", 5, ["大大", "小小"]);
    console.log(bigDog);

    console.log(bigDog === smallDog);
    </script>
</body>

</html>

在浏览器中打开,点击f12,查看Console:

属性和方法:

属性:一般是名词,用来描述事物的特征。如果一个变量属于一个对象所有,那么该变量就可以称之为该对象的一个属性。

方法:动词,描述事物的行为和功能。如果一个函数属于一个对象所有,那么该函数就可以称之为该对象的一个方法。

对象的属性值可以是任何的数据类型,也可以是个函数。如果一个函数作为一个对象的属性保存,那么我们称这个函数时这个对象的方法, 调用这个函数就说调用对象的方法(method)

遍历对象所有属性:for ... in 语句【for(var 变量 in 对象){ }】,对象中有几个属性,循环体就会执行几次。

new关键字:

一般和构造函数配合使用。构造函数首字母必须大写,构造函数必须和new一起使用。

new做了哪些事?

  1. new先在内存中创建一个新的空对象;
  2. new会让this指向这个新对象;
  3. 执行构造函数,给这个新对象添加属性和方法;
  4. 返回这个新对象。

this关键字:

解析器在调用函数每次都会向函数内部传递进一个隐含的参数, 这个隐含的参数就是this,this指向的是一个对象 , 这个对象我们称为函数执行的上下文对象。

根据函数的调用方式的不同,this会指向不同的对象。

  • (1)普通函数执行,以函数的形式调用时,this永远都是window。
  • (2)如果函数作为一个对象的方法,以方法的形式调用时,this就是调用方法的那个对象。
  • (3)当以构造函数的形式调用时,this就是新创建的那个对象,。
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <script>
    //1.普通函数执行
    var str = "aaa"

    function func() {
        console.log(this)
        console.log(this.str)
    }
    func();
    console.log("====分割线===")
    //2.对象
    var obj = {
        name: "xbd",
        func: function() {
            console.log(this)
            console.log(this.name)
        }
    }
    obj.func();
    console.log("====分割线===")
    //3.构造函数
    function Func() {
        this.name = "xbd";
        this.age = 12;
        console.log(this);
        console.log(this.name)
    }
    new Func();
    </script>
</body>

</html>

在浏览器中打开,点击f12,查看Console

基本类型和引用类型在堆栈中的表示?

JS中的变量都是保存到栈内存中的,基本数据类型的值直接在栈内存中存储,值与值之间是独立存在,修改一个变量不会影响其他的变量。

对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响。

比较两个基本数据类型的值时,就是比较值。比较两个引用数据类型时,比较的是对象的内存地址,如果两个对象是一模一样的,但是地址不同,它也会返回false。


函数

定义:函数是一个对象,函数是可以重复执行的代码块;是完成特定功能的一段代码;使用typeof检查一个函数对象时,会返回function

作用:因为一部分代码使用次数可能会很多,所以封装起来,需要的时候调用就可以了。

特点:(1)封装到函数中的代码不会立即执行(2)函数中的代码会在函数调用的时候执行(3)调用函数 语法:函数对象()(4)调用函数时,函数中封装的代码会按照顺序执行。

函数声明的3种方式:

函数声明方式

function add(num1,num2){

 return num1+num2;

  }

函数前后均可调用,作用域提升:函数提升

函数表达式声明方式

var add= function(num1,num2){

  return num1+num2;

                  };

必须在函数后调用,作用域提升:变量提升

 

使用Function构造函数

var add = new Function('num1','num2','return num1+num2');

不推荐使用,  主要用于面向对象时理解"函数就是对象,  函数名就是指针"这一概念

JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面。

// 使用函数声明方式,可以在任意地方调用函数,add函数提升到最前面
// function add(a, b) {
//     return a + b;
// }

// 使用函数表达式声明方式,必须在该函数后进行调用。因为只是add变量提升到最前面。
var add = function(a, b) {
    return a + b;
}
console.log(add(1, 3));

函数的参数:

参数的作用:为了增强函数的功能性和函数的可拓展性,便于交互。

形参:形式上参与运算的变量,无实际值,为实参占位置,就像一个躯壳一样。【function add(a,b){}  //a,b是形参,占位用,函数定义时形参无值】

实参:实际参与运算的变量。形参为他占位置,真实参与运算的变量。add(x, y); //x, y实参,有具体的值,会把x,  y复制一份给函数内部的a和b,函数内部的值是复制的新值,无法修改外部的x,y】

注意:在其它语言中实参个数必须和形参个数一致,但是JavaScript中没有函数签名的概念,实参个数和形参个数可以不相等。

函数使用注意:

  • 在调用函数时,可以在()中指定实参,  实参将会赋值给函数中对应的形参。
  • 调用函数时解析器不会检查实参的类型,   所以开发中一般需要对参数进行类型的检查。
  • 函数的实参可以是任意的数据类型。
  • 调用函数时,解析器不会检查实参的数量, 多余实参不会被赋值,  如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined。

arguments对象

包含了传入函数中的所有参数,  arguments并不是一个数组,只是与数组相似,  除了拥有length属性,数组的所有属性和方法都不具备。

arguments对象还有一个名叫callee的属性,  该属性是一个指针,  指向拥有这个arguments对象的函数;

 function sum(num1, num2) {
     // arguments对象
     console.log(arguments);
     var value = 0;
     for (var i = 0; i < arguments.length; i++) {
         value += arguments[i];
     }
     console.log("所有数的总和为:", value);
     console.log("arguments.length=", arguments.length);
     console.log("sum.length=", sum.length);
 }

 sum(10, 20, 30);

执行结果

函数返回值(return)

当一个函数被调用,通常会从函数的开始执行到结束。如果想提前结束该函数的执行可以使用return语句,return语句后面的所有语句将永远不会执行。一般return用于返回结果。

注意:如果函数没有显示的使用 return语句 ,那么函数有默认的返回值:undefined;如果函数使用 return语句,那么跟在return后面的值,就成了函数的返回值;如果函数使用 return语句,但是return后面没有任何值,那么函数的返回值也是:undefined;推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。

匿名函数

没有命名的函数【function () {}】

作用

(1)用在绑定事件的时候

document.onclick = function () {
        alert(1);
 }

(2)定时器

setInterval(function () {
        console.log(444);
},1000);

(3)函数定义完,立即被调用,这种函数叫做立即执行函数,立即执行函数往往只会执行一次

(function(num1,  num2){
	console.log("mum1 = "+ num1);
	console.log("num2 = "+ num2);
})(2, 5);

回调函数:

回调函数就是一个通过函数调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

 function fn(num1, num2, operation) {
     return operation(num1, num2);
 }

 //定义加减乘除
 function add(a, b) {
     return a + b;
 }

 function sub(a, b) {
     return a - b;
 }

 function mul(a, b) {
     return a * b;
 }

 function del(a, b) {
     return a / b;
 }

 console.log(fn(10, 2, add));
 console.log(fn(10, 2, sub));
 console.log(fn(10, 2, mul));
 console.log(fn(10, 2, del));

回调函数经典案例:求Fibonacci的第n个数1 1 2 3 5 8 13 21...

function f1 (n) {
    if (n == 1) return 1;
    if (n == 2) return 1;
    return f1(n-1) + f1(n-2);
}

    console.log(f1(5));

回调函数经典案例:求n个数的累加

function getSum (n) {
   if (n == 1) { return 1;}
    return n + getSum(n - 1);
}
console.log(getSum(100));

注意:执行以下代码,输出【NaN】,因为【sum(10)】的两个参数分别是10和undefined,10+undefined=NaN

 function sum(num1, num2) {
  console.log(num1 + num2);
   
    }

sum(10);

变量的作用域:

块级作用域:在其它语言中,任何一对花括号中的语句都属于一个块,在这之中定义的所有变量在代码块外都是不可见的。

全局变量:定义在script或者不属于某个函数的变量

局部变量:定义在函数内部的变量

注意:函数内部可以访问到该函数所属的外部作用域的变量(作用域链);不使用var声明的变量是全局变量;变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁

变量提升:

  • 变量提升:定义变量的时候,变量的声明会被提升到作用域的最上面,变量的赋值不会提升。
  • 函数提升:JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面。

笔试题

var num = 10;
 fun();

 function fun() {
     console.log(num);
     var num = 20;
 }

运行代码输出结果【undefined】由于fun()函数中已声明了【var num=20】执行到【console.log(num)】时,函数内部的变量声明被提升,赋值未被提升。局部变量, 先在函数内部的作用域找变量num,如果找到则使用,如果找不到再去父级作用域找num变量。

var a = 18;
 f1();

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

运行代码输出结果

数据类型和内存分析:

  • 栈区(stack)-----由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
  • 堆区(heap) — 一般由程序员分配释放, 若开发者不释放,程序结束时可能由OS回收 。

简单(基本)数据类型:Number、String、Boolean、Undefined、Null,直接存储值,存放在栈内存中,占据固定大小的空间,

是按值来访问的。

复杂(引用)数据类型:Object、Array、Date.....,存放在堆内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置。每个空间大小不一样,要根据情况开进行特定的分配。当我们需要访问引用类型的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。栈内存中存放地址指向堆内存中的对象。是按引用访问的。

基本类型与引用类型最大的区别实际就是传值与传址的区别。

数组

简单(基本)数据类型只能存储一个值,想要存储多个值时可以使用数组。 数组是一种复杂(引用)数据类型, 属于对象。它和普通对象功能类似,也是用来存储一些值的。不同的是普通对象是使用字符串作为属性名的,而数组时使用数字来作为索引操作元素。数组的存储性能比普通对象要好,在开发中我们经常使用数组来存储一些数据。数组存储的数据可以是任何类型(数字、字符、布尔值等),但一个数组中应该只存一种类型的变量。

数组创建:

(1)使用 Array 构造函数创建数组

  • 创建一个空数组【var arr=new Array();】
  • 创建一个长度为10的数组【var arr=new Array(10);】
  • 创建包含数字/字符串的数组【var arr=new Array(12, 5, 8, 9);】【var arr=new Array(“xiao”,"cx");】

(2)使用数组字面量创建数组

  • 创建一个空数组【var arr=[  ];】
  • 创建包含数字/字符串的数组【var arr=[12, 5, 8, 9];】【var arr=[“xiao”,"cx"];】

以上两种数组定义方式没有任何差别,[  ]的性能略高,因为代码短

属性:length--既可以获取,又可以设置【console.log(arr.length)】;可以通过修改数组的长度来改变数组中元素的个数,如果改小了,数组从后面删除元素。(伪数组的长度可以修改,但是不能修改里面的元素)

获取数组中的元素:数组中的指定元素 = 数组名[索引值];数组的索引代表的是数组中的元素在数组中的位置,从0开始。如果获取数组中元素是,数组名[索引值],没有指定索引(元素没那么多),系统不报错,而是给定值为undefined;

方法:

添加

push(元素),从尾部添加,返回修改后数组的长度;

unshift(元素),从头部添加,返回修改后数组的长度。

var arr=[1,2,3];

console.log(arr.push(5));//4

arr.unshift(5);

删除

pop(),从尾部弹出,返回移除的项;

shift(),从头部弹出,返回删除元素的值

var arr=[1,2,3];

arr.pop();

arr.shift();

排序

sort([比较函数]),排序一个数组、字符串数组、数字数组

ar arr=['float', 'zindex', 'xy', 'absolute', 'blue', 'leo'];

arr.sort();

 

var arr=[96, 8, 12, 72, 33, 118];

arr.sort(function (num1, num2){

return num1-num2;//从小到大排序

});

 

注意【return num1-num2;】改为【return num2-num1;】则为从大到小排序。

查找位置

indexOf() ---接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的开头(位置 0)开始向后查找。 --arr.indexOf(4)

lastIndexOf()---接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的末尾开始向前查找。--arr.lastIndexOf(4,4)

转换类

reverse()---翻转数组项的顺序--arr.reverse()

concat(数组2)---连接两个数组--arr1.concat(arr2)

join(分隔符)---用分隔符,组合数组元素,生成字符串

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

alert(arr.join(':')); //1:2:3:4

字符串split

插入、删除

splice

 

(1)中间删除:splice(开始,长度)--arr.splice(2, 3);

(2)中间插入:splice(开始, 长度,元素…)--arr.splice(5, 0, 'a', 'b', 'c');先删除,后插入

(3)替换:splice(开始, 长度, 元素…)--arr.splice(1, 2, 'a', 'b');

注意:区别于slice()---slice() 方法可从已有的数组中返回选定的元素.arr.slice(start,end)--返回一个新的数组,包含从 start 到 end (不包括该元素)的 arr 中的元素

(4)清空数组:arr.splice(0);

遍历

forEach()---这个方法只支持IE8以上的浏览器, 所以如果需要兼容IE8,则不要使用forEach,  还是使用for循环来遍历。

forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。forEach()方法需要一个函数作为参数,数组中有几个元素, 函数就会执行几次,每次执行时,浏览器会将遍历到的元素以实参的形式传递进来,我们可以来定义形参,来读取这些内容。浏览器会在回调函数中传递三个参数:当前正在遍历的元素,当前正在遍历的元素的索引,正在遍历的数组

arr.forEach(function(value , index , obj){

  console.log(value);

});

【    var arr = [1, "deef", 5, 30, "dd"];

    arr.forEach(function(value, index) {

        console.log(index + ":" + value);

    });】

其他

 

 

map() 方法“映射”,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。

【   var arr = [1, 3, 5];

    var arr2 = arr.map(function(value, index) {

        return value * value + 1;

    });

    console.log(arr2); //[2,10,26]】

filter() “过滤”功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组。

【 var arr = [1, 2, 6, 8, 9, 10, 11];

    var arr2 = arr.filter(function(value, index) {

        return value % 2 === 0 || value > 9;

    });

    console.log(arr2); //[2,6,8,10,11]】

every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。如果所有元素都满足条件,则返回 true。

【  var arr = [11, 2, 3, 4, 15];

    var result = arr.every(function(value, index) {

        return value < 10;

    });

    console.log(result);//false

some() 方法用于检测数组中的元素是否满足指定条件(函数提供),如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。如果没有满足条件的元素,则返回false

【var arr = [31, 25, 36, 34, 13];

    var result = arr.some(function(value, index) {

        return value < 20;

    });

console.log(result); //true

示例1.求一组数中的最大值和最小值,以及所在位置

 // 1. 定义变量
    var array = [11, 23,-34,-11,55];
    var maxValue = array[0], minValue = array[0]; // 最大值 和 最小值
    var maxIndex = 0, minIndex = 0; // 最大索引 和 最小索引

    // 2. 遍历数组
    for(var i=1; i<array.length; i++){
        // 如果数组中的元素大于我们定义的初始值
        if(array[i] > maxValue){
            // 把这个元素赋值给最大值, 并把索引改变
            maxValue = array[i];
            maxIndex = i;
        }

        if(array[i] < minValue){
            minValue = array[i];
            minIndex = i;
        }
    }

    console.log("最大值为:",maxValue,"它的索引值是:",maxIndex);
    console.log("最小值为:",minValue,"它的索引值是:",minIndex);

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值