JavaScript基础3
作用域
作用域:变量可以起作用的范围。
全局变量和局部变量
- 全局变量
在任何地方都可以访问到的变量就是全局变量,对应全局作用域 - 局部变量
只在固定的代码片段内可以访问到的变量,最常见的例如函数的内部。对应局部作用域(函数作用域)
不使用var声明的变量是全局变量,不推荐使用
变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁
块级作用域
任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域
将这样的所有作用域列出来,可以有一个结构:函数内指向函数外的链式结构,就称作作用域
// 案例1:
function f1() {
function f2() {
}
}
var num = 456;
function f3() {
function f4() {
}
}
// 案例2
function f1() {
var num = 123;
function f2() {
console.log(num);
}
f2();
}
var num = 456;
f1();
预解析
JavaScript代码的执行是由浏览器中的JavaScript解析器来执行。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程
预解析过程:
- 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值
- 把函数的声明提升到当前作用域的最前面,只会提升声明,不会调用
- 先提升var,再提升function
JavaScript的执行过程
// 案例1
var a = 25;
function abc() {
alert(a);
var a = 10;
}
abc();
// 案例2
console.log(a);
function a() {
console.log('aaaaa');
}
var a = 1;
console.log(a);
变量提升
- 变量提升
定义变量的时候,变量的声明会被提升到作用域的最上面,变量的赋值不会提升 - 函数提升
JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面
// 1、-----------------------------------
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
//2、-----------------------------------
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
// 3、-----------------------------------
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);
}
<script>
var num = 12; //全局作用域 0级作用域链
function f1() {
num = 15; // 局部作用域 1级作用链
function f2() {
console.log(num);// 局部作用域 1级作用链
}
f2();
}
f1();
console.log(num);
</script>
对象
JavaScript中的对象其实就是生活中对象的一个抽象
JavaScript的对象是无序属性的集合,其属性可以包含基本值、对象或函数。对象就是一组没有顺序的值。我们可以把JavaScript中的对象想象成键值对,其中值可以是数据和函数。
对象行为和特征
特征***属性 行为-----方法
- 对事物的特征在对象中用属性来表示。
- 事物的行为在对象中用方法来表示。
对象创建方式
字面量:11 ‘abc’ true [] {} 等
var o = {
name: 'zs,
age: 18,
sex: true,
sayHi: function () {
console.log(this.name);
}
};
newObject()创建对象
var person = new Object();
person.name = 'zs';
person.age = 18;
person.sayHi: function () {
console.log(this.name);
}
工厂函数创建对象
function createPerson(name, age, job) {
var person = new Object();
person.name = name;
person.age = age;
person.job = job;
person.sayHi = function(){
console.log('Hello,everyBody');
}
return person;
}
var p1 = createPerson('张三', 22, 'actor');
- 自定义构造函数
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayHi = function(){
console.log('Hello,everyBody');
}
}
var p1 = new Person('张三', 22, 'actor');
属性和方法
如果一个变量属于一个对象所有,那么该变量就可以称之为该对象的一个属性,属性一般是名词,用来描述事物的特征
如果一个函数属于一个对象所有,那么该函数就可以称之为该对象的一个方法,方法是动词,描述事物的行为和功能
new关键字
构造函数,是一种特殊的函数。主要用来字创建对象时初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
- 构造函数用于创建一类对象,首字母要大写。
- 构造函数要和new一起使用才有意义。
new在执行时会做四件事 - new会让内存中创建一个空对象
- new会让this指向这个新对象
- 执行构造函数 目的:给这个新对象加属性和方法
- new会返回这个新对象
this详解
JavaScript中的this指向:
- 函数在定义的时候this是不确定的,只有在调用的时候才可以确定
- 一般函数直接执行,内部this指向全局window
- 函数作为一个对象的方法,被该对象所调用,那么this指向的是该对象
- 构造函数中的this其实是一个隐式对象,类似一个初始化的模型,所有方法和属性都挂载到这个隐式对象身上,后通过new关键字来调用,从而实现实例化
对象的使用
遍历对象的属性
通过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]);
}
删除对象的属性
function fun() {
this.name = 'mm';
}
var obj = new fun();
console.log(obj.name); // mm
delete obj.name;
console.log(obj.name); // undefined
简单类型和复杂类型的区别
基本类型又叫做值类型,复杂类型又叫做引用类型
值类型:简单数据类型,基本数据类型,在存储时,变量中存储的是值本身,因此叫做值类型。
引用类型:复杂数据类型,在存储是,变量中存储的仅仅是地址(引用),因此叫做引用数据类型。
- 堆和栈
堆栈空间分配区别:
- 栈(操作系统):由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
- 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收,分配方式到是类似于链表。
注意:JavaScript中没有堆和栈的概念,此处我们用堆和栈
基本类型在内存中的存储
复杂类型在内存中的存储
基本类型作为函数的参数
复杂类型作为函数的参数
内置对象
JavaScript中的对象分为3种:内置对象、浏览器对象、自定义对象
JavaScript提供多个内置对象:Math/Array/Number/String/Boolean
对象只有带有属性和方法的特殊数据类型
Math对象
Math不是构造函数,它具有数学常数和函数的属性和方法,都是以静态成员的方式提供
跟数学相关的运算来找Math中的成员(求绝对值、取整)
演示:Math.PI、Math.random()、Math.floor()/Math.ceil()、Math.round()、Math.abs() 、Math.max()
Math.PI // 圆周率
Math.random() // 生成随机数
Math.floor()/Math.ceil() // 向下取整/向上取整
Math.round() // 取整,四舍五入
Math.abs() // 绝对值
Math.max()/Math.min() // 求最大和最小值
Math.sin()/Math.cos() // 正弦/余弦
Math.power()/Math.sqrt() // 求指数次幂/求平方根
案例:
<script>
// - 求10-20之间的随机数 [10, 20] 整数
// Math.random() -> [0, 1) 小数
// Math.random() * 20 -> [0, 20) 包含小数部分
// Math.random() * (20 - 10) -> [0, 10) 包含小数部分
// Math.random() * (20 - 10) + 10 -> [10, 20) 包含小数部分
// 求10-20之间的随机数
var a = 10;
var b = 20;
// math.random() 范围在[0,1)
console.log(parseInt(Math.random() * (b - a) + a));
// 随机生成颜色RGB [0,255]
function randomRgb(min, max) {
var color1 = Math.floor(Math.random() * (max - min + 1) + min);
var color2 = Math.floor(Math.random() * (max - min + 1) + min);
var color3 = Math.floor(Math.random() * (max - min + 1) + min);
return 'rgb(' + color1 + ',' + color2 + ',' + color3 + ')';
}
// 点击按钮调用随机生成颜色方法
function fn() {
var a = randomRgb(0, 255);
// 改变body的背景
document.body.style.backgroundColor = a;
}
console.log(a);
// 模拟min()和max()
var MyMath = {
max: function () {
var max = arguments[0];
for (let i = 1; i < arguments.length; i++) {
if (max < arguments[0]) {
max = arguments[i];
}
}
return max;
}
}
console.log(MyMath.max(20, 20, 30, 40))
</script>
math不是构造函数,静态成员直接math.random() date是构造函数需要new date()
Date对象
创建Date实例用来处理日期和时间。Date对象基于1970年1月1日。
// 获取当前时间,UTC世界时间,距1970年1月1日(世界标准时间)起的毫秒数
var now = new Date();
console.log(now.valueOf()); // 获取距1970年1月1日(世界标准时间)起的毫秒数
Date构造函数的参数
1. 毫秒数 1498099000356 new Date(1498099000356)
2. 日期格式字符串 '2015-5-1' new Date('2015-5-1')
3. 年、月、日…… new Date(2015, 4, 1) // 月份从0开始
//获取日期的毫秒形式
var now = new Date();
// valueOf用于获取对象的原始值
console.log(date.valueOf())
// HTML5中提供的方法,有兼容性问题
var now = Date.now();
// 不支持HTML5的浏览器,可以用下面这种方式
var now = + new Date(); // 调用 Date对象的valueOf()
//日期格式化方式
toString() // 转换成字符串
valueOf() // 获取毫秒值
// 下面格式化日期的方法,在不同浏览器可能表现不一致,一般不用
toDateString()
toTimeString()
toLocaleDateString()
toLocaleTimeString()
//获取日期指定部分
getTime() // 返回毫秒数和valueOf()结果一样,valueOf()内部调用的getTime()
getMilliseconds()
getSeconds() // 返回0-59
getMinutes() // 返回0-59
getHours() // 返回0-23
getDay() // 返回星期几 0周日 6周6
getDate() // 返回当前月的第几天
getMonth() // 返回月份,***从0开始***
getFullYear() //返回4位的年份 如 2016
案例:
<script>
// 写一个函数,格式化日期对象,返回yyyy-MM-dd HH:mm:ss的形式
function formatDate(data) {
// 先判断是不是date格式
if (!(data instanceof Date)) {
console.error('格式不正确!')
return;
}
// 获取时间日期
var year = data.getFullYear(),
month = data.getMonth() + 1,
day = data.getDate(),
hour = data.getHours(),
minute = data.getMinutes(),
second = data.getSeconds();
// 判断是否大于10
month = month < 10 ? '0' + month : month;
day = day < 10 ? '0' + day : day;
hour = hour < 10 ? '0' + hour : hour;
minute = minute < 10 ? '0' + minute : minute;
second = second < 10 ? '0' + second : second;
return year + '-' + month + '-' + day + '-' + '' + hour + ':' + minute + ':' + second;
}
var test = new Date();
var data = formatDate(test);
console.log(data);
// var test = new Date(2000, 3);
// var data = formatDate(test);
// console.log(data);
// 计算两个时间段的差
var d1 = new Date();
var d2 = new Date(1945 - 4 - 5);
console.log(d1 - d2);
</script>
Array对象
创建数组对象的两种方式
- 字面量方式
- new Array()
// 1. 使用构造函数创建数组对象
// 创建了一个空数组
var arr = new Array();
// 创建了一个数组,里面存放了3个字符串
var arr = new Array('zs', 'ls', 'ww');
// 创建了一个数组,里面存放了4个数字
var arr = new Array(1, 2, 3, 4);
// 2. 使用字面量创建数组对象
var arr = [1, 2, 3];
// 获取数组中元素的个数
console.log(arr.length);
- 检测一个对象是否是数组
instanceof
Array.isArray()
函数的参数,如果要求是一个数组的话,可以用这种方式来进行判断 - toString()/valueOf()
toString() 把数组转换成字符串,逗号分隔每一项
valueOf() 返回数组对象本身
数组常用方法:push()、shift()、unshift()、reverse()、sort()、splice()、indexOf()
// 1 栈操作(先进后出)
push()
pop() //取出数组中的最后一项,修改length属性
// 2 队列操作(先进先出)
push()
shift() //取出数组中的第一个元素,修改length属性
unshift() //在数组最前面插入项,返回数组的长度
// 3 排序方法
reverse() //翻转数组
sort(); //即使是数组sort也是根据字符,从小到大排序
// 带参数的sort是如何实现的?
// 4 操作方法
concat() //把参数拼接到当前数组
slice() //从当前数组中截取一个新的数组,不影响原来的数组,参数start从0开始,end从1开始
splice() //删除或替换当前数组的某些项目,参数start, deleteCount, options(要替换的项目)
// 5 位置方法
indexOf()、lastIndexOf() //如果没找到返回-1
// 6 迭代方法 不会修改原数组(可选)
every()、filter()、forEach()、map()、some()
// 7 方法将数组的所有元素连接到一个字符串中。
join()
- 清空数组
// 方式1 推荐
arr = [];
// 方式2
arr.length = 0;
// 方式3
arr.splice(0, arr.length);
案例:
<script>
var a = [1, 3, 7, 5];
// 栈操作(先进后出)
// push 参数会有多个,将来都会添加都数组最后
a.push(4, 5);
console.log(a);
// pop返回数组的最后一个元素,并且会修改数组的长度就像截取字符串
var last = a.pop();
console.log(last);
console.log(a.length);
console.log(a);
// 队列操作(先进先出)
var array = [1, 2, 3];
array.push(4);
// 返回数组第一个元素
var first = array.shift();
console.log(first);
console.log(array);
// 在前面添加一个元素
var first2 = array.unshift(0);
console.log(array);
// 3.排序方法
// reverse() 翻转数组
var a1 = [1, 2, 3, 4, 5, 6];
console.log(a1);
var a2 = a1.reverse();
console.log(a2);
//sort 排序
var a3 = [1, 8, 5, 0, 3];
console.log(a3);
var a4 = a3.sort();
console.log(a4);
</script>
基本包装类型
// 下面代码的问题?
// s1是基本类型,基本类型是没有方法的
var s1 = 'zhangsan';
var s2 = s1.substring(5);
// 当调用s1.substring(5)的时候,先把s1包装成String类型的临时对象,再调用substring方法,最后销毁临时对象, 相当于:
var s1 = new String('zhangsan');
var s2 = s1.substring(5);
s1 = null;
// 创建基本包装类型的对象
var num = 18; //数值,基本类型
var num = Number('18'); //类型转换
var num = new Number(18); //基本包装类型,对象
// Number和Boolean基本包装类型基本不用,使用的话可能会引起歧义。例如:
var b1 = new Boolean(false);
var b2 = b1 && true; // 结果是什么
String对象
- 字符串的不可变
var str = ‘abc’;
str = ‘hello’;
// 当重新给str赋值的时候,常量’abc’不会被修改,依然在内存中
// 重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变
// 由于字符串的不可变,在大量拼接字符串的时候会有效率问题 - 创建字符串对象
var str = new String(‘Hello World’);
// 获取字符串中字符的个数
console.log(str.length); - 字符串对象的常用方法
// 1 字符方法
charAt() //获取指定位置处字符
charCodeAt() //获取指定位置处字符的ASCII码
str[0] //HTML5,IE8+支持 和charAt()等效
// 2 字符串操作方法
concat() //拼接字符串,等效于+,+更常用
slice() //从start位置开始,截取到end位置,end取不到
substring() //从start位置开始,截取到end位置,end取不到
substr() //从start位置开始,截取length个字符
// 3 位置方法
indexOf() //返回指定内容在元字符串中的位置
lastIndexOf() //从后往前找,只找第一个匹配的
// 4 去除空白
trim() //只能去除字符串前后的空白
// 5 大小写转换方法
to(Locale)UpperCase() //转换大写
to(Locale)LowerCase() //转换小写
// 6 其它
search()
replace()
split()
fromCharCode()
// String.fromCharCode(101, 102, 103); //把ASCII码转换成字符串
// JavaScript 组成: ECMAScript BOM DOM
// ECMAScript:变量 注释 数据类型 类型转换 操作符 流程控制语句(判断和循环) 数组 对象 构造函数 内置对象
// JavaScript中的对象有三种:自定义对象、内置对象、浏览器对象
// ECMAScript中的对象: 自定义对象、内置对象
//
// 内置对象:Math/Array/Date…
//
// 最常用的属性和方法
//
// 查文档:MDN
案例:
<script>
// 1.charAt() 获取指定位置处字符
// 2.charCodeAt() 获取指定位置处字符的ASCII码
// 3.str[0] HTML5,IE8+支持和charAt()等效
var s = 'abcdef';
console.log(s.charAt(0));
for (let i = 0; i < s.length; i++) {
console.log(s.charAt(i));
}
console.log(s.charCodeAt(0));
// 字符串操作方法
// concat() 拼接字符串,等效于+,+更常用
// slice() 从start位置开始,截取到end位置,end取不到
// substring() 从start位置开始,截取到end位置,end取不到
// substr() 从start位置开始,截取length个字符
// 位置方法
// indexOf() 返回指定内容在元字符串中的位置
// lastindexOf() 从后往前找,只找一个匹配的
var s = '我是程序猿一只';
// 第一个参数,截取的开始位置 0 1 2
// 第二个参数,截取的长度
// var newStr = s.substr(2, 2);
// console.log(newStr);
// // 'jdafjfsdfhfhs' 查找字符串中所有j出现的位置
// var a = 'jdafjfsdfhfhs';
// // 当查找不到的时候返回的是-1
// console.log(a.indexOf('j', 0));
// var index = -1;
// do {
// index = a.indexOf('j', index + 1);
// if (index !== -1) {
// console.log(index);
// }
// } while (index !== -1);
var s = 'abcoefoxyozzopp';
// abc!efoxyozzopp
// 只会替换第一个找到的字符串
// s = s.replace('o', '!');
// console.log(s);
//
var index = -1;
do {
index = s.indexOf('o', index + 1);
if (index !== -1) {
// 替换
s = s.replace('o', '!');
}
} while (index !== -1);
console.log(s);
// 去除空白
// trim() 只能去除字符串中的位置
//trim() 只可以去除字符串前后的空格
var s2 = ' abc vyx xyx ';
console.log(s2.trim());
// 思路1 可以把字符串中的所有 空格 字符串 用replace替换成 '' 空字符串
// 思路2 使用split简化
var str = 'a,b,c,d';
var arr = str.split(',');
console.log(arr.join('!'));
var arr1 = s2.split(' ');
console.log(arr1.join(''));
// 大小写转换方法
// to(local) UpperCase() 转换大写
// to(local)LowerCase() 转换小写
// 其他
// search() 寻找 replace() 替换 split() 全部替换 要join() 方法
// 获取url中?后面的内容
// 例如:http://www.itheima.com/login?name=zs&age=18&a=1&b=2
var url = 'http://www.itheima.com/login?name=zs&age=18&a=1&b=2';
// console.log(url.substr(2));
// var index = url.indexOf('?') + 1;
// console.log(url.substr(index));
// {
// name: 'zs',
// age: 18
// }
// 获取url后面的参数
function getParams(url) {
// 获取? 后面第一个字符的索引
var index = url.indexOf('?') + 1;
// url中?后面的字符串 name=zs&age=18&a=1&b=2
var params = url.substr(index);
// 使用& 切割字符串 ,返回一个数组
var arr = params.split('&');
var o = {};
// 数组中每一项的样子 key = value
for (var i = 0; i < arr.length; i++) {
var tmpArr = arr[i].split('=');
var key = tmpArr[0];
var value = tmpArr[1];
o[key] = value;
}
return o;
}
var obj = getParams(url);
console.log(obj);
console.log(obj.name);
console.log(obj.age);
</script>