js:解释型语言,运行之前不会检查语法,碰到错误会停止后续代码 弱类型;面向对象;
输出在页面:document.write(输出的东西); fyntexerror +运算:两边是数字,直接+一起 两边有字符串,最后就是字符串拼接 NAN:Not a Number:不是一个数字,也是数字类型 NAN==NAN ->false NaN不能参与比较运算,都为false 注意=与==的区别,=是赋值;==是相比较
数据类型
1、原始/基本/值类型 两类 Number、String、Boolean、Undefined(创建了一个变量,没有赋值,默认为undefined)、Null(不用的变量可以进行释放,节约内存空间) 2、引用/对象:11个对象(属性和方法)
输入框:var r = parseInt(prompt('请输入圆的半径:'));
数据类型的转换
number+string=string; js获取页面上的一切东西,都是string; +左右没有字符串都转为数值型;
算数运算的隐式转换
悄悄的将左右两边转为数字,在进行运算;
true –>1;false –>0; undefined –>NaN; null –>0; '100'–>100;'100px'–>NaN(不知道转为哪个数字,就转为NaN);
2+true -->3
2+undefined -->NaN
2+null -->2
Boolean(value)——把给定的值转换成Boolean型; Number(value)——把给定的值转换成数字(可以是整数或浮点数);----》不推荐,跟隐式转换一样 parseInt()只有对String类型调用这些方法,这两个函数才能正确运行;对其他类型返回的都是NaN(Not a Number)
Boolean(""); //false – empty string
Boolean("hi"); //true – non-empty string
Boolean(100); //true – non-zero number
Boolean(null); //false - null
Boolean(0); //false - zero
Boolean(new Object()); //true – object
parseInt("1234blue"); //returns 1234
parseInt("0xA"); //returns 10
parseInt("22.5"); //returns 22
parseInt("blue"); //returns NaN
//基模式
parseInt("AF", 16); //returns 175
parseInt("10", 2); //returns 2
parseInt("10", 8); //returns 8
parseInt("10", 10); //returns 10
String(value)——把给定的值转换成字符串。num.toString(),undefined和null不能转换
函数Function方法
需要预定义好的,以后就可以【反复使用】的代码段
分支结构:程序的流程控制语句 1、顺序执行-从上到下 2、分支结构-条件判断 3、循环结构
玩一玩带参数的函数
循环三要素
循环条件:开始-结束,循环的次数 循环体:做的操作是什么? 循环变量:记录我们当前在哪一次,必须有变化
随机固定整数:parseInt(Math.random()*(max-min+1)+min)
for与while的区别:一般没有区别,区别于不知道循环次数就用while(死循环),知道循环次数就用for,更简洁
数组
最大下标:length-1 不限制下标越界,添加元素下标越界,数组会成为稀疏数组 对象.属性; 对象.方法(); length的用法:1、添加元素,不覆盖、不越界;2、获取导数第n个元素:arr[arr.length-n];3、缩容,删除倒数n个元素:arr.length-=n;
for(var i=0;i<arr.length;i++){
循环体内容
}
不能直接操作DOM集合HTMLCOLECTION,可以加上加标 可以从已经找到的父元素查找标签名 父元素:一个:elem.parentnode; 子元素:集合:elem.children; 第一个子元素:elem.firstElementChild; 最后一个子元素:elem.lastElementChild; 前一个兄弟:elem.previousElementSibling; 后一个兄弟:elem.nextElementSibling; id有唯一性,不用找
操作元素:前提:找到元素 获取--》判断;elem.getAttribute('属性名'); 设置--》修改;elem.setAttribute('属性名','属性值'); 1、内容: innerHTML:获取和设置开始标签到结束标签之间的内容,可以识别标签; innerText:不可以识别标签; 以上获取不了input的value值; value:input.value; 2、属性: 简化版:elem.属性名; 缺陷: elem.className; 自定义属性操作不了 3、样式 css属性名有-的,用小驼峰命名法 border-redius –> borderRedius 只能获取内联样式(目前)
事件 elem.on事件名=function(){} this关键字:
eval(str)
先选择btn 遍历 绑定事件 判断+或- +:找到数量;拿到并+1.在赋值给它;再找单价,并计算小计,单价*数量,写入小计中 -:跟上一样,除了位置,还要判断数量>0 找到tbody里面的tr集合,里面的最后一个的小计,再相加
类型转换 只有NaN、0、""、undefined、null、false会转为false,其余boolean()为true
ArrayAPI:
//冒泡排序
固定公式:
for(var j=1;j<arr.length;j++){
for(var i=0;i<arr.length-j;i++){
if(arr[i]>arr[i+1]){
var middle=arr[i];
arr[i]=arr[i+1];
arr[i+1]=middle
}
}
}
正式开发中:排序API:
arr.sort();
问题1:默认会将元素们转为字符串,按位PK每个字符的unicode号,如果希望按照数字排序
解决:
//我们第一次遇到传入实参,传入的是一个函数,而且是一个没有函数名的函数,我们称呼这种函数叫做匿名回调函数,不需要我们程序员自己调用
//回调函数都是前辈们提供好的,我们只需要学习如何使用的
arr.sort(function(a,b){ //a:后一个数 b:前一个数
return a-b; //返回一个正数:后一个数>前一个数
//返回一个负数:后一个数<前一个数
//返回一个0:后一个数==前一个数
//而我们的sort会根据你返回的正数/负数/0,来自动判断要不要交换两者的位置
//return b-a; //从大到小
});
问题2:如何降序排列
arr.sort(function(a,b){
return b-a;
});
强调:排序非常重要:切忌:只要以后页面中有排序功能,他的底层一定是一个数组,因为在js中只有数组可以做排序功能
遍历二维数组
var arr= [['张三','12','1000'],['李四','13','2000'],['王五','14','3000']];
for(var r=0;r<arr.length;r++){
for(var c=0;c<arr[i].length;c++){
console.log(arr[r][c]);
}
}
栈和队列:添加元素和删除元素的新方式 栈:其实就是数组,只不过是一端封闭,只能从另一端进出的数组; 何时:优先使用最新的数据,现实生活中,情况并不多:公交车、电梯... 如何: 开头进:arr.unshift(新值1,...); //添加元素的新方式:向前添加:缺陷:导致其他元素的下标发生变化; 开头出:var first=arr.shift(); //删除元素的新方式:向前删除:缺陷:导致其他元素的下标发生变化; //一次调用只会删除一个元素,而且也有返回值,返回的是你删除的元素;
结尾进:arr.push(新值1,...); //添加元素的新方式:向后添加; 结尾出:var last=arr.pop(); //删除元素的新方式:向后删除;
队列:其实就是数组,只不过一端进,另一端出 何时:根据先来后到的顺序使用数据; 如何: 开头进:arr.unshift(新值1,...); 结尾出:var last=arr.pop();
结尾进:arr.push(新值1,...); 开头出:var first=arr.shift();
var arr = ['孙悟空','猪八戒','唐僧','沙悟净','白骨精'];
/*
*value:数组元素
*index:索引下标
*arr: 正在遍历的数组
/*
// IE8及以下不支持*
arr.forEach(function(*value*,*index*,*arr*){
// console.log(value,index,arr);*
})
// var str = "我的名字是"炮哥" \u9fa5"; //转义字符 \
\n:换行
\t:大空格,制表符
\u4e00:一 (第一个字)19968
\u9fa5: 龥 (最后一个字)40869
只读方法,需要用变量来接收
转英文大小写(做验证码):验证码统一转大小写
大写:str = str.toUpperCase();
小写:str = str.toLowerCase();
获取字符串中指定的字符:str.charAt(i)-->不用,不如用str[i]
获取字符串中指定的字符的ASCII码:
var ascii = str.charCodeAt(i)
通过ascii码转为原文
var yuanwen = String.fromCharCode(ascii)
检索字符串
str.indexOf()
*str/arr.slice(starti,endi+1) 含头不含尾 支持负数参数
str.substring(starti,endi+1) 不支持负数参数
*str.substr(starti,n) n代表的是截取的个数,不考虑含头尾
拼接字符串
var newStr = str.concat(新字符串,...) 不如用+
替换字符串
var newStr = str.replace('关键字'/正则表达式,'新内容');
切割(字符串转为数组)
var arr = str.split(''); //string-->arr
切割符就不存在
var str = arr.join(); //arr-->string
正则表达式
1、 ***** 正则表达式 什么是:规定字符串中字符出现规则的表达式 何时:切割 替换 【验证】 如何:语法:/正则表达式/ 1、最简单的正则:关键字原文 "no"=> /no/gi g:全部 i:忽略大小写
2、备选字符集:/^[备选字符集]$/
强调:1、一个中括号,只管一位字符
2、正则表达式默认只要满足条件就不管后续了,我们希望从头到尾按照我们的要求完全匹配,解决:前加^后加$:从头到尾完全匹配
特殊:如果备选字符集的ascii码是连续的,那么可以用-省略掉中间部分
比如:一位数字:[0-9]
一位英文字母:[A-Za-z]
一位数字字母下划线:[0-9A-Za-z_]
一位汉字:[\u4e00-\u9fa5]
除了xxx之外的:[^0-9] - 很少使用,范围太广了
3、预定义字符集:前辈们提前定义了一套字符集,方便我们程序员 - 简化了备选字符集
一位数字:\d === [0-9]
一位数字字母下划线:\w === [0-9A-Za-z_]
一位空白字符:\s === 包括:空格、换行、制表符
一位除了换行外的任意字符:. - 很少使用,范围太广了
优先使用预定义字符集,预定义字符集满足不了在用备选字符集补充
问题:不管是预定义字符集,还是备选字符集,一个都只管一位、
4、量词:规定了一个字符集出现的次数
1、有明确数量:
字符集{n,m}:前边相邻的字符集,最少n个,最多m个
字符集{n,}:前边相邻的字符集,最少n个,多了不限
字符集{n}:前边相邻的字符集,必须n个
2、没有明确数量
?:前边相邻的字符集,可有可无,最多一次
*:前边相邻的字符集,可有可无,多了不限
+:前边相邻的字符集,至少一次,多了不限 == {1,}
5、选择和分组
选择:在两个规则中选一个
规则1|规则2
分组:将多个子规则重组为一个规则
(规则1|规则2)
6、指定匹配位置
^:开头
$:结尾
特殊:两者同时使用,前加^后加$:表示从头到尾完全匹配 - 只要你做【验证】必须这么写
年FullYear 月Month 日Date 星期Day 时Hours 分Minutes 秒Seconds 毫秒Milliseconds
1、*Error对象:- 错误 以后工作/学习中目的: 1、快速找错 2、记得。。。。
程序员需要的是: 1、会敲代码 2、会自己解决问题 3、自学能力
1、 ***** 浏览器自带4种错误类型,可以快速找到自己的错误 语法错误:SyntaxError - 一定就是你的语法【符号】写错了 引用错误:ReferenceError - 没有创建直接就去使用了 *类型错误:TypeError - 不是你的方法,你却在使用 - cannot ....... of undefined/null 说明不是你的API写法错误,是你API前面的那个人是undefined/null 范围错误:RangeError - 只有一个API会碰到:num.toFixed(d);//d取值范围:0~100之间
2、只要发生错误,就会报错:会导致后续代码停止/闪退,我们不希望 错误处理:就算发生错误,也不要抛出错误(红色),而是给一个错误的提示(黑色),后续代码也可以顺利继续执行 语法:
try{
只放入你可能出错的代码
}catch(err){
发生错误后才会执行
console.log(err);//err就是我们的错误提示:英文
console.log("中文错误提示");
}
try...catch...的性能非常差,几乎里面的代码效率会被降到最低 *可以用一个技术代替:分支结构,比如if...else...提前预判 *开发经验:记住一切的客户端输入/用户输入都是坏人 - 你不必担心,只要你做好防护工作就不会出现问题(!isNaN、正则);
3、抛出自定义错误: throw new Error("自定义错误信息"); - 只要是报错就会卡主后续代码
2、Function:需要预定义好的,以后可以反复使用的代码段 1、创建:3种 1、声明方式:function 函数名(形参列表){函数体 return 返回值;} - 完整的声明提前 2、直接量方式:var 函数名=function(形参列表){函数体 return 返回值;} - 只有函数名部分会声明提前 3、构造函数方式:var 函数名=new Function("形参1","形参2","函数体 return 返回值"); 何时:如果你的函数体是固定的,而不是动态拼接的一个字符串 - 那我们就是用第一种函数创建方式 如果你的函数体是字符串动态拼接而成,不是固定的,可能是让用户来输入的 - 那么我们就是用第三种函数创建方式 var arr=[32,15,4,7,6,897,9,80,9,7635,245,2]; var user=prompt("请输入a-b则为升序排列,输入b-a则为降序排列"); var compare=new Function("a","b","return "+user); arr.sort(compare); console.log(arr);
2、调用时,如果有return操作,记得要拿一个变量接住结果 var result=函数名(实参列表);
3、考点: 1、创建 2、作用域:带来了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错 3、声明提前: 4、按值传递: 5、重载:相同的函数名,传入不同的实参,可以自动选择对应的函数执行 为什么:减轻程序员的负担! 问题:js的语法不支持重载! js不允许多个同名函数同时存在,如果同时存在,最后的会覆盖之前所有的 解决:在【函数内部】有一个对象 - arguments对象 什么是arguments:只能在函数中使用,自动创建,是一个类数组对象(类似数组) 作用:可以接收住所有传入的实参 arguments对象是一个类数组对象:长得像一个数组,但是,不是数组! 只有3个点和数组相同: 1、使用下标 2、使用length 3、都可以遍历 arguments可以实现的功能: 1、实现重载,通过在函数内部判断arguments的不同,执行不同的操作 2、以后有没有形参都无所谓了 3、正式开发中,有可能会将多个函数整合为一个函数 - 代码优化
6、匿名函数:没有名字的函数 1、匿名函数自调:只能调用一次 为什么:节约内存,因为匿名函数,没有变量名引用着,用完,垃圾回收器就会登场把他带走 语法: (function(){ //以后可以代替全局写法,尽量不要外部再去书写js,放在里面的变量会自动释放掉(放心,事件是不会被释放掉的,因为事件这个函数始终有一个函数名关联着,垃圾回收器就不会登场) })();
2、匿名函数回调:将函数作为实参,传递给其他函数中调用 学习的目的: 1、让大家知道哪些叫做回调函数,只要是匿名函数,不是自调,就是回调,回调函数多半都是前辈们定义好的 arr.sort(function(){}) str.replace(reg,function(){}) btn.onclick=function(){}
2、以后ES6技术:箭头函数 - 简化【一切的回调函数】
3、了解到了回调函数的原理
没有名字的函数就是匿名函数,如果后面没有跟着(),就不是自调,不是自调就一定是回调
1、Function 作用域:2种 1、全局:随处可用,可以反复使用,缺点:容易被污染 2、函数:只能在函数内部使用,不会被污染,缺点:一次性的,是会自动释放的
***函数的执行原理: 1、程序加载时 创建执行环境栈(ECS):保存函数调用顺序的数组 首先压入全局执行环境(全局EC) 全局EC引用着全局对象window window中保存着全局变量
2、定义函数时: 创建函数对象:封装代码段 在函数对象中有一个scope(作用域)属性:记录着函数来自的作用域是哪里 全局函数的scope都是window
3、调用前: 在执行环境栈(ECS)压入新的EC:函数的EC 创建出活动对象(AO):保存着本次函数调用时用到的局部变量 在函数的EC中有一个scope chain(作用域链)属性引用着AO AO有一个parent属性是函数的score引用着的对象
4、调用时:正是因为前面三步,我们才有了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
5、调用完:函数的EC会出栈,AO自动释放,局部变量也就自动释放了
两链一包: 作用域链:以函数EC的scope chain属性为起点,经过AO,逐级引用形成的一条链式结构,我们就称之为叫做作用域链 作用:查找变量,带来了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构 - 其实还是一个函数,写法和以前有不同 何时:希望保护一个可以【反复使用的局部变量】 如何使用: 1、两个函数进行嵌套 2、外层函数创建出受保护的变量 3、外层函数要return返回内层函数 4、内层函数要操作受保护的变量
强调: 1、判断是不是闭包,有没有两个函数嵌套,返回内层函数,内层在操作受保护的变量 2、外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本 3、同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
缺点:受保护的变量,永远都不会/不能被释放,闭包使用过多,或造成内存泄漏 - 不可多用 问题:应该在哪里使用啊? 1、三个事件需要防抖节流 1、elem.onmousemove - 鼠标移动事件 2、input.oninput - 每次输入/改变就会触发 3、window.onresize - 每次窗口的大小发生改变就会触发 - css3媒体查询的底层原理 这三个事件修改DOM的速度太快太多,所以要搭配上防抖节流(闭包)
防抖节流公式:
elem.on事件名=function(){
inner()
}
function fdjl(){
var timer=null;//你平时保存的这个timer变量,其实是定时器序号,代表的是第几个定时器,而且第一次从1开始的
return function(){
if(timer){
clearTimeout(timer);//停止一次性定时器
timer=null;//给了一个状态
}
timer=setTimeout(function(){
//要做的操作是什么
},1000)
}
}
var inner=fdjl();
2、 ***** Object - 对象 - Array/String/RegExp...对象具有属性和方法,都是预定义好的,现在我们要学习如何去自定义对象 面向对象:三大特点:封装、继承、多态
1、开发方式:面向对象 和 面向过程 面向过程:经过,开始 -> 结束,我们一直的开发方式都是面向过程,先干什么在干什么最后干什么 面向对象:对象(属性和方法),js有一句话万物皆对象,假设一个人是一个对象的话 属性:姓名、身高、体重、爱好、智商、情商... 方法:吃饭、睡觉、拉粑粑、打游戏、走路、打字、谈恋爱... 为什么要面向对象:现实生活中所有的数据都必须包含在一个事物中才有意义 何时使用面向对象:建议以后任何操作都要封装在一个对象中,但是此种开发方式对新手很不友好 2、封装:创建自定义对象:3种方式 1、*直接量方式: var obj={ "属性名":属性值, ... "方法名":function(){}, ... }
强调:1、其实属性名和方法名的""可以省略不写 - 但是不推荐,因为以后我们要学习一个JSON数据格式,和对象非常相似,但是必须使用""包裹属性名和方法 2、访问对象的属性和方法 *obj.属性名 === obj["属性名"] *obj.方法名() === obj["方法名"] () 建议使用.访问对象的属性和方法,更简单 js中一切都是对象,除了undefined和null,一切对象的底层都是hash数组 3、访问到了不存在的属性:返回undefined 4、可以随时随地的添加新属性和新方法 5、如果我们希望获取出对象中所有的东西 - 遍历for in,自动遍历:obj[i] 6、如果你希望在对象的方法里使用对象自己的属性:this.属性名;
***** 难点:this的指向: 1、单个元素绑定事件:this->单个元素 2、多个元素绑定事件:this->当前触发事件的元素 3、函数中使用this->谁在调用此函数,this指的就是谁 4、定时器中this->window 5、箭头函数中this->外部对象 6、自定义的构造函数this->当前正在创建的对象 2、预定义构造函数方式:var obj=new Object();//空对象 //需要自己后续慢慢追加属性和方法 obj.属性名=属性值; obj.方法名=function(){} 以上两个方法都有一个缺陷:一次只能创建一个对象,适合创建单个对象时(第一种方式)使用,第二种方式永远不用
3、自定义构造函数方式: 1、创建自定义构造函数 function 类名(name,age,hobby){ this.name=name; this.age=age; this.hobby=hobby; } //千万不要再里面创建方法,导致每个对象都会创建一个方法 - 浪费内存,明天我们学了原型链继承就好了
2、调用构造函数创建出对象 var obj=new 类名(实参,...)
面向对象: 优点:1、逼格高,所有的属性和方法,全都保存在一个对象之中 - 更符合现实更有意义 2、每个功能特地分开写 - 便于维护 3、铁索连舟 - 一个方法触发多个方法联动
缺陷:1、对新手不友好,this的指向非常的恶心
javascript:运行在客户端(浏览器端)的解释性弱类型基于原型的面向对象脚本语言
1、 ***** Object: 1、 ***** 继承:父对象的成员(属性和方法),子对象可以直接使用 为什么:代码重用!节约内存空间!提升网站性能! 何时继承:只要多个子对象公用的属性和【方法】,都要集中定义在父对象中
2、如何找到父对象(原型对象) :保存一类子对象共有属性和共有方法的父对象 1、对象名.proto;//必须先有一个对象 2、构造函数名.prototype;//构造函数名:几乎人人都有,除了undefined、null、Math
3、*面试题:两链一包:作用域链、原型链、闭包 每个对象都有一个属性:proto,可以一层一层都找到每个人的父亲,形成的一条链式结构,我们称之为原型链 可以找到所有父对象的成员(属性和方法),作用:找共有属性和共有方法 最顶层是Object的原型,上面放着一个我们眼熟的方法toString,怪不得人人都能用toString JS中万物皆对象
4、有了原型对象,设置共有的属性和方法 1、原型对象.属性名=属性值;//添加|修改了一个共有属性 2、原型对象.方法名=function(){};//添加|修改了一个共有方法
***** 继承具有非常多的鄙视题: 1、判断是自有还是共有 1、判断自有:obj.hasOwnProperty("属性名") true->是自有 false->可能共有,可能没有
2、判断共有:
if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj){//in 会自动在整条原型链上进行查找,true->找到了,false->没找到
console.log("共有")
}else{
console.log("没有")
}
公式:
if(obj.hasOwnProperty("属性名")){
console.log("自有")
}else{
if("属性名" in obj){
console.log("共有")
}else{
console.log("没有")
}
}
2、删除、修改自有和共有 自有:修改:obj.属性名=新值; 删除:delete obj.属性名; 共有:修改:原型对象.属性名=新值;千万不要直接在本地修改共有的东西 - 非常危险,并且修改到爸爸,而是在本地添加了一个同名属性 删除:delete 原型对象.属性名;千万不要再本地直接删除,无效的操作
3、如何为老IE的数组添加indexOf方法:也有可能考你为一类人设置某个方法
if(Array.prototype.indexOf===undefined){//老IE
Array.prototype.indexOf=function(key,starti){//任何一个数组都可以使用
starti===undefined&&(starti=0);//用户没有传入第二个实参的时候starti默认为undefined,设置到0
for(var i=starti;i<this.length;i++){
if(key==this[i]){
return i;
}
}
return -1;
}
}
4、思考一下:如何判断x是不是一个数组:为什么不能用typeof?只能检查原始类型,不能检查引用类型 1、判断x是否继承自Array.prototype Array.prototype.isPrototypeOf(x); true->是数组 false->不是数组
2、判断x是不是由Array这个构造函数创建的: x instanceof Array; true->是数组 false->不是数组
3、ES5提供了一个API用于判断是不是数组:- ES5以上老IE都是不支持的 Array.isArray(x); true->是数组 false->不是数组
4、输出【对象的字符串】形式 在Object的原型上保存着最原始的toString方法 原始的toString输出形式:[object 构造函数名] ***多态:子对象觉得父对象的成员不好用,在本地定义了同名成员,覆盖了父对象的成员 不同的人使用,就算函数名相同,效果出来也不一样,其实根本不是同一个函数 固定用法:借用:Object.prototype.toString.apply(x);
5、实现自定义继承 1、两个对象之间设置继承: 子对象._ proto_=父对象 2、多个对象之间设置继承: 构造函数名.prototype=父对象 注意时机:先设置继承关系,在创建对象