1.变量名可以由数字,字母,下划线及美元符号组成,但不能以数字开头
2.js基本数据类型:数字(浮点数与整数,Infinity),字符串,布尔值,undifined(已申明未赋值的变量),null
非基本数据类型:对象
3.typeof返回的结果:number,string,boolean,undefined,object,function
1) typeof Infinity //number 表示超出了javaScript处理范围的值,任何数除以0也是Infinity
Infinity + Infinity = Infinity
Infinity - Infinity = NaN;
另外Infinity与其他任何操作数执行任何运算结果也等于Infinity
2) typeof NaN //number NaN是一种特殊的数字类型,在运算中使用不恰当的操作数导致运算失败,该运算就会返回NaN
var a = 10 * "f"; NaN
1+2+NaN = NaN
NaN不等于任何东西,包括它自己 NaN = NaN; //false
3) 当我们将一个数字字符串用于算数运算中的操作数时,该字符串会在运算中被当做数字类型来使用(加法运算除外)
var s = '1';
s = 3*s;
typeof s; "number"
4)操作符的优先级 !> && > ||
5) 转换为false的6中情况 空字符串,null,undefined,0,NaN,false;
6)undefined和null的区别 typeof undefined //undefined; typeof null //object
转换成数字: var i = 1*undefined; i=NaN; var b = 1*null; b=0;
4.函数
1)isNaN() 可以用来确定某个输入值是否是一个可以参与算数运算的数字
isFinite() 可以用来检查输入是否是一个既非Infinity也非NaN的数字
encodeURI(),decodeURI(),encodeURIComponent(),decodeURIComponent()
2)匿名函数的用法:
1.可以将匿名函数作为参数传递给其他函数,这样,接收方函数就能利用我们所传递的函数来完成某些事情(回调函数)
2.可以定义某个匿名函数来执行某些一次性任务
3)及时函数
(function( ) { alert('aaa'); })() 第一对括号定义匿名函数,第二对括号起到的是立即调用的作用,同时也是我们想匿名函数传递参数的地方
优点:不会产生任何全局变量
缺点:函数是无法重复执行得。适合于执行一些一次性的或初始化的任务
4)闭包
5)getter和setter
getter 是一种获得属性值的方法,setter是一种设置属性值的方法
5.对象
1.通过instanceof操作符,我们可以测试一个对象是不是由某个指定的构造器函数所创建的
function Hero(){}
var h = new Hero();
var o = {};
h instanceof Hero; true
h instanceof Object; true
o instanceof Object; true
2.构造器函数
对于对象在构造器函数内部是如何创建出来的,可以设想在函数开头处存在一个叫做this的变量,这个变量会在函数结束时被返回
function C(){
// var this = {};
this.a = 1;
// return this;
}
3.传递对象:当我们拷贝某个对象或者将它传递给某个函数时,往往传递的都是该对象的引用。因此我们在引用上所做的任何改动,实际上都会影响它所用的原对象
4.比较对象:当我们对对象进行比较的时候,当且仅当两个引用指向同一个对象时结果为true;
5.内建对象大致可以分为三大类:
数据封装类对象:包括Object,Array,Boolean,Number,String
工具类对象:Math,Date,RegExp等用于提供便利的对象
错误类对象:包括一般性错误对象以及其他各种特殊的错误类对象
6.Array
Array() 是一个用来构建数组的内建构造器函数
typeof Array //object 由于数组也是对象,说明它也继承了Object的所有方法和属性 toString() valueOf() 等方法 [1,2,3].constructor 是 function Array(){} 方法
除了从父级Object那里继承的方法意外,数组对象还有一些更为有用的方法
push() 数组末端添加元素,返回改变后的数组长度
pop()移除最后一个元素,返回被移除的元素
sort()给数组排序,返回排序后的数组,改变原数组
join() 将数组元素连接成字符串
slice(1,3);截取字符串,左闭右开区间,不修改原数组
splice(1,2,100,101,102) 修改目标数组,第一个参数所指定的是要移除切片的起始索引位置,第二个参数是要移除的元素个数,其他参数则用于填补的新元素值
var a = [1,3,5,7,'test'];
var b = a.splice(1,2,100,101,102);
a //[1,1001,101,102,7,"test"];
7.Function函数对象的属性
function myfunc(a){return a };
myfunc.constructor // function Function(){}
constructor属性,其引用的是Function()这个构造器函数
函数也有一个length属性,用于记录函数声明时所决定的参数数量
prototype属性
每个函数的prototype属性中都指向了一个对象
它只有在该函数是构造器时才会发挥作用
该函数创建的所有对象都会持有一个该prototype属性的引用,并可以将其当做自身的属性来使用
8.函数对象的方法
当一个函数调用toString()方法时,所得到的就是该函数的源代码
9.js中每个函数都有call()和apply()
1.可以用来触发函数,并指定相关的调用参数
2.改变this指向,可以让一个对象去借用另一个对象的方法和属性,并为自己所用
some_obj.someMethod.apply(my_obj,['a','b','c']);
some_obj.someMethod.call(my_obj,['a','b','c']);
10.arguments对象
转换成数组: [].slice.call(arguments); 或者 Array.prototype.slice.call(arguments);
js中每个函数都有call()和apply()方法,[].slice是一个函数,可以调用call和apply方法
区分对象和数组的方法
使用Object对象的toString()方法,这个方法会返回所创建对象的内部类名,toString方法必须要来自于Object构造器的prototype属性,直接调用Array的toString方法是不行的,因为在Array对象中,这个方法已经处于其他目的被重写了
Object.prototype.toString.call({}); "[Object Object]"
Object.prototype.toString.call([]); "[Object Array]"
11.Boolean()方法可以将一些非布尔值转换为布尔值(相当于进行两次取反操作)
12.Number
Number.toFixed();保留几位小数点
Number.toExponential(); 将数字转换成指数形式
13.String对象的一些方法
toUpperCase();
toLowerCase();
charAt(); 返回指定位置的字符,与[]作用相当
s.indexOf('o',2) 字符串内部搜索,遇到匹配字符时会返回第一次匹配位置的索引值,第二个参数指定开始搜索的位置
lastIndexOf() 字符串从末端开始搜索(但返回的索引值仍然是从前到后计数)
slice方法和substring方法都可以用于返回目标字符串指定的区间,第二个参数所指定的都是区间的末端位置
区别:substring方法会将负值视为0,而slice方法会将其视为负值与字符串的长度相加
s.slice(1,5); slice方法既是数组方法也是字符串方法
s.substring(1,5);
splite("") 可以根据我们所传递的分割字符串,将目标字符串分割成一个数组
concat()既是数组方法也是字符串方法,可以用于连接字符串或者数组
6.Math
Math对象不是函数对象,不能调用new操作符,Math只是一个包含一系列方法和属性,用于数学计算的全局内建对象
Math.PI 数字常数
Math.SQRT2 2的平方根
Math.sqrt(9); 3 //9的平方根
Math.pow(2,8);2的8次方
Math.random() 返回的是0-1之间的某个数 (max-min)*Math.random()+min 获取区间范围内的随机数
floor() 向下取整
ceil() 向上取整
round() 四舍五入取整
Math.max(2,3,4,5,6);
Math.min(2,3,4,5,6);
7.Date对象
创建Date对象
var d = new Date(); 获取当前时间
// new Date("month dd,yyyy hh:mm:ss");
// new Date("month dd,yyyy");
// new Date(yyyy,mth,dd,hh,mm,ss);
// new Date(yyyy,mth,dd);
// new Date(ms);
常用的对象方法
getFullYear(); 获取年份
getMonth(); 获取月份(0~11)
getDate(); 获取一个月中的某一天(1~31)
getDay(); 获取一周中的某一天(0~6)
getHours(); 获取小时(0~23)
getMinutes(); 获取分钟(0~59)
getSecondes(); 获取秒(0~59)
date.getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)
date.getTime() 返回 1970 年 1 月 1 日至今的毫秒数
8.Error对象
捕获错误
try{
iDontExist();
}catch(e){
console.log(e.name);
console.log(e.message);
}
9.原型
hasOwnProperty() 判断一个属性是否是自身属性
isPrototypeOf() 判断当前对象是否是另一个对象的原型
monkey.isPrototypeOf(george);判断monkey是否为george的原型
Object.getPrototypeOf(george); 获取george的原型对象
Object.getPrototypeOf(george) === george.__proto__;
__proto__是某个实例对象的属性,prototype是构造器函数的属性
当我们重写某对象的prototype时,需要重置相应的constructor属性
当我们通过某个构造器函数来创建对象时(使用new操作符),这些对象就会自动拥有一个指向各自prototype属性的神秘链接,并且可以通过它来访问相关原型对象的属性
总结习题: 实现随机打乱函数shuffle(),执行效果如下:[1,2,3,4,5,6,7,8,9].shuffle(); //[2,4,1,8,9,6,5,3,7]
Array.prototype.shuffle = function(){
return this.sort(function(){
return 0.5-Math.random()
})
}
[1,2,3,4,5,6,7,8,9].shuffle();
10.继承
1)原型链是javaScript中实现继承的默认方式
function Shape(){
this.name = 'Shape';
this.toString = function(){ return this.name}
}
function TwoShape(){
this.name = '2D shape';
}
TwoShape.prototype = new Shape();
用构造器Shape() 通过new操作符另建了一个新的对象,然后用它去覆盖TwoShape构造器的prototype属性
当我们对对象的prototype大户型进行完全替代时,有可能会对对象的constructor属性产生一定的副作用,所以需要对这些对象的constructor属性进行相应的重置
TwoShape.prototype.constructor = TwoShape.;
在对原型对象进行扩展之前先完成相关的继承关系构造
2)子对象访问父对象的方式
3)深浅拷贝
浅拷贝:拷贝的只是该对象在内存中的位置指针
浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。
浅拷贝
function extendCopy(p){
var c = {};
for( var i in p){
c[i] = p[i];
}
c.uber = p;
return c;
}
深拷贝
function deepCopy(p,c){
c = c || {};
for ( var i in p){
if(p.hasOwnProperty(i)){
if(typeof p[i] === 'object‘){
c[i] = Array.isArray(p[i])?[]:{};
deepCopy(p[i],c[i]);
}else{
c[i] = p[i];
}
}
}
return c;
}
在拷贝每个属性之前,使用hasOwnProperty()来确认不会拷贝不需要的继承属性
BOM对象
1.window对象
window.frames属性是当前页面中所有框架的集合,无论当前页面中是否存在框架,window.frames属性总是存在的,并指向window对象本身
<iframe name = "myframe" src="hello.html" />
访问iframe元素的window对象 window.frames[0]
frame元素的重载 frames[0].window.location.reload();
子元素访问父级页面 frames[0].parent === window
访问当前最顶层页面 window.frames[0].window.top === window;
编程模式与设计模式
异步javaScript代码载入
<script defer src="behaviors.js"></script>
兼容处理:动态创建script标签
(function(){
var s = document.createElement('script');
s.src = 'behaviors.js';
document.getElementsByTagName('head')[0].appendChild(s);
}());
深入理解javaScript
1.编写高质量代码
1)单var形式申明变量
2)for循环时,缓存数组或集合的长度
for( var i = 0,max = arr.length; i<maxl i++){}
3)for-in循环遍历对象时用hasOwnProperty过滤原型属性
for( var i in man){
if(man.hasOwnProperty(i)){
//过滤原型属性和自身属性
}
}
4)避免隐式类型转换,比较的时候始终使用===和!==
5)parseInt('09',10);应该始终带上基数,若省略,当数字以0开头时会转换成八进制
2.函数表达式和函数声明
函数声明: function 函数名称(参数){ 函数体 };
函数表达式: function 函数名称(可选)(参数){ 函数体 }
区别:
函数声明会在任何表达式被解析和求值之前先被解析和求值,即使你的声明在代码的最后一行,它也会在同作用域内第一个表达式之前被解析/求值
alert(fn());
function fn() {
return 'Hello world!';
}