數(shù)據(jù)類型
JavaScript 是弱類型語言,但并不是沒有類型,JavaScript可以識(shí)別下面7種不同類型的值:
基本數(shù)據(jù)類型
- Boolean
- Number
- String
- null
- undefined
- Symbol (es6,引入唯一值)
Oject
- Array
- RegExp
- Date
- Math
可以使用 typeof 判斷數(shù)據(jù)類型,操作符 返回一個(gè)字符串,但并非返回的所有結(jié)果都符合預(yù)期
typeof false //boolean
typeof .2 //number
typeof NaN //number
typeof '' //string
typeof undefined //undefined
typeof Symbol() //symbol
typeof new Date() //object
typeof [] //object
typeof alert //function
typeof null //object
typeof not_defined_var. //undefined
變量
在應(yīng)用程序中,使用變量來為值命名。變量的名稱稱為identifiers
聲明
- 使用關(guān)鍵字
var->函數(shù)作用域 - 使用關(guān)鍵字
let->塊作用域(block scope local variable) - 直接使用:
全局作用域
變量提升
JavaScript中可以引用稍后聲明的變量,而不會(huì)引發(fā)異常,這概念成為變量聲明提升(hoisting)
console.log(a); //undefined
var a=2;
等同于
var a;
console.log(a);
a=2;
函數(shù)
一個(gè)函數(shù)就是一個(gè)可以被外部代碼調(diào)用 ( 或者函數(shù)本身遞歸調(diào)用 ) 的子程序
定義函數(shù)
- 函數(shù)聲明
- 函數(shù)表達(dá)式
- Function 構(gòu)造函數(shù)
- 箭頭函數(shù)
function fn(){}
var fn=functoin(){}
var fn=new Function(arg1,arg2,...argN,funcBody);//和eval一樣進(jìn)入了javascript解釋內(nèi)核中,幾乎不用
var fn=(params)=>{}
arguments
- arguments:一個(gè)包含了還遞給當(dāng)前執(zhí)行函數(shù)參數(shù)的類似于數(shù)組的對(duì)象
- arguments.length:傳給函數(shù)的參數(shù)的數(shù)目,實(shí)參
function foo(){
return arguments;
}
foo(1,2,3); //Arguments[3]
//{"0":1,"1":2,"2":3}
rest
對(duì)arguments的一種優(yōu)化
function foo(...args){
return args;
}
foo(1,2,3); //Array[3]
//[1,2,3]
function fn(a,b,...args){
return args;
}
fn(1,2,3,4,5);
//[3,4,5] 返回?cái)?shù)組
default
function fn(a=2,b=3){
return a+b;
}
fn(2,3); //5
fn(2); //5
fn(); //5
對(duì)象
JavaScript中對(duì)象是可變 鍵控集合 (keyed colletions)
定義對(duì)象
- 字面量
- 構(gòu)造函數(shù)
var obj={
prop:'value',
fn:function(){}
}
var date=new Date();
構(gòu)造函數(shù)
構(gòu)造函數(shù)和普通函數(shù)并沒有區(qū)別,使用new關(guān)鍵字調(diào)用就是構(gòu)造函數(shù),使用構(gòu)造函數(shù)可以是實(shí)例化一個(gè)對(duì)象
函數(shù)的返回值有兩種可能
- 顯式調(diào)用
return返回return后表達(dá)式的求值 - 沒有調(diào)用
return返回undefined
function People(name,age){
this.name=name;
this.age=age;
}
var people=new People('Byron',26);
構(gòu)造函數(shù)的返回值
- 沒有返回值
- 簡(jiǎn)單數(shù)據(jù)類型
- 對(duì)象類型
前兩種情況構(gòu)造函數(shù)返回構(gòu)造對(duì)象的實(shí)例,實(shí)例化對(duì)象正是利用的這個(gè)特性
第三種構(gòu)造函數(shù)和普通函數(shù)表現(xiàn)一致,返回 return 后表達(dá)式的結(jié)果
prototype
- 每個(gè)函數(shù)都有一個(gè)
prototype的對(duì)象屬性,對(duì)象內(nèi)有一個(gè)constructor屬性,默認(rèn)指向函數(shù)本身 - 每個(gè)對(duì)象都有一個(gè)
__proto__的屬性,屬性指向父類型的prototype
function Person(name){
this.name=name;
}
Person.prototype.print=function(){
console.log(this.name);
}
var p1=new Person('Jacket');
console.log(p1);

this和作用域
作用域可以通俗的理解
- 我是誰
- 我有哪些馬仔
其中我是誰的回答就是 this
馬仔就是我的局部變量
this 場(chǎng)景
普通函數(shù)
- 嚴(yán)格模式:undefined
- 非嚴(yán)格模式: 全劇對(duì)象
1) Node:global
- 瀏覽器:window
- 瀏覽器:window
構(gòu)造函數(shù):對(duì)象的實(shí)例
對(duì)象方法:對(duì)象本身
call&apply
- fn.call(context,arg1,arg2,...,argn)
- fn.apply(context,args)
通過其他函數(shù)調(diào)用這個(gè)方法產(chǎn)生一個(gè)函數(shù)作用域
function isNumber(obj){
//傳入的實(shí)參去調(diào)用Object原型鏈上的toString方法,而不用自己本身的toString方法
return Object.prototype.toString.call(obj)==='[object Number]';
}
Function.prototype.bind
根據(jù)這個(gè)函數(shù)生成一個(gè)新的函數(shù),這個(gè)新的函數(shù)作用域被我改掉了,老的是不變的
bind 返回一個(gè)新函數(shù),函數(shù)的作用域?yàn)?
bind參數(shù)
function fn(){
this.i=0;
setInterval(function(){
console.log(this.i++);
}.bind(this),500);
}
fn();
執(zhí)行結(jié)果
0
1
2
3
...
setInterval函數(shù)里面本來作用域this是undefined,通過綁定fn里面的this,將this傳進(jìn)去
箭頭函數(shù)
箭頭函數(shù)是ES6提供的新特性,是簡(jiǎn)寫的函數(shù)表達(dá)式,擁有詞法作用域和this值
function fn(){
this.i=0;
setInterval(()=>{
//this指向外面的this
console.log(this.i++);
},500);
}
fn();
執(zhí)行結(jié)果和上面一樣
繼承
在JavaScript的場(chǎng)景,繼承有2個(gè)目標(biāo),子類需要得到父類的:
1.對(duì)象的屬性(得到父類的屬性)
2.對(duì)象的方法(得到父類的方法)
function inherits(child,parent){
//創(chuàng)建一個(gè)parent.prototype的副本(淺拷貝)
var _prototype=Object.create(parent.prototype);
//_prototype的constructor.name指向的是parent的name,重新賦值child.constructor
_prototype.constructor=child.prototype.constructor;
child.prototype=_prototype;
}
function People(name,age){
this.name=name;
this.age=age;
}
People.prototype.getName=function(){
return this.name;
}
//English繼承People的方法,當(dāng)English新增方法不改變父級(jí)的方法
//English.prototype=People.prototype按址引用,English改變People也改變
//寄生式組合繼承
function English(name,age,language){
People.call(this,name,age);
this.language=language;
}
inherits(English,People);
ES6 class 與繼承
"use strict";
class People{
constructor(name,age){
this.name=name;
this.age=age;
}
getName(){
return this.name;
}
}
class English extends People{
constructor(name,age,language){
//調(diào)用父類構(gòu)造函數(shù),如果子類和父類構(gòu)造函數(shù)相同,可不寫constructor
//如果寫了constructor,沒調(diào)super,就不能繼承父類的方法了
super(name,age);
this.language=language;
}
introduce(){
console.log('I am '+this.getName);
console.log('I speak '+this.language);
}
}
語法 label statement
語句與表達(dá)式
可以解釋成語句的不會(huì)解釋成表達(dá)式
var x={a:1} //表達(dá)式 //{a:1}
{a:1} //語句 //{}里面的a是語句,1是表達(dá)式,輸出1
{a:1,b:2} //逗號(hào)是表達(dá)式,b:2會(huì)報(bào)錯(cuò)
立即執(zhí)行函數(shù)
//()里面必須是表達(dá)式,function(){}()要按照表達(dá)式來執(zhí)行
//function(){}為方法聲明,function(){}()為方法調(diào)用
(function(){}());
(function(){})();
[function(){}()];
~function(){}();
!function(){}();
+function(){}();
-function(){}();
delete function(){}();
typeof function(){}(); //typeof是一種運(yùn)算符
void function(){}();
new function(){}();
var f=function(){}();
1,function(){}();
1^function(){}();
1>function(){}();
高階函數(shù)
高階函數(shù)是把函數(shù)當(dāng)作參數(shù)或者返回值是函數(shù)的函數(shù)
回調(diào)函數(shù)
[1,2,3,4].forEach(function(item){
console.log(item);
})
閉包
函數(shù)的嵌套,并且對(duì)外提供訪問,產(chǎn)生閉包
閉包由兩部分組成
- 函數(shù)
- 環(huán)境:函數(shù)創(chuàng)建時(shí)作用域內(nèi)的局部變量
function makeCounter(init){
var init=init||0;
return function(){
return ++init;
}
}
var counter=makeCounter(10);
console.log(makeCounter());
console.log(makeCounter());
典型錯(cuò)誤
for(var i=0;i<dom.length;i++){
dom.eq(i).on('click',function(){
console.log(i);
})
}
for(var i=0;i<dom.length;i++){
(function(i){
dom.eq(i).on('click',function(){
console.log(i);
})
})(i)
}
惰性函數(shù)
function eventBinderGenerator(){
if(window.addEventListener){
return function(element,type,handler){
element.addEventListener(type,handler,false);
}
}else{
return function(element,type,handler){
element.attachEvent('on'+type,handler.bind(element,window.event));
}
}
}
//第一次執(zhí)行就把函數(shù)執(zhí)行的結(jié)果保存下來,下次執(zhí)行不會(huì)再去判斷
var addEvent=eventBinderGenerator();
柯里化
一種允許使用部分參數(shù)生成函數(shù)的方式
function isType(type){
return function(obj){
return Object.prototype.toString.call(obj)==='[object '+ type ']';
}
}
var isNumber=isType('Number');
console.log(isNumber(1));
console.log(isNumber('s'));
function f(n){
reuturn n*n;
}
function g(n){
return n*2;
}
console.log(f(g(5)));
function pipe(f,g){
return f.call(null,g.apply(null,arguments));
}
var fn=pipe(f,g);
console.log(fn(5));
尾遞歸
- 尾調(diào)用是指某個(gè)函數(shù)的最后一步是調(diào)用另一個(gè)函數(shù)
- 函數(shù)調(diào)用自身,稱為遞歸
- 如果尾遞歸自身,就稱為尾遞歸
遞歸很容易發(fā)生棧溢出錯(cuò)誤(stack overflow)
反柯里化
Function.prototype.uncurry=function(){
return this.call.bind(this);
}
push 通用化
var push=Array.prototype.push.uncurry();
var arr=[];
push(arr,1);
push(arr,2);
push(arr,3);
console.log(arr);