本專題預計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()/定時器啥的 :)