JavaScript基础篇——02作用域、域解析、js对象
作用域概述
作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
JavaScript(es6前)中的作用域有两种:
- 全局作用域
- 局部作用域(函数作用域)
作用于所有代码的环境(整个script标签内部)或者一个独立的js文件
局部作用域(函数作用域)作用于函数内的代码环境,就是局部作用域。
JS没有块级作用域- 块级作用域由{ }包括
- 在其他编程语言中(java,c)在if语句、循环语句中创建的变量,仅仅只能在本if语句、本循环语句中使用。
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)
- 全局变量在代码的任何位置都可以使用
- 在全局作用域下var声明的变量是全局变量
- 特殊情况下,在函数内不使用var声明的变量也是全局变量( 不建议使用)
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
- 局部变量只能在该函数内部使用
- 在函数内部var 声明的变量是局部变量
- 函数的形参实际上就是局部变量
形参是不需要var 声明的变量,是局部变量
全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
采用就近原则的方式查找变量最终的值
// 案例1 : 结果是几? function f1() { var num = 123; function f2() { var num = 0; console.log(num); // 站在目标出发,一层一层的往外查找 0 } f2(); } var num = 456; f1(); // 案例2 :结果是几? 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的值 ? 4 console.log(b); //b的值 ? 22 } } } fn1();域解析
我们js引擎运行js 分为两步: 预解析 代码执行
1.(1). 预解析 js引擎会把js 里面所有的 var 还有 function 提升到当前作用域的最前面
(2). 代码执行 按照代码书写的顺序从上往下执行
2. 预解析分为 变量预解析(变量提升) 和 函数预解析(函数提升)
(1) 变量提升 就是把所有的变量声明提升到当前的作用域最前面 不提升赋值操作
(2) 函数提升 就是把所有的函数声明提升到当前的作用域的最前面 不调用函数
// 1问 console.log(tel);//error // 2问 console.log(num); // undefined 坑 1 var num = 10; // 相当于执行了以下代码 // var num; // console.log(num); // num = 10; // 3问 function fn() { console.log(11); //11 } fn(); // 4问 fun(); // 报错 坑2 var fun = function () { console.log(22); } // 函数表达式 调用必须写在函数表达式的下面 // 相当于执行了以下代码 // var fun; // fun(); // fun = function() { // console.log(22); // }
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); } // 相当于 var a = 9; b = 9; c = 9; b 和 c 直接赋值 没有var 声明 当 全局变量看 // 集体声明 var a = 9, b = 9, 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 error
对象
什么是对象对象由属性和方法组成的。
创建对象的3种方式- 利用字面量创建对象 { }
- 利用 new Object创建对象
- 利用 构造函数创建对象
{ }里面采取键值对的形式表示
键:相当于属性名
值:相当于属性值,可任意类型(数字类型、字符串类型、布尔类型、函数类型等)
// 利用对象字面量创建对象 {} // 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();
利用new Object()创建对象
对象.属性=值
// 利用 new Object 创建对象 var obj = new Object(); // 创建了一个空的对象 obj.uname = '张三疯'; obj.age = 18; obj.sex = '男'; obj.sayHi = function() { console.log('hi~'); } // (1) 我们是利用 等号 = 赋值的方法 添加对象的属性和方法 // (2) 每个属性和方法之间用 分号结束 console.log(obj.uname); console.log(obj['sex']); obj.sayHi();
利用构造函数创建对象
构造函数:有类的意思
- 构造函数用于创建某一类对象,其首字母大写
- 构造函数要和new一起使用才有意义
- 构造函数不需要return
- 函数内的属性和方法前面需要加this,表示当前对象的属性和方法
//构造函数的语法格式 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('李香兰')
new关键字
new在执行时会做4件事
1.在内存中创建一个新的空对象
2.让this指向这个新对象
3.执行构造函数里面的代码,给这个新对象添加属性和方法
4.返回这个新对象(所以构造函数里面不需要return)
for…in语句
for(变量 in 对象名字){
//执行代码
}
// 遍历对象 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变量、属性、函数、方法总结
- 变量 单独声明并赋值 使用的时候直接写变量名 单独存在
属性 在对象里面的不需要声明的 使用的时候必须是 对象.属性 - 函数和方法的相同点 都是实现某种功能 做某件事
函数是单独声明 并且调用的 函数名() 单独存在的
方法 在对象里面 调用的时候 对象.方法()
内置对象
JavaScript中对象分为3种:自定义对象、内置对象、浏览器对象
JavaScript提供了多个内置对象:Math、Date、Array、String等
Math对象不是构造函数,它具有数字常数和函数的属性和方法。
Math.PI //圆周率 Math.floor() //向下取整 Math.ceil() //向上取整 Math.round() //四舍五入 就近取整 注意-3.5结果是-3 Math.max()/Max.min() //求最大和最小值
// 利用对象封装自己的数学对象 里面有 PI 最大值和最小值 var myMath = { PI: 3.141592653, 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, 5, 9)); console.log(myMath.min(1, 5, 9));
随机数方法random()
random()方法随机返回一个小数,其取值范围 [0,1)
得到一个两数之间的随机数,包括两个数在内 function getRandom(min,max){ return Math.floor(Math.random()*(max-min+1)+min; }日期对象Date
Date是一个构造函数,我们需要实例化后使用
方法名 | 说明 | 代码 |
---|---|---|
getFullYear() | 获取当年 | date.getFullYear() |
getMonth() | 获取当月(0-11) | date.getMonth()+1 |
getDate() | 获取当天日期 | date.getDate() |
getDay() | 获取星期几(周日0 到周六6) | date.getDay() |
getHours() | 获取当前小时 | date.getHours() |
getMinutes() | 获取当前分钟 | date.getMinutes() |
getSeconds() | 获取当前秒钟 | date.getSeconds() |
// 1. 使用Date 如果没有参数 返回当前系统的当前时间 var date = new Date(); console.log(date);//Mon May 18 2020 08:13:52 GMT+0800 (中国标准时间) 当前系统的当前时间 // 2. 参数常用的写法 数字型 2019, 10, 01 或者是 字符串型 '2019-10-1 8:8:8' var date1 = new Date(2019, 10, 1); console.log(date1); // 返回的是 11月 不是 10月 Fri Nov 01 2019 00:00:00 GMT+0800 (中国标准时间) var date2 = new Date('2019-10-1 8:8:8'); console.log(date2); //Tue Oct 01 2019 08:08:08 GMT+0800 (中国标准时间)
格式化日期 年月日 我们写一个 2019年 5月 1日 星期三
// 格式化日期 年月日 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]);
格式化日期 时分秒
// 格式化日期 时分秒 var date = new Date(); console.log(date.getHours()); // 时 console.log(date.getMinutes()); // 分 console.log(date.getSeconds()); // 秒 // 要求封装一个函数返回当前的时分秒 格式 08:08:08 function getTimer() { var h = date.getHours(); h = h < 10 ? '0' + h : h; var m = date.getMinutes(); m = m < 10 ? '0' + m : m; var s = date.getSeconds(); s = s < 10 ? '0' + s : s; return h + ':' + m + ':' + s; } console.log(getTimer());
获得date总的毫秒数
var date1 = +new Date(); // +new Date() 返回的就是总的毫秒数 console.log(date1);
数组对象
方法名 | 说明 | 返回值 |
---|---|---|
push(参数1…) | 末尾添加一个或多个元素,注意修改原数组 | 并返回新的长度 |
pop() | 删除数组最后一个元素,把数组长度减1 无参数、修改原数组 | 返回它删除的元素的值 |
unshift(参数1…) | 向数组的开头添加一个或更多元素,注意修改原数组 | 返回新的长度 |
shift() | 删除数组的第一个元素,数组长度减1 无参数。修改原数组 | 返回第一个元素的值 |
reverse() | 颠倒数组中元素的顺序,无参数 | 该方法会改变原来的数组 返回新数组 |
sort() | 对数组的元素进行排序 | 该方法会改变原来的数组 返回新数组 |
indexOf() | 数组中查找给定元素的第一个索引 | 如果存在返回索引号 如果不存在,则返回-1 |
lastIndexOf() | 在数组中的最后一个的索引 | 如果存在返回索引号 如果不存在,则返回-1 |
toString() | 把数组转为字符串,逗号分隔每一项 | 返回一个字符串 |
join(‘分隔符’) | 用于把数组中的所有元素转换为一个字符串 | 返回一个字符串 |
concat() | 连接两个或多个数组 不影响原数组 | 返回一个新数组 |
slice() | 数组截取slice(begin,end) | 返回被截取项目的新数组 |
splice() | 数组删除splice(第几个开始,要删除个数) | 返回被删除项目的新数组 注意这个会影响原数组 |
添加删除数组元素方法
// 添加删除数组元素方法 // 1. push() 在我们数组的末尾 添加一个或者多个数组元素 var arr = [1, 2, 3]; console.log(arr.push(7, 'pink')); //5 console.log(arr); //(5) [1, 2, 3, 7, "pink"] // (1) push 是可以给数组追加新的元素 // (2) push() 参数直接写 数组元素就可以了 // (3) push完毕之后,返回的结果是 新数组的长度 // (4) 原数组也会发生变化 // 2. unshift 在我们数组的开头 添加一个或者多个数组元素 console.log(arr.unshift('red', 'purple'));//7 console.log(arr); //(7) ["red", "purple", 1, 2, 3, 7, "pink"] // (1) unshift是可以给数组前面追加新的元素 // (2) unshift() 参数直接写 数组元素就可以了 // (3) unshift完毕之后,返回的结果是 新数组的长度 // (4) 原数组也会发生变化 // 3. pop() 它可以删除数组的最后一个元素 console.log(arr.pop()); //pink console.log(arr);//(6) ["red", "purple", 1, 2, 3, 7] // (1) pop是可以删除数组的最后一个元素 记住一次只能删除一个元素 // (2) pop() 没有参数 // (3) pop完毕之后,返回的结果是 删除的那个元素 // (4) 原数组也会发生变化 // 4. shift() 它可以删除数组的第一个元素 console.log(arr.shift());//red console.log(arr); // (1) shift是可以删除数组的第一个元素 记住一次只能删除一个元素 // (2) shift() 没有参数 // (3) shift完毕之后,返回的结果是 删除的那个元素 // (4) 原数组也会发生变化
特别注意下冒泡排序的写法
// 1. 翻转数组 var arr = ['pink', 'red', 'blue']; arr.reverse(); console.log(arr); // 2. 数组排序(冒泡排序) var arr1 = [13, 4, 77, 1, 7]; arr1.sort(function(a, b) { // return a - b; 升序的顺序排列 return b - a; // 降序的顺序排列 }); console.log(arr1);
var arr = ['red', 'green', 'pink']; console.log(arr.indexOf('blue'));//-1 没找到 // 返回数组元素索引号方法 lastIndexOf(数组元素) 作用就是返回该数组元素的索引号 从后面开始查找 var arr = ['red', 'green', 'blue', 'pink', 'blue']; console.log(arr.lastIndexOf('blue')); // 4
数组去重
// 数组去重 [-1, '-1', -2, -1, -5, 7, 7, 9, 8, 9] 要求去除数组中重复的元素。 // 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([-1, '-1', -2, -1, -5, 7, 7, 9, 8, 9]);//-1,'-1',-2,-5,7,8,9 console.log(demo);
var date=new Date();//声明日期对象 var obj={};//空对象 var obj1=new Object(); //空对象obj1 var arr=[]; //声明空数组 var array=new Array();//声明空数组 //都用 var关键字来声明字符串对象
基本包装类型 String、Number、Boolean
浅谈JavaScript基本包装类型
// 基本包装类型 var str = 'andy'; console.log(str.length); // 对象 才有 属性和方法 复杂数据类型才有 属性和方法 // 简单数据类型为什么会有length 属性呢? // 基本包装类型: 就是把简单数据类型 包装成为了 复杂数据类型 // (1) 把简单数据类型包装为复杂数据类型 var temp = new String('andy'); // (2) 把临时变量的值 给 str str = temp; // (3) 销毁这个临时变量 temp = null;
数组转换为字符串
// 数组转换为字符串 // 1. toString() 将我们的数组转换为字符串 var arr = [1, 2, 3]; console.log(arr.toString()); // 1,2,3 // 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
字符串的不可变
指的是里面的值不可变,虽然看上去可以改变内容,但其实地址变了,内存中新开辟了一个内存空间
var str='abc'; str='hello'; //当重新给str赋值的时候,常量‘abc’不会被修改,依然在内存中 //重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变 //由于字符串的不可变,在大量拼接字符串的时候会有效率问题 var str = ''; for (var i = 1; i <= 1000000000; i++) { str += i; } console.log(str);//这个结果需要花费大量时间来显示,因为需要不断的开辟新的空间
根据字符返回位置
方法名 | 说明 |
---|---|
indexOf(‘要查找的字符’,开始的位置) | 返回指定内容在元字符串中的位置,如果找不到就返回-1 ,开始的位置是index索引号 |
lastIndexOf() | 从后往前找,只找第一个匹配的 |
//根据字符返回位置 str.indexOf('要查找的字符', [起始的位置]) var str = '改革春风吹满地,春天来了'; console.log(str.indexOf('春')); //2 console.log(str.indexOf('春', 3)); //8 从索引号是 3的位置开始往后查找
查找字符串"abcoefoxyozzopp"中所有o出现的位置以及次数
// 查找字符串"abcoefoxyozzopp"中所有o出现的位置以及次数 // 核心算法:先查找第一个o出现的位置 // 然后 只要indexOf 返回的结果不是 -1 就继续往后查找 // 因为indexOf 只能查找到第一个,所以后面的查找,一定是当前索引加1,从而继续查找 var str = "oabcoefoxyozzopp"; 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);
根据位置返回字符
方法名 | 说明 | 使用 |
---|---|---|
charAt(index) | 返回指定位置的字符(index字符串的索引号) | str.charAt(0) |
charCodeAt(index) | 获取指定位置处字符的ASCII码(index索引号) | str.charCodeAt(0) |
str[index] | 获取指定位置处字符 | HTML5,IE8+支持和charAt()等效 |
// 根据位置返回字符 // 1. charAt(index) 根据位置返回字符 var str = 'andy'; console.log(str.charAt(3));//y // 遍历所有的字符 for (var i = 0; i < str.length; i++) { console.log(str.charAt(i)); // a n d y } // 2. charCodeAt(index) 返回相应索引号的字符ASCII值 目的: 判断用户按下了那个键 console.log(str.charCodeAt(0)); // 97 a对应ASCII码值97 // 3. str[index] H5 新增的 console.log(str[0]); // a
字符串操作方法
方法名 | 说明 |
---|---|
concat(str1,str2,str3…) | concat()方法用于连接两个或多个字符串。 |
substr(start,length) | 从start位置开始(索引号),length取的个数 |
slice(start,end) | 从start位置开始,截取到end位置,end取不到(它们俩都是索引号) |
substring(start,end) | 从start位置开始,截取到end位置,end取不到 基本和slice相同,但是不接受负值 |
replace()用于在字符串中用一些字符替换另一些字符
replace(被替换的字符串,要替换为的字符串) 它只会替换第一个字符
split()用于切分字符串,可将字符串切分为数组。在切分完毕后,返回的是一个新数组
var str='a,b,c,d'; console.log(str.split(',')); //返回的是一个数组[ a,b,c,d]
// 字符串操作方法 // 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 是取几个字符
// 1. 替换字符 replace('被替换的字符', '替换为的字符') 它只会替换第一个字符 var str = 'andyandy'; console.log(str.replace('a', 'b')); //bndyandy // 有一个字符串 'abcoefoxyozzopp' 要求把里面所有的 o 替换为 * var str1 = 'abcoefoxyozzopp'; while (str1.indexOf('o') !== -1) { str1 = str1.replace('o', '*'); } console.log(str1); //abc*ef*xy*zz*pp // 2. 字符转换为数组 split('分隔符') 前面我们学过 join 把数组转换为字符串 var str2 = 'red, pink, blue'; console.log(str2.split(',')); //Array(3) var str3 = 'red&pink&blue'; console.log(str3.split('&')); //Array(3)
简单类型传参相当于复制一份,不影响原变量
// 简单数据类型传参 function fn(a) { a++; console.log(a); //11 } var x = 10; fn(x); console.log(x); //10
复杂数据类型传参改变值
// 复杂数据类型传参 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. 这个输出什么 ? 张学友
参考文档
[1] 浅谈 javascript 中基本包装类型https://wiki.jikexueyuan.com/project/brief-talk-js/basic-type-of-packaging.html
- 自学javascript笔记_自用_解析W3school的代码_JS对象
- [JS]详尽解析window.event对象 --javascript 教程及特效
- javascript_面向对象系列_02用JS写一个类(ES3和ES6两种写法)
- [JS]详尽解析window.event对象 --javascript 教程及特效
- JavaScript基础精华02(函数声明,arguments对象,匿名函数,JS面向对象基础)
- JavaScript基础精华02(函数声明,arguments对象,匿名函数,JS面向对象基础)
- [JS]详尽解析window.event对象 --javascript 教程及特效
- Javascript 将json字符串解析成js 对象的四种方法
- 自学javascript笔记_自用_解析W3school的代码_JS对象
- JavaScript--解析JSon数据--JS对象、数组
- [WebKit] JavaScriptCore解析--基础篇 (一)JSC与WebCore
- JavaScript解析顺序和变量作用域
- 【JS】day03_JavaScript对象_常用内置对象一
- D3.js以及通用JS(JavaScript)读取并解析服务器端JSON的注意事项
- JavaScript中select、js对象、js数组复合操作
- 003_JavaScript深度剖析之对象定义详解——北京圣思园JavaScript&jsUnit&Ajax&jQuery
- js 将json字符串转换为json对象的方法解析
- JSON学习(案列):js 将json字符串转换为json对象的方法解析
- js 将json字符串转换为json对象的方法解析
- javascript区分DOM对象与JS对象