文章目录
switch case 条件判断语句
当有一句语句满足条件后 虽然下面的语句不做i判断但是它依然会被执行
var date=window.prompt('input')
switch(date){
case "周一":
case "周二":
case "周三":
case "周四":
case "周五":
console.log("工作日");
break;
case "周六":
case "周日":
console.log("休息日")
break;
}
break 用于在需要的时候终止循环 必须放在循环体里面 否则报错
continue 终止本次循环 进行下一次循环
数组
var arr=[1,"abc",undefined,null,true,NaN];
// 遍历数组 把数组的每一位都拿出来
for(var i=0 ;i<arr.length;i++){
console.log(arr[i]);
}
对象
// 对象
var deng={
lastName:"Deng",
//属性名:属性值
age:40,
// 属性与属性之间要用逗号隔开 属性名与属性值之间用:隔开
wife:"xiaoliu",
father:"dengdaye",
son:"xiaodeng",
handsome:false
}
// 取值
console.log(deng.lastName);
deng.lastName="Old Deng";
typeof操作符
可以返回的六种值分别是 number string boolean object undfined function
显式类型转换
- Number的目的是把对象里面的东西转换成数字
- parseInt的目的是把对象里面的东西转换成整型 从数字位一直读到非数字位 截断非数字位并舍弃 undefined null false true这些不再关注
- parseFloat它会识别小数点后一位 然后截断 舍弃 返回小数点后一位之前的数字
- String 试图把对象里面的东西转换成字符串
- boolean 试图把对象里面的东西转换成布尔类型的
- to string 试图把对象里面的东西转换成字符串 但是undefined、null不能用toString方法
隐式类型转换
- isNaN() 判断括号里面的数字是不是NaN 他会先把变量拿出来放到Number里面去 然后再和NaN比较 然后返回结果
- ++、–隐式调用Number先弄成数字类型 ±看情况调用Number或String
- *、/、% 隐式调用Number
- &&、||、!隐式调用Boolean
- < > <= >= 如果没有数字就对比埃斯特码 如果有数字 就隐式调用Number
- == != 有隐式类型转换的等于和不等于
- === !== 没有隐士类型转换的绝对等于和绝对不等于
函数
- 命名函数表达式
function theFirstName(){
//小驼峰命名规则 第一个单词首字母小写 往后单词的首字母都大写
}
console.log(theFirstName);//弱数据语言永远都输出不了地址 这里会输出函数体
- 匿名函数表达式 --> 函数表达式
var test=function abc(){
}
console.log(test);//表达式是忽略函数名的 此时的函数是匿名的 匿名函数表达式就是统称的函数表达式
参数
// a,b 写在小括号里就相当于再函数体里 var了一个 a又var了一个b 没有值
// 形式参数-->形参
function demo(a,b){
var c=a+b;
console.log(c);
}
// 实际参数-->实参
demo(1,2);
// javascript中 参数不限制位数 且天生不定参 实参比形参多可以 形参比实参多没问题
function demo1(a,b,c){
// 再每个函数里面都有一个隐式的 类数组>arguments -->实参列表数组
for(i=0;i<arguments.length;i++){
console.log(arguments[i]);
}
}
demo1(1,2,3)
// 不定参的好处
function sum(){
var result=0;
for(var i=0;i<arguments.length;i++){
result+=arguments[i];
}
console.log(result);
}
sum(1,2,3,4,5,6,7,8,9,10,11,12,13,9);
// 映射关系是当形参有实参也有的时候才映射 当他们其中一个没有的时候不会映射的
// 函数的结束条件加返回值
function demo2(a,b){
console.log('a');
return;//又终止函数 又返回变量
console.log('b');
}
// 把输入的变量转换为number类型
function myNumber(target){
return+target;
}
var n=myNumber(undefined);
console.log(typeof(n)+" "+n);
demo
function scream(animal){
switch(animal){
case "dog":
console.log('wang');
return;
case "cat":
console.log('miao');
return;
case "flsh":
console.log('O~O~O');
return;
case "pig":
console.log('pu~pu~');
return;
case "chicken":
console.log('go~go~go');
return;
}
}
// 2.定义一组函数,输入数字,逆转并输出汉字形式
function reverse (){
var ns=window.prompt('input');
var str="";
for(var i=ns.length-1;i>=0;i--){
str+=ns[i];
}
console.log(str);
}
function transfer(target){
switch(target){
case"1":
return"壹";
case"2":
return"贰";
case"3":
return"叁";
}
}
// 3. 写一个函数实现n的阶乘
// 递归 效率很低 特别复杂的程序 不能用递归
// 有规律有出口就大胆的用递归
function jc(n){
if(n==0||n==1){
return 1;//找到出口 当n=0 的时候就不计算了直接返回
}
return n*jc(n-1);//找到规律
}
// 4.写一个函数,实现斐波那契额数列
// 递归 有递归就先写return
function fb(n){
if(n==1||n==2){
return 1;
}
return fb(n-1)+(n-2);
}
fb(5);
作用域
- 在函数外面定义的变量叫全局变量 再函数里面定义的变量叫局部变量
- 在函数里面可以访问全局的变量 但是在全局不能访问函数里面的变量
- 同级函数之间也不能相互访问
- 函数套函数的情况下 最里面的可以访问外面任意层的变量 权限最高 但是反过来最外面层的不能访问里面的函数 权限最低
预编译分三步 语法分析> 预编译>解释执行
- 函数声明整体提升 如果你写了一个函数声明 不管你写在哪里 系统总是会把他提升到逻辑的最前面
- 一切声明的全局变量 都归全局对象window所有 -->window=GO
js中的连等
//连续赋值的过程一定是自右向左的
function test(){
var a=b=123;//此时的b是未经声明的
}
test();
预编译发生在函数执行的前一刻
- 创建AO对象 Activation Object (执行期上下文)
- 找形参和变量声明 将变量声明的名和形参的名作为AO对象的属性名,值为undefined
- 将实参和形参的值相统一
- 找函数体里面的函数声明 将函数声明的名作为AO对象的属性名,值为函数体
全局预编译发生在全局执行的前一刻
- 创建GO对象 Global Object ==window(全局执行期上下文)
- 找形参和变量声明 将变量声明的名和形参的名作为AO对象的属性名,值为undefined
- 找函数体里面的函数声明 将函数声明的名作为AO对象的属性名,值为函数体
demo
function bar(){
return foo;
foo=10;
function foo(){
}
var foo=11;
}
console.log(bar());
// AO{
// foo:function (){} >10>11
// }
console.log(bar2());
// AO{
// foo:undefined>fn >10>11
// }
function bar2(){
foo=10;
function foo(){
}
var foo=11;
return foo;
}
作用域链
- 每个JavaScript 函数都是一个对象,对象中有些属性我们可以访问, 但是有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。
- [[scope]]指的就是我们所说的作用域,其中存储了执行期上下文的集合。
- 执行期上下文:当函数执行时会创建一个称为执行器上下文的内部对象,一个执行器上下文定义了一个函数运行时的环境,函数每次执行时的执行期上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行期上下文,当函数执行完毕,它所产生的执行期上下文被销毁。
- 作用域链:[[scope]]中存储的执行器上下文的集合,这个集合呈链式链接,我们把这种链接叫做作用域链
function a(){
function b(){
var b=234;
}
var a=123;
b();
}
var glob=100;
a();
// a.[scope]-->用来存作用域链-->GO{a:fn;glob:100;}
// 新的函数执行时 当前AO放到作用域链的第0位 Go放在作用域链的第一位
// 查找变量:在那个函数里面查找变量就上那个函数的作用域链的顶端依次向下查找
demo
function aa(){
function bb(){
function cc(){
}
cc();
}
bb();
}
aa();
// a defined aa[[scope]]-->0:GO
// a doing aa[[scope]]--> 0:aaAO
// 1:GO
// b defined bb[[scope]]-->0:aaAO
// 1:GO
// b doing bb[[scope]]--> 0:bbAO
// 0:aaAO
// 1:GO
// c defined cc[[scope]]-->0:bbAO
// 0:aaAO
// 1:GO
// c doing cc[[scope]]--> 0:ccAO
// 0:bbAO
// 0:aaAO
// 1:GO
闭包
但凡是内部的函数 保存到了外部 它必须生成闭包
demo
// 改变的永远都是a 的AO因为第一次执行的时候b里面啥都没有 所以第二次执行的时候a的AO里面的num值为101
function a (){
var num=100;
function b(){
num++;
console.log(num);
}
return b;//b被保存到外部了 a执行完了销毁a的AO 但是此时b还拿着a的AO
}
var demo=a();//b被demo保存了 执行demo就是执行b
demo();//101
demo();//102
这段代码中 由于函数a执行时生成了函数a的aAO,此时的num值是100,然后num++之后输出的num是101,然后返回函数b,但是执行到这里函数a就全部执行结束了,销毁了自己的作用域,但是b被返回到外部的时候还带着a执行完的aAO,然后aAO里面的num是101,第二次执行demo的时候 num就是第一次执行之后的结果,101++,输出102.,因为aAO的作用域还在b里所以,两次执行用的是一个num。
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有的作用域链不释放,造成内存泄漏。
实现公有变量
function add(){
var count=0;
function demo(){
count ++;
console.log(count);
}
return demo;
}
var counter =add();
counter();
counter();
counter();
可以做缓存 (存储结构)外部是不可见的 但是它确实有3存储结构
function test (){
var num=100;
function a(){
num ++;
console.log(num);
}
function b(){
num--;
console.log(num);
}
return[a,b];
}
var myArr=test();
myArr[0]();//101
myArr[1]();//100
function eater(){
var food="";//生成闭包
var obj={
eat:function(){
console.log("i am eating" +food);
food="";
},
push:function(myFood){
food=myFood;
}
}
return obj;
}
var eater1=eater();
eater1.push('banana');
eater1.eat();
立即执行函数
标准定义:此类杉树没有声明,在一次执行过后即释放。适合做初始化工作。
var nums= (function abc(a,b,c){
//这里的括号传形参 前面定义的num用来接收立即执行函数的返回值
var d = a+b+c;
}(123,234,345))//这里的括号传 实参 而且立即执行函数也有返回值
只有表达式才能被执行符号执行 能被执行符号执行的函数就是立即执行函数
var test=function(){
console.log('a');
}()
// 只要趋势上把他转成数字 他就会变成可被执行符号执行的表达式
+ function a(){
console.log('a');
}();
demo
理论上坚决不能执行的 只写括号的时候系统只能识别为执行符号 但是加上参数了之后 系统就会把括号直接丢掉不看了 系统不想报错
function tes(a,b,c,d){
console.log(a+b+c+d);
}(1,2,3,4)
对象,包装类
var mrDeng ={
name:"MrDeng",
age:40,
sex:"male",
health:100,
somke:function(){
console.log('I an smoking! cool!!!');
this.health--;
return mrDeng.health;
},
drink:function(){
console.log('I am drink');
this.health++;
return mrDeng.health;
}
}
this在这里是第一人称自己的意思
对象、属性、方法、的增加删改查
//增
mrDeng.wife="xiaoliu";
//删
delete mrDeng.age;
//改
mrDeng.name="OldDeng";
//查
console.log(mrDeng.name);
var deng={
prepareWife:"xiaowang",
gf:"xiaoliu",
name:"laodeng",
sex:"male",
wife:"",
divorce:function(){
//离婚方法
delete this.wife;
this.gf=this.prepareWife;
return deng.wife;
},
getMarried:function(){
//结婚方法
this.wife=this.gf;
return deng.wife;
},
changePrepareWife:function(someone){
//预备人选
this.prepareWife=someone;
return deng.wife;
}
}
对象的创建方法
- var Obj={}plainObject 对象字面量/对象直接量
- 构造函数
1)系统自带的构造函数 new Object()
2)自定义
构造函数必须遵循大驼峰式命名规则 TheFirstName
var obj=new Object();
obj.name='abc';
obj.sex='male';
function person(){
//构造函数和普通函数在结构上没有任何区别
}
var person1=new person();//有new他就会生成一个对象
function Car(){
this.name="BMW";
this.height="1400";
this.lang="4900";
this.weight=1000;
this.health=100;
this.run=function(){
this.health--;
}
}
var car =new Car();
var car1=new Car();//虽然他们的属性、方法都一样但是他们之间不会互相改变 每一个new生成的对象都是独立的
car.name="Maserati";
car1.name="merz";
function Student(name,age,sex){
// var this ={
// this.name=name;
// this.age=age;
// this.sex=sex;
// this.grade=2020;
// return this;
// }
this.name=name;
this.age=age;
this.sex=sex;
this.grade=2020;
}
var student=new Student('zhangsan',18,'male');
构造函数的内部原理
- 在函数体最前面隐式的加上this={}
- 执行this.xxx=xxx;
- 隐式的返回this
包装类
undefined和null不能有属性
var str=new String('abcd');
var num=new Number(123);
var bol=new Boolean(true);
var n=4;
n.len=3;
// new Number(4).len=3; delete
// new Number(4).len
console.log(n.len);
var s="abcd";
s.length=2;
// new string('abcd').lenth=2;-->delete
console.log(s);
var st="abc";
st+=1;
var test=typeof(st);
if(test.length==6){
test.sign="typeof返回结果可能为String";
}
console.log(test.sign);
mrChang={
name:"ChangJiawei",
sex:"male",
age:19,
health:100,
chi:function () {
this.health++;
},
he:function () {
this.health--;
}
}
// 小demo
// 当前字符的Unicode》255,那么该字符串长度为2
// 2、<=255为1
var str ="abcd 成";
function bytesLength(str){
// var count=str.length;
// for(var i=0;i<str.length;i++){
// if(str.charCodeAt(i)>255){
// count++;
// }
// }
var count=0;
for(var i=0;i<str.length;i++){
if(str.charCodeAt(i)>255){
count+=2;
}else {
count++;
}
}
return count;
}
原型、原型链
- 定义:原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。
- 利用原型特点和概念,可以提取共有属性。
- 对象如何查看原型->隐式属性——proto——
- 对象如何查看对象的构造函数
利用圆形特点和概念,可以提取共有属性
Car.prototype={
//利用原型特点和概念,可以提取共有属性。
height:1400,
lang:4900,
carName:"BMW"
}
function Car(color,owner){
this.owner=owner;
this.color=color;
}
var car=new Car('red','prof.ji');
var car1=new Car('green','prof.Deng');
//
原型的增删改查
// 增加
Person.prototype.lastName='Deng';
function Person(name){
this.name=name;
}
var person=new Person('xuming');
// 删除
delete Person.prototype.lastName;
// 修改
Person.prototype.lastName="James";
// 查看
console.log(person.lastName);
constructor构造器 指向函数本身 可以被更改(认贼作父)
Bar.prototype.abc='123';
function Bar(){
}
var bar=new Bar();
__proto__存的是对象的一个原型,指向原型本身 可以被更改
PersonOne.prototype.name="abc";
var obj={
name:"sunny"
}
function PersonOne(){
}
var personOne=new PersonOne();
原型链
CanvasGradient.prototype.lastName="Deng";
function Grand(){
}
var grand=new Grand();
Father.prototype=grand;
function