本专题预计5节,旨在从基础到上手hybrid(主要是移动端react-native以及weex框架)开发。
** 几句题外话:前两节虽然比较基础,但都是js中比较重要的概念,面试过程中也应该会经常被问到。简单的概念我就不在此篇中赘述了。后三节内容则着重于实际开发踩到的坑。**
- 数字 文本
- null 和 undefined
- 深复制与浅复制
- 变量作用域
数字 文本
数字
有人会问数字有什么说的,好像确实是没有什么好说的,但我也硬总结了几个
1.大家要记住: ** js中的所有数字均用浮点数值标识 **,这意味着:他可以精确的表示分数,但这种二进制浮点数表示法并不能精确表示类似0.1这样简单的数字
看下这段代码:
console.log(0.3 - 0.2);//0.09999999999999998
console.log(0.2 - 0.1);//0.1
在开发中也会遇到类似情景,比如价格之类的计算,如遇到此类计算可以先将数值*10再进行操作。
2.记住几个常用的Math函数
- Math.round(.6)//四舍五入
- Math.ceil(.6)//向上取整1.0
- Math.floor(.6)//向下取整0.0
- Math.pow(2,23)//2的23次幂
- Math.randow()//0-1.0的伪随机数
- Math.max(x,y,z)//最大值
- Math.min(x,y,z)//最小值 等等(剩下的自己看吧)。。
3.上溢(overflow)和下溢(underflow)
上溢:超过了js能表达数字上限,用 Infinity 和 -Infinity 标识
举个栗子
console.log(1/0);//Infinity
console.log(-1/0);//-Infinity
下溢:运算结果无限接近零,但超过了js能表示的值,这种情况就会返回『零』,当一个负数发生下溢是,返回『负零』
举个栗子
console.log(-1/Number.POSITIVE_INFINITY);//-0
console.log(Number.MIN_VALUE / 2);//0
思考:
console.log(Number.POSITIVE_INFINITY/Number.POSITIVE_INFINITY);//?
console.log(0/0);//?
console.log( 0 === -0);//?
4.NaN = not a number 经常会用isNaN来判断是否位数字
5.日期
js 提供了Date()对象,来表示日期和时间
var now = new Date();
var then = new Date([year],[month],[day],[hour],[minute],[second]);
then.getFullYear();//year
then.getmonth();//month 从0开始 剩下的自己看看吧
文本
1.操作字符串项目中经常使用的
var s = "hello, world";
s.charAt(0);//h
s.substring(1,4);//"ell" 取第二个到第四个字符
s.slilce(1,4);//同上
s.slice(-3);//"rld" 取最后三个字符
s.splite(", ");//["hello","world"] 分割字符串
2.正则匹配 [链接地址] (https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions)
null 和 undefined
我作为java开发者,只知道null,开发js后又来个undefined,让我一度很蒙逼啊 okay,下面这段话你读一读就懂了
null是一个特殊值,用来描述『空值』。对null执行typeOf,结果返回字符串 "object",也就是说 ** null可以看做特殊的对象值,含义是非对象 **
js中还有第二个值来表示值的空缺。用来定义更深层次的"空值",表明变量没有初始化。如果要查询对象属性或数组元素的值时返回undefined,则说明这个属性或元素不存在。
** 总之: undefined 标识系统级的,而 null 标识程序级,正常的,意料之中的值的空缺。 **
深复制和浅复制
怎么会出现深复制和浅复制这个概念呢?
首先,这种情况只会出现在对象的复制的
我们将对象称为引用类型,js中还有一个类型叫基本类型。对象的值都是引用,对象的比较均是引用的比较,当且仅当他们引用同一个对象是,他们才相等
再举个栗子:
var a = [];
var b = a;
b[0] = 1;
console.log(a[0]); //1
console.log(a === b);//true
你看对象b变了,a也就变了。结论就是将对象(或数组)赋值给一个变量,仅仅赋值的是引用值,对象本身并没有复制一次。如果你想得到一个对象或数组的副本,就要显式复制对象的每一个属性或数组的每个元素
再举个栗子:
var temp = ['a','b','c'];
var convert = [];
for(var i = 0 ; i < temp.length; i++){
convert[i] = temp[i];
}
这样改变temp convert数组也不会受到影响
js中深复制实现的方法有很多,最简单的方法
var cloneObj = JSON.parse(JSON.stringify(obj));
上面这种方法好处是非常简单易用,但是坏处也显而易见,这会抛弃对象的constructor,也就是深复制之后,无论这个对象原本的构造函数是什么,在深复制之后都会变成Object。另外诸如RegExp对象是无法通过这种方式深复制的。
这边简单写了一个深复制,仅供参考学习
// 递归实现一个深拷贝
function deepClone(source){
if(!source && typeof source !== 'object'){
throw new Error('error arguments', 'shallowClone');
}
var targetObj = source.constructor === Array ? [] : {};
for(var keys in source){
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
// test example
var o1 = {
arr: [1, 2, 3],
obj: {
key: 'value'
},
func: function(){
return 1;
}
};
var o3 = deepClone(o1);
console.log(o3 === o1); // => false
console.log(o3.obj === o1.obj); // => false
console.log(o2.func === o1.func); // => true
变量作用域
在js中,用var申明的变量实际上是有作用域的。就说点容易错的
** 没有被var修饰的变量,是全局变量 **
如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量:
function foo() {
var x = 1;
x = x + 1;
}
x = x + 2; // ReferenceError: x is not defined
由于JavaScript的函数可以嵌套(闭包),此时,内部函数可以访问外部函数定义的变量,但反之不可以
function foo() {
var x = 1;
function bar() {
var y = x + 1;
}
var z = y + 1;// ReferenceError: y is not defined
}
如果内部函数和外部函数的变量名重名,js会从内向外查找
function foo() {
var x = 1;
function bar() {
var x = 'A';
alert('x in bar() = ' + x); // 'A'
}
alert('x in foo() = ' + x); // 1
bar();
}
变量提升
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量提升到函数顶部:
function foo() {
var x = 'Hello, ' + y;
console.log(x); //hello,undefined
var y = 'Bob';
}
相当于:
function foo() {
var y;
var x = 'Hello, ' + y;
console.log(x); //hello,undefined
y = 'Bob';
}
结语:下一节讲讲this/闭包/ bind() call() apply()/定时器啥的 :)