2、前端开发——JavaScript基础学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/F_Felix/article/details/89102287

JS基础学习

类型转换

var s = prompt("请输入一个数字"); // 此时我们接受到的其实是一个字符串类型的
// 可以通过在pormpt前面加个"+" (正号)来进行类型转换
var s = +prompt("请输入一个数字"); // 此时取到的s就是一个数值类型的

JavaScript中的浮点数存在精度丢失的问题,比如

var a = 0.1 ,b =0.2;
console.log(a+b); //  0.3000000000000004
// 因此需要注意小数计算和比较的时候进行小数位数的保留或者尽量少用小数进行比较

运算符的优先级

在这里插入图片描述

JS数组

数组的创建方式

字面量方式

字面量:也叫直接量,指的是直接从字面上就能看出类型的量,比如11,‘abc’,true,这些值我们能够一下子看出分别是数字,字符串和布尔类型的,系统是能够直接识别这些字面量的,在JS中 [ ] 表示的是数组字面量

 // [ ] 表示的是数组字面量
var arr = [];
// 给数组中添加值
var arr1 = ['张三','李四','王五'];
var arr2 = [1,2,3,4,5,6,7];

构造函数创建数组

var arr = new Array();
// 添加数据
var arr1 = new Array('张三','李四','王五');
var arr2 = new Array(1,2,3,4,5);

数组取值赋值

var arr = ['a','b','c','d','e'];
// arr[下标]=值;
// 这个下标下有值,则覆盖原值,如果没有值添加新值
arr[2]="z";  // ['a','b','z','d','e']
arr[100] = 'D'; // 结果会导致数组的长度变成 101,中间有n个值是empty的,这样的数组是不连续的

JS变量

局部变量

在 JavaScript 函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它。(该变量的作用域是局部的)。

您可以在不同的函数中使用名称相同的局部变量,因为只有声明过该变量的函数才能识别出该变量。

只要函数运行完毕,本地变量就会被删除。

局部变量比同名全局变量的优先级高,所以局部变量会隐藏同名的全局变量。

全局变量

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

如果您把值赋给尚未声明的变量,该变量将被自动作为全局变量声明 (隐式全局变量)

carname="Volvo";

函数笔记(https://www.w3cschool.cn/umsno/umsno-yx7325wg.html

预解析

js执行代码分为两个过程:

  • 预解析过程(变量与函数提升)
  • 代码一行一行执行

预解析过程:

  1. 预解析会把所有的var声明提升到当前作用域最前面,不会提升赋值

  2. 预解析会把所有的function声明提升到当前作用域最前面,不会提升调用,如果多个函数同名,后面的函数会覆盖前面的函数。

  3. 如果遇到同名的函数和变量,函数优先。

    预解析过程:

    1. 函数优先,先提升function,后提升var
    2. 遇到重名的var会被忽略。
    3. 遇到重名的function会被覆盖。

函数提升

  1. 提升(Hoisting)是 JavaScript 默认将当前作用域提升到前面去的的行为。
  2. 提升(Hoisting)应用在变量的声明与函数的声明。
  3. 使用表达式定义函数时无法提升

函数内部的变量提升

函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部

// num不是全局变量吗?已经赋值了,为什么在fn1中会输出undefined
/* 解: 在函数fn1中有定义了num,因为函数内部也存在“变量提升”的现象
        导致num被重新定义,覆盖了全局变量的值,所以输出undefined */
var num = 10;
fn1();
function fn1() {
    console.log(num);
    var num = 20;
}

函数

函数的声明

注意点:如果同一个函数被多次定义(声明),后面的定义(声明)就会覆盖前面的定义(声明)

1 函数声明

function functionName(parameters) {        
  执行的代码        
}
// 由于函数声明不是一个可执行语句,所以不以分号结束

2、匿名函数声明

下面函数以分号结尾,因为它是一个执行语句。

var fun = function(parameters) {        
  执行的代码        
};
var fn = function(a,b) {return a*b;} // 上述函数以分号结尾,因为它是一个执行语句。
// 调用方式
console.log(fn(3,5));  //15

3、系统提供的构造函数声明Function(注:Function和function是不一样的)

最后一个参数是返回值,如果是无参函数,则就一个返回值也是可以的。

var myFunction = new Function("a", "b", "return a * b"); 
var x = myFunction(4, 3);

可以写成下面这样,在 JavaScript 中,很多时候,你需要避免使用 new 关键字。

// 匿名函数声明的方法
var myFunction = function (a, b) {return a * b} 
var x = myFunction(4, 3);

函数的使用

1、自调用函数

函数表达式可以 "自调用"。
自调用表达式会自动调用。
如果表达式后面紧跟 () ,则会自动调用。
Y不能自调用声明的函数。
通过添加括号,来说明它是一个函数表达式:
//  匿名自我调用的函数 
(function () { 
    var x = "Hello!!";      // 我将调用自己 
})();

2、直接使用

function myFunction(a, b) { 
    return a * b; 
} 
// 作为一个值使用
var x = myFunction(4, 3);
// 作为一个表达式使用
var x = myFunction(4, 3) * 2;

函数的参数

Arguments 对象

JavaScript 函数有个内置的对象 arguments 对象.

argument 对象包含了函数调用的参数数组。

通过这种方式你可以很方便的找到最后一个参数的值:

var x = findMax(1, 123, 500, 115, 44, 88);
function findMax() {
    var i, max = arguments[0];

    if (arguments.length < 2) return max;

    for (i = 0; i < arguments.length; i++) {
        if (arguments[i] > max) {
            max = arguments[i];
        }
    }
    return max;
}
console.log(x); // 500

通过值传递参数

在函数中调用的参数是函数的参数。

如果函数修改参数的值,将不会修改参数的初始值(在函数外定义)。

总结:JavaScript函数传值只是将参数的值传入函数,函数会另外配置内存保存参数值,所以并不会改变原参数的值。

var x = 1;
// 通过值传递参数
function myFunction(x) {
    x++; //修改参数x的值,将不会修改在函数外定义的变量 x
    console.log(x);
}
myFunction(x); // 2
console.log(x); // 1

通过对象传递参数

在JavaScript中,可以引用对象的值。

因此我们在函数内部修改对象的属性就会修改其初始的值。

修改对象属性可作用于函数外部(全局变量)。

var obj = {x:1};
// 通过对象传递参数
function myFunction(obj) {
    obj.x++; //修改参数对象obj.x的值,函数外定义的obj也将会被修改
    console.log(obj.x);
}
myFunction(obj); // 2
console.log(obj.x); // 2

函数的调用

函数定义作为对象的属性,称之为对象方法。

函数如果用于创建新的对象,称之为对象的构造函数。

1、作为一个函数调用

函数没有被自身的对象调用时, this 的值就会变成全局对象。在 web 浏览器中全局对象是浏览器窗口(window 对象)。该实例返回 this 的值是 window 对象

function myFunction(a, b) {
    return a * b;
}
myFunction(10, 2);           // myFunction(10, 2) 返回 20
console.log(this);  // window

2、函数作为方法调用

在 JavaScript 中你可以将函数定义为对象的方法。

var myObject = {
    firstName:"John",
    lastName: "Doe",
    fullName: function () {
        return this.firstName + " " + this.lastName;
    }
}
myObject.fullName();         // 返回 "John Doe"

this对象,拥有 JavaScript 代码。实例中 this 的值为 myObject 对象。

测试一下!修改 fullName 方法并返回 this 值:

var myObject = {
    firstName:"John",
    lastName: "Doe",
    fullName: function () {
        return this; // 函数作为对象方法调用,会使得 this 的值成为对象本身。
    }
}
 console.log(myObject.fullName());          // 返回 [object Object] (所有者对象)

3、使用构造函数调用函数

如果函数调用前使用了 new 关键字, 则是调用了构造函数。

这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象:

构造函数的调用会创建一个新的对象。新对象会继承构造函数的属性和方法。

// 构造函数:
function myFunction(arg1, arg2) {
    this.firstName = arg1;
    this.lastName  = arg2;
}
// This creates a new object
var x = new myFunction("John","Doe");
x.firstName;                             // 返回 "John"
/*
	构造函数中 this 关键字没有任何的值。
	this 的值在函数调用时实例化对象(new object)时创建。
*/

4、作为函数方法调用函数

在 JavaScript 中, 函数是对象。JavaScript 函数有它的属性和方法。

call()apply() 是预定义的函数方法。 两个方法可用于调用函数,两个方法的第一个参数必须是对象本身。

var myObject;
function myFunction(a, b) {
    return a * b;
}
myFunction.call(myObject, 10, 2);      // 返回 20
function myFunction(a, b) {
    return a * b;
}
myArray = [10,2];
myFunction.apply(myObject, myArray);   // 返回 20

函数可以调用自身,这就是递归(recursion)

function f(x){
  if(x>2){
    console.log(x);
    return f(x-1);
  }else{
    return 1;
  }
}
f(4); 
// 4
//3

逻辑运算符作取值运算(逻辑运算的短路问题)

值为false的有六类: 0 ‘’ NaN undefined null false ;除此之外的都是true;

逻辑与(&&)

var d = 12 && "hello" && undefined;
console.log(d);   // 输出 undefined

原理:

  • 取第一个为false的值,然后赋值给结果
  • 如果都为true的时候,取最后一个值

逻辑或(||)

var m = 0 || undefined ||45 ||"hello";
console.log(m);  // 输出 45;

原理:

  • 取第一个为true的值,赋值给结果
  • 如果都是false,结果取最后一个值

JS对象

创建对象的方法

对象字面量

什么是字面量之前在数组那已经讲过了,{} [] 等浏览器直接可以识别的,字面量:11 “abc” true [] {}等 ,在对象中对应的字面量是 { }

var obj = {};// 定义了一个空的对象
// 定义对象的时候并且给这个对象赋值
var obj = {
  name : "zs",
  age : 18,
  sex : true,
  sayHi : function() {
    console.log(this.name);
  }
};

内置构造函数(Object)

// 使用js自带的一个Object构造函数,定义了一个空对象
var obj = new Object(); 
// 当没有参数时,可以把()省略,定义空对象
var obj = new Object;
// 定义对象的然后赋值 语法  对象名.属性 = 值;
var obj = new Object();
obj.name = "zs";
obj.age = 18;
obj.gender = "男";
//给对象设置添加一个方法
obj.sayHi = function() {
console.log("大家好,我是"+obj.name);

工厂函数

工厂函数案例见后面

优点:可以同时创建多个对象

缺点:创建出来的没有具体的类型,都是object类型的

自定义构造函数

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

  1. 构造函数首字母要大写(推荐做法)。
  2. 构造函数要和new一起使用才有意义。
  3. 构造函数的作用是用于实例化一个对象,即给对象添加属性和方法

new在执行时会做四件事情

new会做4件事情
1. new会创建一个新的空对象,类型是Teacher
2. new 会让this指向这个新的对象
3. 执行构造函数  目的:给这个新对象加属性和方法
4. new会返回这个新对象

对象的使用

1、点语法

// 获取对象属性的语法:
    // 对象.属性:对象的属性
    // 1. 如果有这个属性,直接返回属性值
    // 2. 如果没有这个属性,返回undefined
// 设置对象的属性的语法
    // 对象.属性 = 值
    // 1. 如果对象有这个属性,修改这个属性
    // 2. 如果对象没有这个属性,添加这个属性

2、[ ] 语法(关联数组法)

//获取对象属性
    // 对象['下标']   :把对象的属性当成下标
//设置对象的属性
    // 对象['下标'] = "值";

点语法和[ ] 语法两者有时候可以互相转换使用,但是使用比较多的是点语法,因为使用起来比较简单,但是有时候必须使用[ ] 语法,比如下面对象的遍历 for……in

var obj = {};
for (var i = 0; i < 10; i++) {
    obj[i] = i * 2;
}
for(var key in obj) {
    console.log(key + "==" + obj[key]);
}

附:

工厂函数和构造函数的区别

工厂函数和构造函数,工厂函数有return返回值,但是不需要new,打印工厂函数输出的是object
构造函数需要用new,并且没有返回值,通过new来获取返回值的,打印构造函数输出的是构造函数这个对象

构造函数

 function Teacher(name, age, sex) {
     this.name = name;
     this.age = age;
     this.sex = sex;
     this.sayHi = function () {
         console.log("hello world!");
     }
     console.log(this);  //  Teacher
 };

var tec = new Teacher("zs", "19", true);
tec.sayHi();

工厂函数:

//工厂函数:
function createStudent(name, age, sex) {
    var stu = {};  // 实质上就是 = new Object();
    stu.name = name;
    stu.age = age;
    stu.sex = sex;
    stu.sayHi = function() {
        console.log("大家好,我是"+this.name);
    }
    return stu;
}
var stu1 = createStudent("zs", 18, "男");
stu1.sayHi();
console.log(stu1);    //Object

内置对象

Math对象

随机数(★)

Math.random();//返回一个[0,1)之间的数,能取到0,取不到1

如果求0~3(即0,1,2)这三个数的随机,让取到这三个数的几率一样

ParseInt(Math.random()*3)  //因为这样就是0~2.999999999999999的数,取整后就是0,1,2

Date对象

时间戳

var date = +new Date();//1970年01月01日00时00分00秒起至现在的总毫秒数
//思考
//1. 如何统计一段代码的执行时间?

//2. 倒计时,计算距离下课还有多长时间

补充一个倒计时的例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        span {
            color: #e92322;
            font-size: 30px;
        }
    </style>
</head>
<body>
    <h2>距离五一劳动节还有<span id="time"></span></h2>
    <script>
        function reverseTime(){
            var targetDate = new Date("2019-05-01 00:00:00");
            var now = new Date();
            var time = document.getElementById("time");
            var millSec = targetDate - now;
            var sec = millSec / 1000;
            var second = parseInt(sec) % 60; 	//足60秒的就是一分钟,取剩余的秒数
            var minute = parseInt(sec / 60) % 60;  //足60分钟就是一小时,取剩余的分钟数
            var hours = parseInt(sec / 3600) % 24;  // 足24小时的就是一天,取不足24小时的
            var day = parseInt(sec / 86400);
            time.innerHTML = day + " 天 " + hours + " 小时 " + minute + " 分钟 " + second + '秒钟';
        }
        window.onload = setInterval("reverseTime()", 200);
    </script>
</body>
</html>

Array 对象

array.join(separator)  //将数组的值拼接成字符串
array.push();//从后面添加元素,返回新数组的length
array.pop();//从数组的后面删除元素,返回删除的那个元素
array.unshift();//从数组的前面的添加元素,返回新数组的长度
array.shift();//从数组的最前面删除元素,返回删除的那个元素
array.reverse();//翻转数组
array.sort();//数组的排序,默认按照字母顺序排序
arr.concat() //数组合并,不会影响原来的数组,会返回一个新数组。
//数组切分,复制数组的一部分到一个新数组,并返回这个数组原来的数组不受影响,包含begin,不包含end
arr.slice();
//删除数组或者增加数据元素,start:开始位置  deleteCount:删除的个数  items:替换的内容
arr.splice(start,deletCount,items);
//indexOf方法用来查找数组中某个元素第一次出现的位置,如果找不到,返回-1
array.indexOf(search, [fromIndex])//astIndexOf()从后面开始查找数组中元素出现位置,如果找不到,返回-1
array.lastIndexOf(search, [fromIndex]);

上面一些简单的就不多说了,下面补充一些例子

// 获取数组中每个元素出现的次数
var arr = ["c", "a", "z", "a", "x", "a", "a", "z", "c", "x", "a", "x"]
// 找到数组中每一个a出现的位置
var start = 0;
while (start != -1) {
    console.log(arr.indexOf("a", start));
    start = arr.indexOf("a", arr.indexOf("a", start) + 1);
    console.log(start);
}

// 数组去重,返回一个新数组
var newArr = [];
for (var i = 0; i < arr.length; i++) {
    // console.log(newArr.indexOf(arr[i]);
    if (newArr.indexOf(arr[i]) == -1) {
        newArr.push(arr[i]);
    }
}
console.log(newArr);
// 获取数组中每个元素出现的次数
var obj = {};
for (var i = 0; i < arr.length; i++) {
    if (obj[arr[i]] === undefined) {
        obj[arr[i]] = 1;
    } else {
        obj[arr[i]]++;
    }
}
console.log(obj);

Array 对象中的sort方法

var a = new Array(3, 5, 7, 1, 8, 2, 9, 3, 34, 23, 76, 64, 18);
console.log("排序后的a数组:");
console.log(a.sort(s2b));

function s2b(a, b) {
    // return b - a ; // 大到小 
     return a - b; // 小到大
}
// 方便理解可以这么认为,当return a- b;表示执行的是下面第一个if这种情况,如果return b-a; 表示执行的是下面第二种的if情况
// 解释为什么a - b 是从小到大
if (a > b) {
    return 1;  // 此处判断的是a大于b,并且返回的是一个 >=0 的数 ,那么就是执行从小到大的规则,
} else {
    return -1;
}
以上述的数组为例,a 和 b 分别表示的是两个数字(这里a 表示前面的数,b 表示后面的数,这是固定的)
假设a = arr[0] //3
b = arr[1] //5
执行到函数s2b()时,会判断 a > b 吗,如果大于,返回一个 >=0 的数,表示需要交换位置,这样大的数字就会放后面,实现了从小到大的排序,如果 不大于,则保持当前的顺序,不交换位置
// 解释为什么 b - a 是从大到小
if(b > a){ 
    return 1; // 此处判断的是b大于a,并且返回的是一个 >=0 的数 ,那么就是执行从大到小的规则,
}else{
    return -1;
}
以上述的数组为例,a 和 b 分别表示的是两个数字(这里a 表示前面的数,b 表示后面的数,这是固定的)
假设a = arr[0] //3
b = arr[1] //5
执行到函数s2b()时,会判断b > a 吗,如果大于,返回一个 >=0 的数,表示需要交换位置,b > a 互换位置后,大的数字提前了,所以就实现了从大到小的排序,否则不交换位置.
上述两种其实可以互相转换的
if (a > b) {
    return 1;  
} else {
    return -1;
}
上面这种情况下是从小到大排序,我修改成下面这种情况就是从大到小排序
if (a > b) {
    return -1; 
} else {
    return 1;
}
// sort还可以像下面这样使用
//将学生数组按照年龄从小到大排列
var arr2 = [
    {name: 'zs', age: 18, score: 100},
    {name: 'ls', age: 28, score: 50},
    {name: 'ww', age: 88, score: 9},
    {name: 'zl', age: 5, score: 88}
];
arr2.sort(function(a, b) {
    return b.age - a.age;
})
console.log(arr2);

关键看的是到底是a - b 返回大于等于0 的值,还是b - a 返回大于等于0 的值,这就决定了是从小到大还是从大到小

基本包装类型

  • js为了我们使用方便,给简单类型提供了对应的复杂类型,复杂类型有属性方法。
  • 当我们调用简单类型的属性和方法的时候。js内部会自动把简单类型给你变成复杂类型。结束后,再把复杂类型变回了简单类型,这个过程对于我们是透明的。
  • 基本包装类型,当我们使用基本类型调用属性和方法的时候,js会自动包装成复杂类型。结束后自动变成简单类型。
var str = “abc”;
var result = str.indexOf(“a”);
//执行indexof时发生了三件事情
1. 把简单类型转换成复杂类型:var s = new String(str);
2. 调用包装类型的indexOf方法:var result = s.indexOf(“a”);
3. 销毁刚刚创建的复杂类型

Number对象

toFixed(2)//保留2位小数

String对象

去除空白

trim();//去除字符串两边的空格,内部空格不会去除

字符串拼接与截取

//字符串拼接
//可以用concat,用法与数组一样,但是字符串拼串我们一般都用+

//字符串截取的方法有很多,记得越多,越混乱,因此就记好用的就行
//slice :从start开始,end结束,并且取不到end。
//substring :从start开始,end结束,并且取不到end
//substr : :从start开始,截取length个字符。

字符串替换

replace(searchValue, replaceValue)
//参数:searchValue:需要替换的值    replaceValue:用来替换的值

猜你喜欢

转载自blog.csdn.net/F_Felix/article/details/89102287