consoe.dir()可以显示一个对象所有的属性和方法
变量
变量声明var a;
,赋值a = 10;
变量命名规则和规范
前端缩进是两个空格。
变量命名规则:
①第一个字符必须是字母、下划线_或美元符$
②其它字符可以是字母、下划线、美元符或数字
③不能使用关键字和保留字
变量命名规范:
①多个单词使用驼峰标识,例如:var lastName; var userLoginFlag;
②尽量做到见名知意,不要使用拼音
③赋值=、+=
(或其他符号)两边都加上一个空格
④一条语句结束,后面跟一个;
,函数、循环、if后面不需要加分号
基本语法
值类型——数据类型
- 不可改变的原始值(栈数据:像裤兜装东西的环节,先进后出)
Number、Boolean、String、undefined、null、Symbol - 引用值(堆数据)
array、object、function
var arr = [1, 2];
var arr1 = arr; //arr里的东西放到arr1里,arr和arr1同时指向一个房间
arr = [1, 3]; //arr等于一个新的东西,此时arr等于1,3,arr1等于1,2
document.write(arr1); //1,2
原始值没有属性和方法!
字符串插值(模板字面量最常用的一个特性是支持字符串插值${})
/****变量名写在 ${} 中,${} 中可以放入 JavaScript 表达式。****/
let value = 5;
let exponent = 'second';
let age = 18;
// 以前,字符串插值是这样实现的:
let interpolatedString =
value + ' to the ' + exponent + ' power is ' + (value * value);
// 现在,可以用模板字面量这样实现:
let interpolatedTemplateLiteral =
`${ value } to the ${ exponent } power is ${ value * value }, i am ${age + 1} years old`;
console.log(interpolatedString); // 5 to the second power is 25
console.log(interpolatedTemplateLiteral); // 5 to the second power is 25, i am 19 years old
/****字符串中调用函数****/
function f(){
return "have fun!";
}
let string2= `Game start,${f()}`;
console.log(string2); // Game start,have fun!
判断数据类型
- typeof六种数据类型:number、string、boolean、undefined、object、function
- typeof两种写法:typeof(num)、typeof num
typeof(null); //object
typeof(a); //'undefined'是字符串类型的undefined
被认定为false的值
- undefined,null,NaN,“”,0,false
delete
delete操作符用于删除对象的某个属性, 返回值是布尔(delelte删除不了变量, 删除不了原型链中的变量 )
不使用任何声明创建变量,它会被视作全局变量,挂载到window对象上面,等价于delete window.age
,所以删除成功
基础运算符
- “+”
1.数字运算、字符串链接
2.任何数据类型加字符串都等于字符串
var a = "a" + 1; //a1
var a = "a" + 1 + 1; //a11
var a = 1 + 1 + "a" + (1 + 2); //2a3
- “-”,“*”,“/”,“%”,“=”,“()”
除了+号,其他的运算符两边有字符串的都会转为数字类型 - 优先级“=”最弱,“()”的优先级较高
- “++”,“- -”,“+=”,“-=”,“/=”,“*=”,“%=”
//赋值的顺序自右向左,计算的顺序自左向右
var a = 10;
var b = ++a - 1 + a++; //b=11-1+11=21
document.write(b + " " + a); //21 12
a++; --> a = a + 1; //自身+1再赋值给自身
a += 10 --> a = a + 10;
- a++和++a。通常用在数字变量上面。
如果直接使用a++
或++a
是没有区别的。如果参与运算时有以下区别:
var a = 100;
a++ + 10; //110
先使用,之后自身再+1
++a + 10; //111
先自身+1,之后再使用
var a = 1;
document.write(a++); //1; 打印a++的结果,这是一个执行语句,++在后面识别的语法是先运行执行语句,执行完了最后再++,在等document打印完了之后再++,所以打印的还是1。
document.write(a); //2; 这里打印的才是++完的结果。
var a = 1;
document.write(++a); //2; ++在前面优于一切,a先++,a是1++1就等于2,然后再执行++完的打印语句结果
document.write(a); //2;
比较运算符
- “>”,“<”,“==”,“>=”,“<=”,“!=”(比较结果为boolean)
全等:
- “==”在判断两个值时会自动进行类型转换。
"123" == 123; //true
- “===”表示全等,需要类型和数据完全相等,在判断两个值时不会自动进行类型转换。
"123" === 123; //false
全不等:
- !==表示全不等,也不会自动进行类型转换。
"123" != 123; //false
,"123" !== 123; //true
逻辑运算符
“&&”,“||”,“!”(运算结果为布尔类型)
- &&:与(同时为真)。当结果是真的就会往后走,直到返回最后那个真的,一旦有假的就返回那个假的。
false && true; //false
- ||:或(一个为真)。当结果是真的就直接返回真的,后面的就不看了,碰到假的就会往后看,一直寻找真的;两个都是假的就返回最后那个假的。
false || true; //true
- !:非(取反)。
!false; //true
显示类型转换
其他类型转成数字类型:
Number()
parseInt(string,radix)
将字符串转成整数,radix参数可以不写是进制的意思parseFloat(string)
将字符串转成小数
如果第一个字符是数字或运算符号就开始解析,直到遇到非数字字符,停止解析并得到解析结果;如果第一个字符是非数字或非运算符号,则不解析并得到结果NaN
其他类型转成字符串类型:
变量.toString()
只针对数字类型和布尔类型,null和undefined会报错String(变量)
所有类型都可以+
其他的数据类型和字符串通过+运算符进行拼接时,会自动转成字符串
其他类型转成布尔类型:
- Boolean()
如果某个值为“”(空字符串)、0(包括0、-0)、undefined、NaN、null时,转换成布尔类型的值为false,否则除了那5个值其他的都为true
隐式类型转换
- ++ 或 - -
- +或-
- isNaN()
- 加号运算符(+)
- -*/%
- && || !
- < > <= >=
- == !=
条件语句
- if、if else、if else if else(值的范围判断)
三元运算符(if else的简写):表达式1 ? 表达式2 : 表达式3
var age = 20;
var result = age >= 18 ? "成年人": "未成年";
- switch case(值的相等判断,使用全等运算符===)
break(结束整个循环)
continue(终止本次循环,进行下次循环)
var holidayName = prompt("请输入节日");
switch (holidayName){
case "情人节":
alert("买玫瑰看电影");
break; //不加这个会case穿透,会执行下面的语句
case "平安夜":
alert("买苹果吃大餐");
break;
case "生日会":
alert("买蛋糕");
break;
default:
alert("上班");
}
循环遍历
- while
while(循环条件){
//循环体
}
//打印0-99的数字
var i = 0;
while(i<100){
console.log(i)
i++
}
- do while
特点:不管条件成不成立,do循环体都会先执行一次
do{
//循环体
} while(循环条件)
- for
//语法
for(初始化表达式1; 条件表达式2; 自增/减表达式3){
//循环体4
}
//语句一:通常会写成var i = 1;
//语句二:进行条件判断
//语句三:i++或i--
//练习一:打印100~1的数字
for(var i=100; i>0; i--){
console.log(i);
}
//练习二:计算0-100奇数的和
var oddTotal = 0;
var evenTotal = 0;
for(var i=0; i<100; i++){
//取余数为0就是偶数,否则就是奇数
if( i % 2 === 0 ){
evenTotal += i;
}else{
oddTotal += i;
}
}
console.log(evenTotal)
console.log(oddTotal)
//练习三:正三角爱心(第一行一个,第二行二个...)
for(var i=0; i<6; i++){
//循环里面每行❤的个数,不+1第一行的❤就是0个,也可以写成j<=i;
for (var j=0; j<i+1; j++){
document.write("❤ ");
}
document.write("<br />"); //每行结尾处换行
}
//练习四:九九乘法表
//初始化值都从1开始
for (var i = 1; i < 10; i++){
for ( var j = 1; j <= i; j++){
var str = j + "*" + i + "=" + j * i + " "
document.write(str)
}
document.write("<br />");
}
断点调试debug
- 方式一:打开浏览器的F12→Sources→点击源代码的行数→单步调试
- 方式二:在代码中写上
debugger;
数组
- 数组属性
①length属性:获取数组的长度
②索引值也称下标值index,数组的索引值从0开始的 - 数组遍历
访问数组的最后一个元素:nums.length - 1;
//正向遍历
var nums = [100, 30, 68, 96, 26, 128, 9];
for(var i = 0; i < nums.length; i++){
console.log(i);//打印索引值
console.log(nums[i]);//打印数组内容
}
//反向遍历
//通过nums.length-1先获取最后一个元素
for(var i = nums.length-1; i >= 0; i--){
console.log(i);//打印索引值
console.log(nums[i]);//打印数组内容
}
//练习一:数组中元素拼接,所有的元素使用-进行分割100-30-68-96-26-128-9
var msg = ""; //要有初始化值,没有赋值就会是”undefined“
for(var i = 0; i < nums.length; i++){
//1.先把所有的数组内容拼接到msg中
msg += nums[i];//100306896261289
//2.用-分割
//方法一:除了最后一个元素(不等于最后一个),其他的都加“-”
if( i !== nums.length - 1 ){
msg += "-"
}
//方法二:如果是最后一个元素,用break跳出循环
/*if( i === nums.length - 1 ){
break;
}
msg += "-";*/
//方法三:先遍历前面3个元素都加上-,最后单独拼接最后一个元素
}
console.log(msg);
//练习二:求数组的和和平均值
var total = 0; //要有初始化值,没有赋值就会是undefined
for(var i = 0; i < nums.length; i++){
console.log(nums[i]);//确保可以获取每个数字
total += nums[i]
}
console.log(total);//和:457
var avarage = total / nums.length;
console.log(avarage);//平均值:68.29
//练习三:求数组中的最大值
/*1.定义一个变量,变量保存第一个数字
2.遍历所有的数字
3.将所有遍历的数字和保存的第一个数字进行比较
如果 遍历的数字 > 保存的第一个数字
就将遍历的数字放到保存的变量中*/
var max = nums[0];
for (var i = 0; i < nums.length; i++){
console.log(nums[i]); //打印遍历的数字
if (nums[i] > max){
max = nums[i];
}
}
console.log("最大值"+max); //128
//练习四:数组的反转操作
/*死办法*/
var temp = nums[0]; //定义一个临时变量,取出数组中第一个数字保存给临时变量
nums[0] = nums[nums.length-1]; //把数组中最后一个数字赋值给数组中第一个数字
nums[nums.length-1] = temp; //把临时变量保存的数字赋值给数组中最后一个数字
console.log(nums);
var temp = nums[1];
nums[1] = nums[nums.length-2];
nums[nums.length-2] = temp;
console.log(nums);
var temp = nums[2];
nums[2] = nums[nums.length-3];
nums[nums.length-3] = temp;
console.log(nums);
var temp = nums[3];
nums[3] = nums[nums.length-4];
nums[nums.length-4] = temp;
console.log(nums);
/*循环写法*/
//只需要遍历到数组中间进行交换
for (var i = 0; i < nums.length / 2; i++ ){
var temp = nums[i];
nums[i] = nums[nums.length-1-i];
nums[nums.length-1-i] = temp;
}
console.log(nums)
//练习五:冒泡排序
//实现思路:相邻的两个两个进行比较,第一项与第二项比较,谁大就放后面,然后再第二项与第三项比较,谁大就放后面,一直比较直到把最大的值放在最后面,完成第一轮排序;再比较前面的数字,比较出倒数第二大的数字放在倒数第二的位置完成第二轮排序,以此类推。
函数
函数其实就是对某段代码的封装,完成某一个功能。
使用步骤:定义函数,调用函数。
- 组成形式
①函数名称(小驼峰)
②参数(形参实参)
③返回值
使用return关键字来返回结果,可以把值返回到函数外
一旦在函数中执行return操作,那么当前函数会停止
如果函数中没有使用return语句,那么函数有默认的返回值:undefined
如果函数使用return语句,但是return后面没有任何值,那么函数的返回值也是:undefined
定义函数的方式
①函数声明写法
function 函数名() {
}
②函数表达式写法
var test = function abc() {
document.write('a');
}
test();
//这个叫函数表达式;=号后面的是表达式,会忽略后面abc的名字,执行函数是test(),不写abc的名字就是匿名函数表达式
//1.function
const aaa = function() {}
//2.对象字面量中定义函数,以下两种方式是一样的
const obj = {
bbb: function() {}, //ES5写法
bbb() {} //ES6函数的增强写法
}
//3.es6中的箭头函数
const ccc = (参数列表) => {} //可以有多个参数列表,只有一个参数时小括号可省略
const sum = (num1, num2) => num1 + num2 //函数代码块中只有一行代码,return和方括号可省略
//练习一:加法计算器
function sum(sum1, sum2){
return sum1 + sum2;
}
var result1 = sum(10, 20);
console.log(result1); //10+20=30
//练习二:计算矩形的面积:宽度*高度
function calcRectArea(width, height){
return width * height;
}
var result2 = calcRectArea(10, 20);
console.log(result2);//10*20=200
//练习三:计算圆型的面积:πr²
function calcCircleArea(radius){
return Math.PI * radius * radius;
}
var result3 = calcCircleArea(10);
console.log(result3);
//练习四:计算1~n数字的和
function calcNSum(n){
var total = 0;
for (var i = 1; i <= n; i++){
//console.log(i); //打印1~n的值
total += i;
}
return total;
}
var result4 = calcNSum(5);
console.log(result4);
//练习五:数组的反转操作(如果有多个数组可以调用一个函数)
function reverseArray(arr){
for (var i = 0; i < arr.length / 2; i++ ){
var temp = arr[i];
arr[i] = arr[arr.length-1-i];
arr[arr.length-1-i] = temp;
}
return arr;
}
var nums1 = [100, 30, 68, 96, 26, 128, 9];
nums1 = reverseArray(nums1);
console.log(nums1);
var nums2 = [116, 3, 90, 68, 96, 26, 128, 19];
nums2 = reverseArray(nums2);
console.log(nums2);
//练习六:选择排序
//实现思路:可以选择最大的或最小的。选择最小的直接放在第一个,先把第一项与第二项进行比较,谁小谁放在第一个,再把第一项与第三项进行比较,谁小谁放在第一个,再把第一项与第四项进行比较,谁小谁放在第一个,以此类推,找出最小的值放在第一个完成第一轮排序;再用第二项与第三项比较,第二项与第四项比较,找出第二小的值放在第二个完成第二轮排序,以此类推。
function sortArray(arr){
/***死办法***/
//第一步:先找出数组中最小的值放在第一个位置
for(var i = 1; i < arr.length; i++){
//第一项的值和所有的值进行比较,如果第一项比后面的值大,第一项arr[0]就和arr[i]做交换(把arr[i]中最小的值的交换到第一个位置)
if(arr[0] > arr[i]){
var temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
}
}
//第二步:找出数组中第二小的值放在第二个位置
for(var i = 2; i < arr.length; i++){
//第二项的值和所有的值进行比较,如果第二项比后面的值大,第二项arr[1]就和arr[i]做交换
if(arr[1] > arr[i]){
var temp = arr[1];
arr[1] = arr[i];
arr[i] = temp;
}
}
//第三步:找出数组中第三小的值放在第三个位置
for(var i = 3; i < arr.length; i++){
//第三项的值和所有的值进行比较,如果第三项比后面的值大,第三项arr[2]就和arr[i]做交换
if(arr[2] > arr[i]){
var temp = arr[2];
arr[2] = arr[i];
arr[i] = temp;
}
}
//。。。类推
/***循环写法***/
for(var j = 0; j < arr.length; j++){
for(var i = j+1; i < arr.length; i++){
if(arr[j] > arr[i]){
var temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
}
}
var nums1 = [100, 30, 68, 96, 26, 128, 9]; //定义一个需要排序的数组
sortArray(num1); //调用函数并传入nums1数组
console.log(nums1) //打印nums1排序后的结果
立即执行函数
全称:立即调用函数表达式(针对初始化功能的函数)
此类函数没有声明,在一次执行过后即释放。
作用:会创建一个独立的执行上下文环境,可以避免外界访问或修改内部的变量,也避免了对内部变量的修改。
(function (){
}()) //可以有参数和返回值
//只有函数表达式才能被符号执行
var test = function(){
console.log("a")
}()
什么是回调函数
当一个函数做另一个函数的参数时,这个函数就叫回调函数。
函数的参数——arguments(实参列表)
1.arguments对象是所有(非箭头)函数中都可用的局部变量
2.如果调用者传入的参数多于函数接受的参数,可以通过arguments去获取所有的参数
3.arguments对象和function是分不开的,只有函数开始时才可用
//定义一个函数,计算所有参数的和
function sum(){
var total = 0;
for (var i = 0; i < arguments.length; i++){
total += arguments[i];
}
return total;
}
console.log(sum(10, 20, 30));
console.log(sum(10, 20, 30, 40, 50));
变量的作用域
在js(ES5之前)没有块级作用域的概念,但是函数可以定义自己的作用域。
局部变量:定义在函数内部的变量。
全局变量:定义在script标签中的变量。
预编译前奏
①函数声明整体提升function test() {} //test()在最前面也能访问函数里面的内容
②变量声明提升var a;
- imply global暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为全局对象所有。
a = 123; --> window.a = 123;
,var a = b = 123; --> window.a = 123; --> window.b = 123;
- 一切声明的全局变量,全是window的属性(window就是全局)。
var a = 123; ---> window.a = 123
function test() {
var a = b = 10;
console.log(window.a)//undefined
console.log(window.b)//10;b没经声明就赋值,此变量为全局对象所有,归GO。
}
test();
console.log(b)//undefined,只有函数声明才会提升,var b走的是变量是函数表达式
var b = function () {
}
预编译四部曲
预编译发生在函数执行的前一刻,编译完四步之后执行函数(走函数体里面的代码,如果里面有函数声明就不会再次执行了,因为在变量的时候已经被提升了)
函数的预编译:
①创建AO对象(Activation Object 执行期上下文)
②找形参和变量声明(var a
),将变量和形参名作为AO的属性名,值为undefined
③将实参值和形参统一(将实参放到形参里)
④在函数体里面找函数声明,值赋予函数体
然后再执行函数,AO发生在函数执行的前一刻
全局的预编译:
①创建GO对象
②找变量声明(var a
),将变量作为GO的属性名,值为undefined
③找函数声明,值赋予函数体
然后再执行函数
规律:一旦有重名的,有a变量和a函数,在执行第一条就访问a的话就一定是函数
注意:AO执行的是函数内部,函数外面的是全局GO
注意:如果AO里的c=100;
没有用var声明,就会给全局的GO
注意:GO就是window
注意:如果AO和GO都有test同名的属性,AO和GO会形成链式关系,AO有就用自己的,没有就往上面的GO找;如果AO的if语句判断的a为undefined,那么if语句就不会执行,不会向外层找a。
注意:if语句里面不能有函数声明
作用域精讲
- [[scope]]:每个javascript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供javascript引擎存取,[[scope]]就是其中一个。[[scope]]指的就是我们所说的作用域,其中存储了执行期上下文的集合。
- 作用域链:[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫作用域链。
- 运行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。
- 查找变量:从作用域链的顶端依次向下查找。
内存管理
js会在定义变量时为我们分配内存
- js对于基本数据类型内存的分配会在执行时,直接在栈空间进行分配
- js对于复杂数据类型内存的分配会在堆内存中开辟一块空间,并将这块空间的指针返回值变量引用
闭包
函数可以作为另外一个函数的参数,也可以作为另外一个函数的返回值来使用
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄漏
闭包的作用
- 实现公有变量。(函数累加器)
- 可以做缓存。(eater)
- 可以实现封装,属性私有化。(Person())
- 模块化开发,防治污染全局变量。
对象
对象中的方法:属性值是函数管这样的属性叫方法(其实就是函数),对象的方法调用是对象名.属性方法()
,var obj = { name: '哈哈'; eat: function (){} }
,调用obj.eat()
。
注意:对象里面写属性是用冒号,对象外面增加属性是用等号。
- 属性的增删改查
增加:对象名.属性名=‘值’
删除:delete对象名.属性名 - 创建方法:
1、对象字面量:var obj = {}
2、构造函数来构造对象:
第一种是系统自带的构造函数,前面加个new+构造函数的执行,可以返回一个对象,返回是通过return返回,所以需要拿一个变量来接受var obj = new Object()
;
第二种是自定义构造函数,function Person(){}
这是一个构造函数,如果想通过自定义的构造函数构造对象的话,需要通过new操作符,var obj = new Person()
就可以生成对象,多次调用这个构造函数方法并且有自己的属性可以通过传递参数,调用多次构造方法可以产生独一无二的对象。
注意:由于构造函数和正常函数的写法没有任何区别,所以构造函数需要使用大驼峰式命名规则TheFirstName
function Student(name, age){
this.name = name;
this.age = age;
this.grade = 2015
}
var s1 = new Student('xixi', 18);
var s2 = new Student('haha', 20);
构造函数内部原理:
①在函数体最前面隐式的加上this:{}
②执行this.xxxx = xxxx;
③隐式的返回this。
注意:new构造函数会隐式return返回this
包装类:原始值没有属性和方法!原始值给它赋属性和方法会调用包装类,然后会删除这个包装类再返回undefined。
注意:有两个函数和两个函数调用,只会执行后面的那个函数和函数调用
3、Object.create(原型)
原型
定义:原型是function对象的一个属性,它定义了构造函数制造出来的对象的公共祖先,通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
利用原型特点和概念,可以提取共有的属性。
对象如何查看原型:隐式属性__proto__
对象如何查看对象的构造函数:constructor
原型链
所有对象最终都会继承自Object.prototype
this指向
定时器
setTimeOut:该定时器n秒后触发一次函数,只会执行一次。
setInterVal:该定时器n秒执行一次函数,循环多次执行。
js怎么绑定原生事件
①DOM元素绑定事件<button onclick="demo()">按钮3</button>,function demo(){}
②JS里绑定事件,在事件名称前面加上一个on修饰test.onclick=()=>{}
③绑定事件监听test.addEventListener("click",()=>{})
js的三大事件
鼠标事件、键盘事件、html事件