JavaScript 精粹

數(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);
alt 構(gòu)造函數(shù)內(nèi)部情況

this和作用域

作用域可以通俗的理解

  • 我是誰
  • 我有哪些馬仔

其中我是誰的回答就是 this

馬仔就是我的局部變量

this 場(chǎng)景

普通函數(shù)

  • 嚴(yán)格模式:undefined
  • 非嚴(yán)格模式: 全劇對(duì)象

    1) Node:global
    1. 瀏覽器: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);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容