1. 程式人生 > >js前端技術

js前端技術

一、前端技術

1、HTML

HTML(hypertext markup language)超文字標記語言,不同於程式語言。

超文字就是超出純文字的範疇,描述文字的顏色、大小、字型。

 

HTML由一個個標籤組成,標籤各司其職,有的提供網頁資訊,有的負責圖片,有的負責網頁佈局。

 

超文字需要顯示,就得有軟體呈現超文字定義的排版格式,,例如顯示圖片、表格、顯示字型的大小,顏色,軟體就是瀏覽器。

 

超文字的誕生是為了解決純文字不能格式顯示問題,是為了好看,但是隻用通過網路分享超文字的內容,所以制定了HTTP協議。

 

2、瀏覽器

1)歷史、1980年代,tim berners-Lee為cern設計基於超文字思想的enquire,以促進科研人員之間資訊更新和共享。19899年其編寫了《資訊化管理;建議》一文,並構建基於Internet的hypertext系統,並在cern開發了world wide web專案。打造了世界上第一站。於1991年8月6日上線。

 

Tim berners-lee於1990年發明了第一個瀏覽器,還發明瞭HTTP協議。

1994年MIT建立了w3c。w3c全球資訊網聯盟,負責全球資訊網持續發展,提出w3c的標準應該基於無專利權、無版稅。

 

Marc Andreessen於1993年發明了mosaic瀏覽器,看到了技術前景,不久後成立自己的公司---網景公司Netscape,1994發不了Netscape navigator瀏覽器,席捲全球。

 

1995年微軟釋出IE。

 

1999年網景被aol收購,收購後,Netscape公開了瀏覽器程式碼。建立了Mozilla組織。Mozilla組織使用gecko引擎重寫瀏覽器。。

 

2003網景被解散。

 

2008年google的Chrome瀏覽器待著v8引擎橫空出世。

 

 

 

2)網景公司

HTTP cookie,解決HTTP無狀態。

Javascript

Ssl協議:

Jar格式檔案,將Java的class檔案打包壓縮,並加上簽名。

 

2012年4月9日,微軟購買800項美國線上的專利或專利授權。

 

 

3)瀏覽器技術

瀏覽器是特殊的客戶端。

瀏覽器軟體分為兩個部分
         外殼:

         外殼提供使用者互動的介面。

         核心(引擎engine)

         提供HTML,css,影象的渲染引擎。提供DOM程式設計介面。

         提供Javascript引擎。

排版(渲染)引擎

瀏覽器

說明

Gecko

Firefox

 

Trident

IE,AOL

 

Khtml

 

 

Presto

oPera

 

Webkit

Safari,Chrome

 

Blink

Chrome,Opera

 

 

Js引擎:

Jscript、tracemonkey(firefox)  v8等

 

 

使用jquery等框架來解決相容性問題。

 

3、js

是一種動態的弱型別的指令碼解釋性語言。和HTML、css秉承三大web核心技術。

 

 

 

4、ES

ECMAscript:是ecma國際組織

 

JavaScript是商品名。

2009年 ES5釋出

2015年ES6釋出

5、v8引擎

谷歌推出的,使用的是bsd協議開源。

 

 

 

二、nodejs

1、nodejs簡介

 

Nodejs是伺服器端執行JavaScript的開源、跨平臺執行環境。

作者是瑞安達爾(ryan dahl),2009年釋出,使用了v8引擎,採用時間驅動,非阻塞,非同步IO模型。

 

2012年,npm軟體包管理器誕生,通過其,可以方便的釋出,分享nodejs的庫和原始碼。

Nodejs4.0引入了ES6語言的特性。

2、安裝

國內阿里雲映象

https://npm.taobao.org/mirrors/node

Linux:

https://npm.taobao.org/mirrors/node/latest-v8.x/node-v8.11.3-linux-x64.tar.xz

 

windows:

https://npm.taobao.org/mirrors/node/latest-v8.x/node-v8.11.3-x64.msi

 

預設路徑安裝:

 

3、開發

 

Visual studio code

https://code.visualstudio.com/Download

 

 

 

 

 

4、註釋

和c、Java一樣

//單行註釋

/*comment*/  多行註釋,在語句中間使用。

 

str = 'hello' + /*comment*/ 'student'

 

5、常量和變數

識別符號

識別符號必須是字母、下劃線、美元符號和數字,但必須是字母、下劃線、美元符號開頭。,不能是數字開頭。

識別符號區分大小寫。

 

 

宣告

var  a宣告   a值為undefined   宣告全域性變數

let  b 宣告   let  塊變數,區域性變數。

const  c常量宣告時候必須賦值。後期不允許更改。明確知道一個識別符號定以後不在膝蓋,宣告的時候使用const常量,減少被修改的風險。

能給常量就不用變數。

變數和常量宣告和初始化的過程中是可以分開的。

var a

let b

console.log(a,b)

 

a = 1

b = 'a string'

console.log(a,b)

 

//const c   //不能定義,因為const定義時候必須賦值,之後不可以再次進行更改

const c = 100

console.log(c)

 

var y //只是複製,y的值為undefined

var x = 1 //規範的宣告並初始化,宣告全域性或區域性變數

 

function hello()

{

    var a    //只是宣告,a為undefined,作用域是在函式中

    a = 100   //賦值 

}

//console.log(2,a)   //丟擲錯誤,變數a未定義

 

//a = 200   //不能提升作用域

//var a = 200;hello();   //var提升作用域

//console.log(3,a)

 

 

6、資料型別

序號

名稱

說明

1

number

數值型

2

boolean

布林型,true和False

3

String

字串

4

Null

只有一個null值

5

Undefined

變數宣告未賦值的

6

Symbol

Es6新引入的型別

7

object型別

以上基本型別的複合型別,容器

ES是動態弱語言,弱型別語言,雖然先聲明瞭變數,但是變數可以重新賦值任何型別。

//string

console.log('----string-------')

console.log(a = 3+'abc',typeof(a))

console.log(a = null + 'abc',typeof(a))

console.log(a = undefined + 'abc',typeof(a))

console.log(a = true + 'abc',typeof(a))

 

//number

console.log('----number----')

console.log(a = null + 1,typeof(a))

console.log(a = undefined + 1,typeof(a))   //undefined沒有辦法轉成對應的數字,只是顯示男,not a number

console.log(a = true + 8,typeof(a))

console.log(a = false + 8,typeof(a))

 

//boolean

console.log('----bool----')

console.log(a = null + true,typeof(a))

console.log(a = null + false,typeof(a))

console.log(a = undefined + true,typeof(a))   //undefined沒有辦法轉成對應的數字

console.log(a = undefined + false,typeof(a))  //undefined,不能轉成對應的數字

console.log(a = null & true,typeof(a))

console.log(a = undefined & true,typeof(a))

 

//短路

console.log(a = null && true,typeof(a))

console.log(a = false && null,typeof(a))

console.log(a = false && 'abc',typeof(a))

console.log(a = true && 'abc',typeof(a))

console.log(a = true && '',typeof(a))

 

//null

console.log(a = null + undefined,typeof(a))

 

----string-------

3abc string

nullabc string

undefinedabc string

trueabc string

----number----

1 'number'

NaN 'number'

9 'number'

8 'number'

----bool----

1 'number'

0 'number'

NaN 'number'

NaN 'number'

0 'number'

0 'number'

null 'object'

false 'boolean'

false 'boolean'

abc string

 string

NaN 'number'

 

 

型別運算:

String:與str相加全部轉化為str型別。

Number:與number相加全部轉化為number

Boolean型別:轉為話number型別

 

 

 

弱型別,不需要強制型別轉換,會隱士的型別轉換。

 

總結:

遇到字串,加號就是拼接字串。

如果沒有遇到字串,加號就是把其他的所有的型別都當做數字處理。

Undefined特殊,因為他沒有定義值,所以是一個特殊的數字nan.

如果運算子是邏輯運算子,短路符,返回的就是短路時候的型別,沒有隱士轉換,

 

儘量使用顯示的轉換。

7、字串

將一個值利用單引號或者雙引號引起來就是字串。

Es6提供了反引號定義一個字串,可以支援多行,還可以支援插值。

字串:插值。使用反引號$符號進行插值,賦值即定義。

 

let a = 'abc'

let b = 'ced'

let c = `line1

line2

line3

`

console.log(c)

 

let name = 'tom',age = 19

console.log(`hi name is ${name},age${age}`)

 

line1

line2

line3

 

hi name is tom,age19

 

 

 

 

8、轉義字元

名稱

說明

\0

Null位元組

\b

退格符

\f

換頁符

\n

換行符

\r

回車符

\t

Tab製表符

\v

垂直製表符

\’

單引號

\”

雙引號

\

反斜槓符(\)

\XXX

由從0到377最多三位八進位制數XXX,例如\251是版權符號的八進位制序列

\xXX

由從00和FF的兩位十六進位制數字XX表示的Latin-1字元。\ x A9是版權符號的十六進位制序列

\uXXXX

由思維十六進位制數字XXXX的Unicode字元,例如,\u 00A9是版權符號的Unicode序列。見Unicode escape sequences(Unicode轉義字元)

\u{XXXXX}

Unicode程式碼點(code point)轉義字元,例如\u{2F804}相當於Unicode轉義字元\uD87E\uDc04的簡寫。

 

9、字串操作方法

let a = 'abcdefgh'

console.log(a.charAt(2))    //索引查詢字串

console.log(a[2])        //索引查詢字串

console.log(a.toUpperCase())  // 大寫

console.log(a.concat('.com'))   //拼接字串

console.log(a.slice(3))      //  切片

console.log(a.slice(3,6))    //

console.log(a.slice(-2,-1))   //負索引切片

console.log(a.slice(-2))    //負索引切片

 

c

c

ABCDEFGH

abcdefgh.com

defgh

def

g

gh

 

let url = 'www.google.com'

console.log(url.split('.'))   //以什麼進行切割

console.log(url.substr(7,2))   // 返回字串從何處開始,取多長

console.log(url.substring(7,10))  // 返回子串,從何處開始,到什麼為止

 

[ 'www', 'google', 'com' ]

gl

gle

 

 

let url1 = 'www.google.com'

console.log(url1.indexOf('com'))      //   查詢字串所在的索引

console.log(url1.replace('.com','.cn'))   //替換

console.log(url1.indexOf('gle',3))    //   向右偏移3

 

url2 = '\tmg edu \r\n'

console.log(url2.trim())       //去除兩端的空白字串

 

11

www.google.cn

7

mg edu

 

 

 

 

 

10、數值型number

在js中,資料均為雙精度浮點型範圍只能在- +(2^53-1)之間,整型不例外。

數字型別還有三種符號值:+infinity(正無窮)  -infinity(負無窮)和nan(not-a-number非數字)  

二進位制0b。

八進位制0o   

十六進位制0x

指數表示1E3(1000),2e-2(0.02)

 

常量屬性:

 

 

數字的方法;

方法

描述

Number.parseFloat()

把字串引數解析成浮點數,和全域性方法parseFloat()作用一致

Number.parseInt()

把字串解析成特定基數對應的整型數字,和全域性方法parseInt()作用一致

Number.isFinite()

判斷傳遞的值是否為有限的數字

Number.isInteger()

判斷傳遞的值是否為整數

Number.isNaN()

判斷傳遞的值是否為NaN

 

內建數學物件:Math

有絕對值,對數、指數運算、三角函式運算、最大值、最小值、隨機數、開方等運算函式。

 

console.log(Math.PI)    //3.14 PI值

console.log(Math.abs(-1))   //絕對值

console.log(Math.log2(16))   // 開方

console.log(Math.sqrt(2))    //平方根

console.log(Math.random())    //隨機數

 

11、運算子

1)算數運算子

+ - * / %

 

console.log(1/2)   //0.5

console.log(1/0)  //Infinity

console.log(5%3)   //2

console.log(parseInt(1/2))     //  0  向下取整

console.log(parseInt(3/2))     // 1   向下取整

 

console.log(Math.floor(3/2))   // 1   向下取整

console.log(Math.ceil(3/2))    // 2   向下取整

console.log(Math.round(3/2))   //  2  四捨五入

console.log(Math.round(1/2))   //  1  四捨五入

 

++和—

單目運算子,表示變數自增,自減

I++ 先用i,用完之後在加1

++I i先自增,在使用i

let i = 0

let a = i++

console.log(a,i)   //0   1

console.log(a,i++)   // 0   1

a = ++ i

console.log(a,i)    // 3  3

 

 

單目運算子是優先順序高於雙目運算子。

 

 7

i = 0;

let a = ++i+i+++i+++i; //++i + i++ i++ +i

console.log(a);        //  1   1   2    3  7

 

2)比較運算子

 

不做隱士的型別轉換寫的是===。

不做兩個等等號。嚴格相等使用三個等號。

 

console.log(100  > '200') //  false

console.log(100 > 'a')   //false

console.log(300 == '300')  //true

console.log(300 === '300')  //false

3)邏輯運算子

&&,||,!  與或非

 

4)位運算

& |  ^ ~<< >>位與,位或,異或,取反,左移,右移。

5)三元運算子

條件表示式?真值:假值

console.log(('3' > 30)?'真':'假')

 

 

 

 

6)逗號操作符

Js執行多個表示式寫在一起

 

let a = 4+5,b = true,c=a > 20?'t':'f'

console.log(a)   // 9

console.log(c)    // f

7)其他

名稱

說明

Instanceof

判斷是否屬於指定型別

Typeof

判斷型別字串

Delete

Delete操作符,刪除物件

In

 判斷指定的屬性在物件內,則返回true

console.log('a' instanceof String)  // false

console.log(1 instanceof Number)    // false

a = new String('b')                

console.log(a instanceof String)  // true

console.log(new Number(1) instanceof Number) // true

console.log(a instanceof Object) // true

 

Instance必須明確使用的型別定義變數。沒有 new方法的型別的都不是初始的型別。可以用於繼承關係的判斷。

Typeof就是返回物件的型別字串。

 

Delete刪除物件、屬性、陣列元素

 

 

 

 

8)運算子優先順序

運算子由高到低。

 

 

var trees = new Array();

 

逗號運算子優先順序最低,比賦值語句還低。

9)表示式(生產器)

function* inc()

{

    let i = 0;

    let j = 2;

    while(true){

        yield i++

        if (!j--)return  100;

    }

}

let gen = inc()

for (let i = 0 ;i<10;i++)

console.log(gen.next());

 

 

{ value: 0, done: false }

{ value: 1, done: false }

{ value: 2, done: false }

{ value: 100, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

 

每次呼叫next()方法返回一個物件,這個物件包含兩個屬性:value和done,value屬性表示本次yield表示式的返回值,done屬性為布林值,done是False表示後續還有yield語句執行,如果執行完成或者return後,done為true。

 

 

三、js語法

1、語句塊

function hello(){

    let a = 1;

    var b = 2;

    c =3

}

if (1)

{

    let d = 4;

    var e = 5;

    f = 6

    if (true){

        console.log(d)

        console.log(e)

        console.log(f)

        console.log('------')

        g = 10

        var h = 11

    }

}

 

console.log(e)

console.log(f)

console.log(g)

console.log(h)

 

4

5

6

------

5

6

10

11

 

 

大括號中都是一個作用域。

Let定義的外部不能訪問,只能是內部才能訪問。Var塊作用域,外部可以見到,普通定義外部也可見。

2、條件分支

if (cond1){

 

}

else if(cond2){

 

}

else if (cond3){

 

}

else{

   

}

 

條件False等效

 False

Undefined

Null

0

NaN

空字串(””)

3、switch..case分支語句

switch (expression){

    case label_1

        statements_1

        [break;]

 

    case label_2

        statements_2

        [break;]

    default:

        statements_def

        [break;]

}

 

 

let x = 5

switch (x){

    case 0:

        console.log('zero')

        break;

    case 1:

        console.log('one')

    case 2:

        console.log('two')

    case 3:

        console.log('three')

        break;

    case 4:

        console.log('four')

    default:

        console.log('other')

        break;

}

 

Switch…case語句都可以協程多分支結構。

 

4、for迴圈

//for ([initialExpression];[condition];[increamentExpression])

//{

  //  statement

//}

for (let i=0;i<10;i++){

    console.log(i)

}

console.log('---')

 

5、while迴圈和do….while迴圈

While (condition)

         Statement

條件滿足,進入迴圈,條件為真,繼續迴圈

do

         statement

while (condition);

先進入迴圈,然後判斷,為真就繼續迴圈。

let x = 10;

while(x--){

    console.log(x);

}

 

do{

    console.log(x);

 

}while(x++<10)

 

 

列印九九乘法表:

for (let x = 1;x<10;x++)

{   

    line = '';

    for(let y = 1;y<=x;y++)

        line += `${x}*${y}=${x*y}`;

    console.log(line)

}

 

 

5、for…in 迴圈

物件操作語句for…in用來遍歷物件的屬性

for (variable in object){

statements}

let arr =[10,20,30,40 ]

console.log(arr[2])   //30

for (let x in arr)

  console.log(x)

 

for (let index in arr)

console.log(`${index}:${arr[index]}`);

 

for (let i=0;i<arr.length;i++)

console.log(arr[i]);

 

let obj = {

  a:1,

  b:'abc',

  c:true

};

console.log(obj.a)

console.log(obj['b'])

console.log(obj.d)

console.log('++++++')

 

 

for (let x in obj)

console.log(x)  //屬性名

 

for (let key in obj)  //返回陣列的index

console.log(`${key}:${obj[key]}`);

 

30

0

1

2

3

0:10

1:20

2:30

3:40

10

20

30

40

1

abc

undefined

++++++

a

b

c

a:1

b:abc

c:true

 

for in 迴圈返回的是索引或者key,需要簡介訪問到值。

陣列反正返回的是索引,c風格for迴圈操作簡單。

6、for..of迴圈

Es6的新語法

let arr = [1,2,3,4,5]

let obj = {

  a;1,

  b:'abc',

  c:true

}

 

for (let i of arr){  //返回陣列的元素

  console.log(i)

}

 

for (let i of obj){  //異常,不可以迭代

  console.log(i)

}

 

For….of不能是迭代物件。

原因是of後面必須是一個迭代器(typeerror)

break 、continue

break結束當前迴圈

continue中斷當前煦暖,直接進入下一次迴圈。

7、for迭代的差別

function sum(arr){

  for (let x in arr){

    console.log(x,typeof(x),arr[x]);

  }

  for (let x of arr){

    console.log(x,typeof(x));

  }

  for (let x = 0;x<arr.length;x++){

    console.log(x,typeof(x),arr[x])

  }

}

 

X退出的時候還是會加一或減一。

 

四、函式及作用域

1、函式表示式

function //函式名(引數列表){

    //函式體;

    return //返回值;

}

 

function add(x,y){

    return x + y

}

 

console.log(add(3,5))

 

 

匿名函式表示式

const add = function(x,y){

    return x + y;

};

console.log(add(4,5))

 

有名字的函式表示式

const add1 = function fn(x,y){

    return x + y;

};

console.log(add1(3,4))

有名字的函式表示式,名字只能內部使用,外部不可見

 

const add2 = function _add(n){

    if (n === 1) return n;

    return n+ _add(--n)

};

console.log(add2(5))

 

 

函式、匿名函式、函式表示式的差異

函式和匿名函式,本質上是一樣的,都是函式物件,不過函式都有自己的識別符號,函式名,匿名函式需要的是藉助其他的識別符號而已。

區別在於,函式會宣告提升,函式表示式不會。

 

 

console.log(add(3,4))

 

function add(x,y){     //宣告提升

    return x + y;

};

 

console.log(sub(4,5))   //會報出異常的,提示sub未定義

const sub = function(x,y){

    return x + y;

};

 

 

 

定義函式的形式:function表示式。(有名字和匿名的),有名字的內部使用等。

 

宣告先做,呼叫後做。

 

生成器:

const counter = (function *(){

    count = 1

    while(1)

        yield count ++;

})();

 

console.log(counter.next())

 

 

 

 

2、高階函式

高階函式:函式作為引數或者返回一個函式。

const counter = function(){

    let c = 0;

    return function(){

        return c++

    };

};

const c = counter()

console.log(c())

console.log(c())

 

 

 

map函式的實現

const map = function(arr,fn){

    newarr = []

    for (i in arr){

        newarr[i] = fn(arr[i])

    }

    return newarr

};

console.log(map([1,2,3,4],function(x){

    return ++x

}));

 

 

 

 

3、箭頭函式

 

const map1 = function(arr,fn){

    newarr = []

    for (i in arr){

        newarr[i] = fn(arr[i])

    }

    return newarr

}

 

console.log(map([1,2,3,4],x =>++x))

 

 

 

// console.log(map1([1,2,3,4],x =>++x))

// console.log(map1([1,2,3,4],x=>{return ++x}))

console.log(map1([1,2,3,4],(x)=>{return ++x}))

 

 

箭頭函式就是匿名函式定義。 

去掉關鍵字function。

一個引數的時候可以省掉括號。無參和多引數的時候必須保留括號。多個引數使用逗號分隔。

有大括號的時候必須有return。

定義是定義的形式。呼叫必須加括號,因為有優先順序的問題,所以呼叫前面的利用括號抱起來。

 

箭頭函式的返回值:

如果函式體部分有多行,就需要使用{},如果有返回值使用關鍵字return。

如果只有一行語句,可以同時省略大括號和return。

只要有return語句,就不能省略大括號,有return必須有大括號。

只有一條非return語句,加上大括號,函式就是沒有返回值了。

 

Map函式:

function map(arr,fn){

    newarr1 = []

    for (i in arr)

        newarr1[i] = fn(arr[i])

    return newarr1

};  

 

console.log(map([1,2,3,4],function(x){

    return ++x;

}));

4、引數

傳參是按照位置對應的,沒有關鍵字傳參這個屬性。寫的像的話只是賦值語句。

傳參的是隻是表示式的值。

 

陣列不解構的話當做一個來進行,解構利用…

 

預設值可以進行定義的。位置傳參的,預設值往後寫

//位置傳參

const add = (x,y)=> x+y;

console.log(add(4,5));

//預設值

const add1 = (x,y=6)=>x+y;

console.log(add1(4))

//非關鍵字傳參,沒有關鍵字傳參,只是表示式

const add2 = (x,y)=>x+y;

console.log(add2(z=1,c=2))

//預設值不能放在前,否則就是轉換為3和undefined相加,加過為NaN

const add3 = (x=1,y)=>x+y;

console.log(add3(3))    //NaN

 

 

5、可變引數

(1)args

 

const sum = function(...args){

    let resule = 0;

    for (i in args){

        resule += args[i]

    };

    return resule

};

console.log(sum(2,3,4))

 

 

可變引數使用…args.

(2)arguments物件

const sum = function(...args){

    let resule = 0;

    console.log(arguments)

    for (i in args){

        resule += args[i]

    };

    return resule

};

console.log(sum(2,3,4))

 

 

{ '0': 2, '1': 3, '2': 4 }

所有的引數會儲存到一個k,v,鍵值對的字典裡面。

(3)引數解構

const add = function (x,y){

    return x+y

}

console.log(add(...[100,200,300,400,500]))   //引數解構,不需要引數一一對應的。

 

引數解構,不需要和需要的引數一一對應。

6、返回值

Return的返回值:返回的通常是幾個引數,返回的是最後一個引數的值。逗號表示式的。

const add1 = (x,y)=>{return x,y}

console.log(add1(1,2))

表示式的值:

逗號表示式,最後一個的值。

返回 的都只是一個單值。

a = (x = 5,y=6,true);

console.log(a)

 

b = (x=1,y=4,'abc');

console.log(b)

 

function c() {

    return x= 1,y=2,'abc',false;

}

 

console.log(c());

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

7、作用域

Function函式定義,是獨立的作用域,內部定義的變數外部不可以見到。

 

 

//函式作用域

function c(){

    a = 1

    var b = 2

    let c1 = 3

};

c();

console.log(a)

//console.log(b)   //  函式中var定義變數沒有方法突破,外界見不到

//console.log(c1)  //   let定義的外界見不到

 

//塊作用域

if (1){

    d = 4

    var e = 5

    let f = 6

}

console.log(d)

console.log(e)       //var 塊中定義的才會外界可以見到。

// console.log(f)      //let定義外界始終見不到

var b = 2可以提升宣告,可以突破非函式的塊作用域。

a = 1 隱士宣告不能進行提升宣告,

let a=3不能提升宣告。

嚴格模式:使用”use strict”語句放到函式的首行,或者js指令碼首行。

 

function show(i,args){

    console.log(i,args)

};

x = 100;

function fn(){

    let z = 200;

    {

        var a = 300;

        show(1,x)

        t = 'free'

        let p = 400;   

    }

    var y = 500

    show(2,z)

    show(3,x)

    show(4,a)

    show(5,t)

    //show(5.5,p) //異常,let出不來上一個語句塊

    {

        show(6,y);

        show(7,a)

        show(8,t)

        {

            show(9,a)

            show(10,t)

            show(11,z)

        }

    }

}

 

fn()

 // show(12,y)   //異常,出不了函式的y

show(13,t)

 

 // show(14,a)   //異常,a不能出函式的

 

show(15,z)   //變數宣告提升,聲明瞭z,但是還沒賦值

var z = 10;

 

 

五、js物件模型

基於原型的面嚮物件語言,而不是基於類的面嚮物件語言。

基於物件事件。

Js是基於原型的語言,只有原型物件的概念,原型物件就是一個模板,新的物件從這個物件模板構建從而獲取最初的屬性,任何物件在執行時候可以動態的增加屬性。任何一個物件都可以作為另一個物件的原型,後者就可以共享前者的屬性。

 

 

 

 

 

1、定義類

var obj = {

 

}

 

var obj1 = new Object();

var obj2 = new Object;

 

 

建立的時候必須使用new方法。

function定義的時候 大駝峰。

 

字面宣告方式。

 

2、es6之前---構造器

function Point(x,y){

    this.x = x

    this.y = y

    this.show = ()=>console.log(1,this,this.x,this.y)

};

 

console.log(Point)

p1 = new Point(4,5)

console.log(2,p1)

 

function Point3D(x,y,z){

    Point.call(this,x,y);

    this.z = z

    console.log(3,'Point 3d')

};

console.log(4,Point3D)

p2 = new Point3D(3,4,5)

console.log(5,p2)

p2.show();

 

 

[Function: Point]

2 Point { x: 4, y: 5, show: [Function] }

4 [Function: Point3D]

3 'Point 3d'

5 Point3D { x: 3, y: 4, show: [Function], z: 5 }

1 Point3D { x: 3, y: 4, show: [Function], z: 5 } 3 4

 

 

(1)定義一個函式(構造器)物件,函式名首字母大寫。

(2)This指代是當前例項的本身。定義屬性。

(3)使用new和構造器建立一個通用物件。New操作符會將新的物件的this值傳遞給point3d構造器函式,函式為這個物件建立z屬性。

 

如果不使用new方法,就是普通的函式呼叫,this不代表例項。

 

 

3、es6中的class

(1)class

Es6開始,提供了關鍵字class,建立物件更加簡單、清晰。

(1)利用關鍵字class,建立的本質上還是一個函式,是特殊的函式。

(2)一個類只能擁有一個名為constructor的構造器方法,如果沒有顯示定義一個構造方法,,就會預設新增一個constructor方法。

(3)繼承使用extends關鍵字

(4)一個構造器可以使用super關鍵字來呼叫父類的建構函式。

(5)類沒有私有屬性。

 

class Point{

    constructor(x,y){

        this.x = x

        this.y = y

    }

    show(){

        console.log(this,this.x,this.y)

    }

}

let p1 = new Point(10,11)

p1.show()

 

class Point3D extends Point{

    constructor(x,y,z){

        super(x,y);

        this.z = z

    }

}

let p2 = new Point3D(4,5,6)

p2.show()

 

Point { x: 10, y: 11 } 10 11

Point3D { x: 4, y: 5, z: 6 } 4 5

 

重新寫show方法;

class Point{

    constructor(x,y){

        this.x = x

        this.y = y

    }

    show(){

        console.log(this,this.x,this.y)

    }

}

p1 = new Point(1,2)

console.log(p1)

class Point3D extends Point{

    constructor(x,y,z){

        super(x,y)

        this.z= z

       

    }

    show(){

        console.log(this ,this.x,this.y,this.z)

    }

}

 

p2 = new Point3D(3,4,5)

console.log(p2)

 

子類中直接重寫父類的方法即可,如果需要使用父類的方法,使用super.method()的方式呼叫。

 

使用箭頭函式修改:

class Point{

    constructor(x,y){

        this.x = x

        this.y = y

        this.show = ()=>console.log('point')

    }

}

//繼承關係

class Point3D extends Point{

    constructor (x,y,z){

        super(x,y,z)

        this.z = z

        this.show=()=>console.log('point3d')

    }

}

 

let p2 = new Point3D(3,4,5);

p2.show()

 

 

point3d

 

子類覆蓋,最終顯示的結果是point

class Point{

    constructor(x,y){

        this.x = x

        this.y = y

        this.show =()=>

            console.log('point')

    }

}

 

class Point3D extends Point{

    constructor(x,y,z){

        super(x,y)

        this.z = z

        //this.show=()=>console.log('Point3d')   

    }

     show(){

        console.log('point3d')

     }

}

 

優先使用例項的方法,show方法,使用this的方法。

class Point{

    constructor(x,y){

        this.x = x

        this.y = y

        //this.show =()=>

          //  console.log('point')

    }

    show(){

        console.log(this,this.x,this.y)

    }

}

 

class Point3D extends Point{

    constructor(x,y,z){

        super(x,y)

        this.z = z

        this.show=()=>console.log('Point3d')   

    }

     //show(){

       // console.log('point3d')

     //}

}

 

let p1 = new Point3D(2,3,4)

console.log(p1)

p1.show()

 

 

 

 

屬性優先,一定先用屬性。優先使用子類的屬性。

 

總結:如果子類和父類使用同一種方式進行定義,子類覆蓋父類的。

如果父類使用的屬性,子類使用的是方法,那麼就是採用父類的屬性。

如果子類使用的屬性,父類是方法,那麼優先使用的是子類的屬性方法。。

 

 

最終總結,屬性優先。。同一類定義的,子類優先

 

 

靜態屬性:

靜態方法沒有很好的支援的。

 

(2)靜態方法:

在方法名前面加上static,就是靜態方法了。

 

class Add{

    constructor(x,y){

        this.x = x

        this.y = y

    }

    static show(){

        console.log(this.x)  //this是Add   不是Add的例項

    }

}

 

a = new Add(2,3)

console.log(a)

 //a.show()    例項不能直接訪問靜態方法

a.constructor.show()  //例項可以通過constructor構造器方法訪問靜態方法。

 

 

靜態方法總結:例項不能直接訪問靜態方法,例項必須通過constructor方法訪問靜態方法。

靜態成員必須使用類來定義的。

例項是自己的。

 

4、this的坑

var shcool = {

    name : 'abc',

    getNameFunc: function(){

        console.log(1,this.name)

        console.log(2,this)

        return function(){

            console.log(3,this === global);

            return this.name

        }

    }

};

console.log(4,shcool.getNameFunc()());

 

this是全域性的global的,所以第三行是true。

第四行,This是global的,所喲下面的return this.name沒有name屬性。

函式呼叫的時候呼叫的方式不用,this的物件就是不同的。

 

 

函式執行的時候,會開啟新的執行上下文環境executioncontext。

建立this屬性。

(1)myfunction(1,2,3)普通的函式呼叫,this指向的是全域性物件,全域性物件是nodejs的global或者瀏覽器的window。

(2)myObject.myFunction(1,2,3),物件的方法呼叫方式,this指向包含該方法的物件。

(3)call和apply方法的呼叫,都要看第一個引數是誰。

 

解決this的問題。

1)顯式傳入

 

var shcool1 = {

    name : 'cde',

    getNameFunc1 : function(){

        console.log(this.name)

        console.log(this);

        return function(that){

            console.log(this === global);

            return that.name;

        }

    }

}

 

console.log(shcool1.getNameFunc1()(shcool1))

 

cde

{ name: 'cde', getNameFunc1: [Function: getNameFunc1] }

true

cde

 

 

利用關鍵字that   傳入物件。主動傳入物件,避開了this的問題

2)引入call、apply方法。

var shcool2 = {

    name : 'asd',

    getNameFunc2:function(){

        console.log(this.name)

        console.log(this);

        return function(){

            console.log(this === global);

            return this.name

        }

    }

}

 

console.log(shcool2.getNameFunc2().call(shcool2));

 

 

asd

{ name: 'asd', getNameFunc2: [Function: getNameFunc2] }

false

asd

 

call方法和apply都是函式物件的方法,第一引數都是傳入物件引入的。

Apply傳其他引數需要陣列。

Call傳其他引數需要使用可變引數收集。

 

3)bind方法

var school3 = {

    name: 'asdd',

    getNameFunc3:function(){

        console.log(1,this.name)

        console.log(2,this)

        return function(){

            console.log(3,this === global);

            return this.name;

        }

    }

};

 

// console.log(school3.getNameFunc3().bind(school3));

 

var func = school3.getNameFunc3()

console.log(4,func)

 

var bindfunc = func.bind(school3)

console.log(5,bindfunc)

console.log(6,bindfunc())

 

 

1 'asdd'

2 { name: 'asdd', getNameFunc3: [Function: getNameFunc3] }

4 [Function]

5 [Function: bound ]

3 false

6 'asdd'

Apply、call方法,引數不同,呼叫時候傳入this。

。bind方法是為函式繫結this,呼叫時候直接呼叫

 

4)es6引入的箭頭函式定義

 

 

var school = {

    name :'ass',

    getNameFunc:function(){

        console.log(this)

        console.log(this.name)

        return ()=>{

            console.log(this === global);

            return this.name

        }

    }

};

console.log(school.getNameFunc()())

 

{ name: 'ass', getNameFunc: [Function: getNameFunc] }

ass

false

ass

 

 

class school{

    constructor(){

        this.name = 'abcd';

    }

    getNameFunc(){

        console.log(this.name)

&nb