JS基础讲解
- JavaScript组成
- ECMAScript:解释器、翻译
- DOM:Document Object Model
- BOM:Browser Object Model 各组成部分的兼容性,兼容性问题由来
- 兼容性
- ECMAScript几乎没有兼容性问题 (ES6)
- DOM 有一些兼容性问题
- BOM 几乎不兼容
变量详解
1 .变量如果不进行声明,而直接使用一个'局部'变量,那么这个变量会变成全局的
-
变量类型
-
弱语言也有类型
-
typeof查看变量的类型
typeof null === "object" //true typeof NaN //number typeof eval //function new Object() instanceof Array === false
-
类型检测:
-
typeof适合基本类型和function检测,遇到null失效
-
Class 通过{}.toString()拿到,适合内置对象和基本类型,遇到null和undefined失效(IE678等返回object)
-
instanceof适合自定义对象,也可以用来检测原声对象,在不同iframe和window间检测失效
-
-
-
常见类型:
- number, string, boolean, object, null, undefined, function
- 基本数据类型: number,string,boolean,undefined,null
- 复合类型:对象(js里面一切皆是对象)
- undefined:
- 没有定义变量
- 定义了但是没有存东西进去
- 一个变量应该只存放一种类型的数据
-
比较
-
类型相同 a===b
-
类型不同,尝试类型转换后比较
null==undefined //true number==string 转化为number 1=="1.0" //true boolean == number 转化为number 1==true//true object == string | number 尝试对象转为基本类型
-
-
类型转换
var num = parseInt(str); //会提取其中的数字 //str="abc" //NaN(not a number) //str = "abc 12 bc" //NaN //str = "123px" //123 从最左边提取
-
注意:
- NaN与其他任意数值之间的比较总是不相等的
- 比如: parseInt('abc') == NaN 返回的是false
- 只能调用isNaN(parseInt('abc'))来进行比较
- NaN与其他任意数值之间的比较总是不相等的
-
parseFloat
-
Number
var num = Number("123"); var num = Number("123abc"); //NaN, 比Number严格转换
-
隐式转换
var a = 12, b = "12"; alert(a==b) //返回true 但是===不会进行转换 // 先把两边的东西转成一样的东西之后 再进行转换 alert('12'-'5'); //返回值为7 string转化为number alert(typeof a); //string a的类型不变
-
-
变量的作用域和闭包
-
作用域: 局部变量和全局变量
-
什么是闭包
- 子函数可以使用父函数中的局部变量
- 之前一直在使用闭包(闭包-封装)
- 网上对于闭包的定义(常见错误-循环闭包)
-
优势: 灵活方便 封装
-
弊端: 空间浪费 内存泄露 性能消耗
function outer() { var localVal = 30; return function() { return localVal; }; } var func = outer(); func(); //30 任然有能力访问到局部变量 var a = eval('({name:"fff", age:18})'); //外面一定要带一层括号 alert(a.name); //fff
-
抽象概念:
- 执行上下文
- 变量对象:是一个抽象概念中的对象,用于存储执行上下文中的
- 1,变量 2,函数声明 3,函数参数
- VO按照如下顺序填充(变量初始化阶段):
-
函数参数(若为传入,初始值该参数为undefined)
-
函数声明(若发生命名冲突,会覆盖掉)
-
变量声明(初始化变量为undefined,若发生命名冲突会忽略)
function test(a,b){ var c = 10; function d(){}; var e = function _e(){}; (function x(){}); //此处被忽略掉 b = 20; } test(100);
-
-
初始化阶段 (可称为编译阶段 时间非常快)
AO(test) = { a:100, b:undefined, c:undefined, d:<ref to func "d">, e:undefined, }
-
代码执行阶段
VO['c'] = 10; VO['e'] = function _e(){}; VO['b'] = 20;
-
-
变量的使用习惯
- 只存储一种类型的值
- 命名规范以及必要性:可读性 规范性
- 匈牙利命名法
- 首字母大写 oDivUserInfo
- 类型前缀
o-->object s-->string
a-->array i-->integer
f-->float b-->boolean
fn-->function re-->RegExp
v--> Variant(变体变量 不限定一个类型的变量)
-
函数返回值
-
一个函数应该只返回一种类型的参数(函数可以没有return)
-
函数有return 但是没有返回值, 实际返回一个undefined
-
可变参数和不定参数auguments
auguments是一个数组--存的是所有的数组 -
复合样式: background
单一样式(基本样式) width, height.. -
函数参数和arguments是可以共存的
-
函数声明与函数表达式
function add(a,b){} //函数声明 会前置 可以没有声明的时候提前调用 var add = function(a,b){} //函数表达式 不能再此之前使用 //命名函数表达式 var func = function nef(){} //IE6-8不相等 IE9+ FF会报错 //函数构造器 var func = new Function('a','b','console.log(a+b)'); var func = Function('a','b','console.log(a+b)'); func(1,2) //3 //Function构造器 Function("var localVal ='local'; console.log(localVal);")(); console.log(typeof localVal); //undefined 因为是局部变量
-
-
this
-
全局的this
this.document === document //true this === window //true function f1() { return this; } f1() === window //true function f2() { 'use strict' return this; } f2() === undefined //true global object
-
作为对象方法的函数this
var o = {prop:37}; function independent() { return this.prop; } o.f = independent; console.log(o.f()); //37
-
构造器中的this
function c() { this.a = 37; return {a:38}; } o= new c(); console.log(o.a); //38 o为返回的对象 如果返回的是基本类型 那么就返回this
-
+ call/apply与this
```js
function add(c,d)
{
return this.a+ this.b + c + d;
}
var o = {a:1,b:3};
add.call(o,5,7); //1+3+5+7;
add.apply(o,[10,20]); //1+3+10+20
function fooBar()
{
console.log(Object.prototype.toString.call(this));
}
bar.call(3); //[object Number]
```
+ bind与this (ES5)
```js
function f()
{
return this.a;
}
var g = f.bind({a:"test"});
console.log(g()); //test
var o = {a:37,f:f,g:g}
console.log(o.f(),o.g()); //37 test
```
-
arguments
- 注意区分严格模式和非严格模式下 arguments的跟踪问题
function foo(x,y,z) { arguments.length; //2 arguments[0] //1 arguments[0] = 10 ;//x changes to 10 x// 10 arguments[2]=100; //没有传参数过去 z; //still undefined 失去绑定关系 arguments.callee === foo ;//true //严格模式下不能使用 typeof arguments // object 类数组 obj { 0: 'args1', 1:'args2', length:2} }
对象描述
属性是无序的且是字符串,(key不是字符串的话先将key toString()一下)
-
对象结构
- writable, enumberable, configurable, value, get/set
- 对象有的属性
proto, class, extensible, 自定义属性 - 读写对象的属性
-
属性异常
- 访问不存在属性y, 会访问原型链,再没有找到会返回undefined
-
删除属性
delete Object.prototype //不允许删除 返回false var descriptor = Object.getOwnPropertyDescriptor(Object,'prototype'); descriptor.configurable //false 是否可配置 var globalVal - 1; delete globalVal; //false,
- 局部变量和函数也是不可以delete掉
- 但是如果是隐式的创建的话 是可以被删除掉的, 比如ohNo = 1; window.ohNo返回1, delete ohNo //true
-
检测属性
property in obj var cat = new Object(); cat.legs = 4; cat.name="Kitty"; 'legs' in cat//true "toString" in cat//true, 从原型上继承 cat.hasOwnProperty('legs')// true cat.hasOwnProperty('toString') //false
-
枚举属性
-
cat.propertyIsEnumberable('legs')//true 是否可枚举
-
cat.propertyIsEnumberable('toString')//false
-
自定义对象的属性
Object defineProperty(cat,'price',{enumerable:false ,value:1000}); //通过defineProperty创建对象, 所有的属性默认false cat.propertyIsEnumerbla('price'); //false cat.hasOwnProperty('price')// true
-
区分:
var o = {x:1,y:2,z:3}; var obj = Object.create(o);//以o为原型创建对象 obj.a = 4; var key; for (key in obj) { console.log(key); //a,x,y,z if (obj.hasOwnProperty(key)) { console.log(key); //只有a打印出来, xyz是原型链上的属性 } }
-
-
-
getter/setter:
var man = { name: 'Bosn', get age(){ return new Date().getFullYear() - 1988; }, set age(val){ console.log("Age can\'t be set to"); } } function foo() {} Object.defineProperty(foo.prototype,'z',{get:function(){return 1;}}) var obj = new foo(); obj.z;//1; obj.z = 10; obj.z; //still 1; //原型是现在自己上找属性发现没有, 就去原型上找有但是没有set方法,不会更改 修改上面的定义代码 Object.defineProperty(foo.prototype,'z',{value:100,configuration:true}) obj.z; //100 delete obj.z; obj.z// 1 Object.defineProperty(o,'x',{value:1});//表示其不可writable和configurable
-
属性标签
Object.getOwnPropertyDescriptor({pro:true},'pro');//获取对于对象的描述 //第一个参数表示一个对象, 第二个参数表示获取对象某一属性 //Object{value:true,writable:true,enumberable:true,configurable:true} Object.getOwnPropertyDescriptor({pro:true},'a'); //undefined var person = {}; Object.defineProperty(person,'name',{//给Person添加name属性 value:"Confidence",writable:false,enumberable:true,configurable:false });//configurable为false表明不可删除. enumerable表示该属性不可被遍历到 Object.keys(person);//访问对象的属性 Object.defineProperties(person,{ title:{value:'t',enumerable:false}, head:{value:'h',enumerable:true}, } );
-
对象标签和对象序列化
-
原型标签 proto
-
类标签 class没有直接的方式查看, 通过toString查看
function getType(o) { return toString().call(o).slice(8,-1); } ({}).toString.call(window).slice(8, -1) //"[object Window]" - > window toString.call(null); // Object[null] getType(null); //null getType(1); //number getType(new Number(1)); //number typeof new Number(1); //object
-
extensible标签
obj = {x:1, y:2}; Object.isExtensible(obj); //true; Object.preventExtensions(obj);//阻止之后即不能够扩展了 Object.seal(obj); //设置configurable为false Object.isSealed(obj); //true Object.freeze(obj); //冻结, 所有属性都是false Object.isFrozen(); //true
-
-
对象的序列化
var obj = {x:1,y:true,z:[1,2,3],"nullVal":null}; JSON.stringify(obj); obj = {val:undefined,a:NaN,b:Infinity,c:new Date()}; JSON.stringify(obj); //"{"a":null,"b":null,"c":"2015-01-20T14.."}"; obj = JSON.parse("{'x':1}")
-
序列化的自定义
var obj = { x:1, y:2, o:{ o1:1, o2:2, toJSON:function() { return this.o1+this.o2; }, }, }; JSON.stringify(obj); //"{"x":1","y":2","o":3}" var obj = {x:1,y:2}; obj.toString(); //[Object object] obj.toString = function() { return this.x + this.y; } "result: " + obj; //result: 3 +obj;// 3 //尝试把类变成基本类型的时候 obj.valueOf = function(){ return this.x+this.y + 100; } +obj; //103, from valueOf "reuslt: "+ obj; //result: 103 //尝试把对象变成基本类型, 先找valueOf再找toString
-
-
创建对象
当我们给对象赋值的时候,先看对象上有没有当前属性,如果有的话修改当前值,
如果没有的话仅在当前对象上添加属性, 而不会修改原型链上的属性值-
obj.hasOwnProperty("z"): 判断自身对象是是否有该属性
如果需要访问原型上的z, -
delete obj.z; obj.z; 才会获取原型上的z
-
通过var obj = Object.createa({x:1});
var obj = Object.create(null); alert(obj.toString) 为undefined
-
字符串详解
-
str.length; 字符串的长度 (中文和英文是不区分的)
'这个字符串'.length //5 var s1 = "anc"; //string var s2 = new String('abc') //object
-
获取类
-
charAt——指定字符
var ch = str.charAt(index); (str[0]也可以 但IE6兼容性) var ascCode = str.charCodeAt(index); //获取ASCII码 var ch = String.fromCharCode(25105); //编码转文字
-
charCodeAt——指定字符的编码
-
fromCharCode——编码转换成字符
-
-
查找类
-
indexOf、lastIndexOf、search——查找
- indexOf 获取索引 找不到即为-1
- lastIndexOf 最后一个位置的索引
- search 查找
-
indexOf和search的区别
- search匹配正则表达式
var str = "abcd?efgh"; alert(str.search('?'))// 会报错 因为?在正则表示数量词
-
match、replace——匹配和替换 扩展正则的方法
-
-
比较类
-
localeCompare——根据当地习惯比较字符串
按照拼音进行排序 -
排序应用
-
截取类 (从原字符串取出子字符串并返回,不改变原字符串)
-
substring将负值写成0来使用
'JavaScript'.substring(0, 4) // "Java" 'JavaScript'.substring(4) // "Script" // 如果第二个参数大于第一个参数,substring方法会自动更换两个参数的位置。 'JavaScript'.substring(10, 4) // "Script" // 等同于 'JavaScript'.substring(4, 10) // "Script" //如果参数是负数,substring方法会自动将负数转为0。 'Javascript'.substring(-3) // "JavaScript" 'JavaScript'.substring(4, -3) // "Java"
-
slice 负值倒数往后看,变成倒数第几个
- slice方法用于从原字符串取出子字符串并返回,不改变原字符串。
- 它的第一个参数是子字符串的开始位置,第二个参数是子字符串的结束位置(不含该位置)。
'JavaScript'.slice(0, 4) // "Java" //如果省略第二个参数,则表示子字符串一直到原字符串结束。 'JavaScript'.slice(4) // "Script" // 如果参数是负值,表示从结尾开始倒数计算的位置,即该负值加上字符串长度。 'JavaScript'.slice(-6) // "Script" 'JavaScript'.slice(0, -6) // "Java" 'JavaScript'.slice(-2, -1) // "p"
-
substr和substring的区别
- substring: 不包含结束位置
- substr: 第二个参数表示截取的长度, 为负取0
// substr方法的第一个参数是子字符串的开始位置,第二个参数是子字符串的长度。 'JavaScript'.substr(4, 6) // "Script" // 如果省略第二个参数,则表示子字符串一直到原字符串的结束。 'JavaScript'.substr(4) // "Script" // 如果第一个参数是负数,表示倒数计算的字符位置。 // 如果第二个参数是负数,将被自动转为0,因此会返回空字符串。 'JavaScript'.substr(-6) // "Script" 'JavaScript'.substr(4, -1) // ""
-
-
其他
- split——根据分隔符、拆分成数组
- var strArr = str.split(ch);
- toLowerCase、toUpperCase——大小写转换
- var str = str1.toLowerCase()
- var str = str2.toUpperCase()
- split——根据分隔符、拆分成数组
-
数组详解
-
数组的定义
var arr=new Array(1,2,3); var arr=[1,2,3]; //上面的这个的简称, 上面的性能略高 可以忽略不计 var arr = [1,2,,,3,4] //中间的表示undefined length表示6 var arr = [1,2,,,,] //中间的表示undefined length表示6 var arr = new Array(2^23-1)// undefined*2^23-1
-
区别: 可以说基本上没有区别
-
其他简写
function show() { }; var show = function() {}; var show = new Function("alert('a')"); var str="abc"; var str1 = String('abc');
以上两个不能称之为简写, 区别在于第一个属于string,第二个是object
下面一个是属于包装类
-
-
数组属性
-
length
-
不仅可以只读还可以写,但是对于字符串的length进行写的话没效果
var arr = [1,2,3]; arr.length = 10; alert(arr[6]);//undefined // delete之后, 长度并不会变化 //快速清空数组: arr.length = 0;
-
-
数组使用原则:
- 数组中应该只存一种类型的变量, 如果要存多种类型的话,
最好是使用json
- 数组中应该只存一种类型的变量, 如果要存多种类型的话,
-
遍历
arr.forEach(function(item) { console.log('age'+item.age); }) //IE9 之上 arr.forEach(function(x,index,a) { console.log(x+"--"+index+"--"+a===arr); });
-
-
添加、删除:(修改当前数组)
- push 尾部添加 arr.push(value)
- pop 尾部删除 arr.pop(); 一次只能删除掉一个 返回删除元素
- shift 头部删除 arr.shift(value); 返回删除元素
- unshift 头部添加 arr.unshift(value);
- splice:
- 基本语法:splice(开始, 长度,[元素…])
先删除一段长度的元素 再添加一段元素 - 插入
- arr.splice(2,0,'a','b','c');
- 删除
- arr.splice(2,3);
- 替换
- arr.splice(2,3,'a','b','c');
- 基本语法:splice(开始, 长度,[元素…])
-
数组操作 (不修改当前数组)
-
映射
arr.map(function(x) { return x + 10; //让数组中每一个元素都加10, 但是并不会修改原来的数组 });
-
过滤
arr.filter(function(x,index){ return index % 3 == 0 || x >= 8; }); //并不会改变数组原来的内容
-
数组判断
arr.every(function(x) { return x < 3;//判断数组的每一个是不是都满足条件 都满足的话返回true }); arr.some(function(x) { return x === 3;//数组之中的任意一个符合条件就返回true });
-
数组操作
var arr = [1,2,3]; var sum = arr.reduce(function(x,y) { return x + y; //数组中的值两两进行操作 //首先将0传入,1为y 加起来的和赋值为x,取y=2,再次相加赋值 },0);//6 //并不会改变数组原来的值 //reduceRight 与reduce差不多, 但是是从右往左开始遍历
-
判断
Array.isArray([]); //true [] instanceof Array; //true [].constructor ==== Array //true ({}).toString.apply([]) === '[object Array]' //true
-
join:合并数组,变成字符串
var str = arr.join('-'); // 与split相反操作
-
slice:取子数组
var arr = [0, 1,2,3,4,5] var b = arr.slice(0, 4) //0 1 2 3
-
-
二维数组
- var arr = [[0,1],[2,3],[4,5]];
- 稀疏数组
-
并不含有从0开始的连续索引
var arr1 = [undefined]; //0 in arr1 //true var arr2 = new Array(1); //0 in arr2 //false 0 in arr[,,] //false
-
-
排序:(修改原始数组)
-
sort:排序数组
- 排序字符串数组
arr.sort(); //按照字典序排序 (大写在前) - 排序数字数组
- 默认的情况下, 把所有东西都当做字符串处理
- 排序可以有参数
arr.sort(function(num1, num2){ return num1>num2?-1:1; return num1 - num2; //返回-1, 表明第一个比第二个靠左 //返回+1, 表明第一个比第二个靠右 //上述返回值只要是负数或者整数都行 }); //中文字符串排序 arr.sort(function(str1,str2) { return str1.localeCompare(str1,str2); });
- 排序字符串数组
-
-
数组操作 (修改数组)
-
reverse:反转数组
arr.reverse(); // 修改arr
-
concat: 数组连接 arr.concat(arr1);
arr = [1,2,3]; arr.concat([10,[11,12]]); //arr = [1,2,3,10,11,12];
-
toString: 数组转字符串
- 为了覆盖某些库的源代码. 覆盖其toString方法
show.toString = function() { return "就不让你看" };
- 数字的toString
- num.toString(n) n代表的数字的进制, 进行数制转换
-
数组的去重 (去掉重复元素 只保留一个)
- 对象去重法
- ES6 Set集合
-
数组的复制
arr2 = arr1.concat([]); //表明concat复制了一份新的 //能用原生的方法就用原生的, 效率高 arr2 = arr1.slice(0) //ES6 语法中数组复制
-
-
数组apply
//代码查看赏析1 function func() { var m_points = []; m_points = Array.apply(m_points, arguments); //构造函数 将arguments的参数加入到m_points中 m_points.push.apply(m_points, arguments); // 将arguments数组加入到m_points当中 console.log(m_points); //apply的原理: this指向m_points 执行 m_points.push方法 //执行m_points.push()方法中的this指向的是 m_points } func(1,2,3,4,5,6);
流程控制和运算符
-
语句块: {语句1, 语句2} (开发中用的比较少) 区分对象
- JavaScript没有块级作用域
- for (var i =0; i < 5; i ++){}
- 当for循环结束之后 在外部还是可以访问i的, 与放在前面声明是一样的
-
判断(选择)语句
- false: 0,false, ''(空字符串), null, undefined
- true: true,非零数字, 非空字符串,非空对象
-
循环语句
-
其他语句
-
with最好不用(让js引擎更难,可读性差,可被变量定义替代,严格模式下禁用)
with({x:1}) { console.log(x); //输出1 }
-
-
对象属性
var val = (1,2,3); //声明语句 val = 3; var a = b = 1; //创建的b是一个全局变量 delete obj.x //删除对象上的属相 alert(obj.x) //undefined Object.defineProperty(obj,'x',{ configuration:false, /*表明对象上的属性不可以删除*/ value:1, }); delelte obj.x //返回false 表示无法删掉 'x' in window //对象里面是否x这个属性 obj.hasOwnProperty('x') //判断对象是对象上的属性还是原型链上的属性 obj._proto_.hasOwnProperty('x') //是否属于对象原型上
-
逻辑运算
-
数值运算
-
比较运算
-
位运算
-
for in
- 对象属性受原型链的影响
- enumerable为false的时候不会出现
for(attr in oDiv.style) { oTxt.value+=attr+'\n'; }
-
异常处理语句
try { throw "test"; }catch(ex) //可以忽略掉catch { console.log(ex); }finally { console.log("finally"); } try { try { throw new Error("oops"); } finally { console.log("finally"); } }catch (ex) { console.log(ex); } //结果是 先打印 finally 在打印 oops
-
严格模式
"use strict" function fn() { "use strict";//可以向上兼容, 也可以在文件的最开头时使用 }
-
不允许使用with 会报sytax错误,
-
不允许未声明的变量赋值
!function()
{
x = 1;
console.log(window.x);
} -
arguments变为参数的静态副本
!function(a) { aruguments[0] = 100; console.log(a);//打印出100 }(1);
- 上面的情况, 当我们不传参数1的时候, a为undefined, 修改参数argumrnts[0], 但是a的值还是为undefined
- 使用'use strict' arguments与传递的参数之间不会有任何的影响,但是如果
传递的是对象的话, 依然是会相互影响的
-
在严格模式下,delete参数,函数名会报错, delete不可配置的属性会报错
-
对象字面是重复属性会报错 var obj = {x:1, x:2}//语法错误
-
严格模式禁止八进制字面量 alert(0123);
-
eval,arguments变为关键字,不能作为变量名,函数名
-
eval独立作用域
eval("var evalVal = 2"); console.log(typeof evalVal); // 普通模式下 number, 严格模式下undefined
-
网友评论