<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 變量類型 ## 6種原始類型\(值類型\): 1. boolean 2. string 3. number 4. **null** 5. undefined 6. symbol \(es6\) **注意** 原始類型存儲的都是值,是不能調用方法的,像 "1".valueOf() 能調用是因為:這里的 "1" 會被自動裝箱為 String (包裝類)。 null 不是 Object,是原始類型,typeof null 會輸出 object 是因為js的bug undefined: 沒有賦值變量的默認值,自動賦值 null:表示一個變量不再指向任何對象地址 ## 引用類型 在 JS 中,除了原始類型那么其他的都是對象類型了。對象類型和原始類型不同的是,原始類型存儲的是值,對象類型存儲的是地址(指針)。當你創建了一個對象類型的時候,計算機會在內存中幫我們開辟一個空間來存放值,但是我們需要找到這個空間,這個空間會擁有一個地址(指針) ``` function test(person) { person.age = 26 person = { name: 'yyy', age: 30 } return person } const p1 = { name: 'yck', age: 25 } const p2 = test(p1) console.log(p1) // -> ? console.log(p2) // -> ? ``` * test\(p1\) 將p1的對象地址當作函數參數 * person.age = 26 會將對象p1的age也修改 * person = {name: 'yyy',age: 30} person對象的地址重新指向新對象,和p1不在綁定 * const p2 = test\(p1\) 將方法里person的地址傳遞給p2 按值傳遞的類型,復制一份存入棧內存,這類類型一般不占用太多內存,而且按值傳遞保證了其訪問速度。按共享傳遞的類型,是復制其引用,而不是整個復制其值(C 語言中的指針),保證過大的對象等不會因為不停復制內容而造成內存的浪費 ## typeof 能檢測出七種類型,值類型中null的結果是object,引用類型中出來函數顯示為Function,其他都是object,所以能檢測出七種(5個值類型對應的+1個object+1個Function。typeof 并不能準確判斷對象變量到底是什么類型 | type | 結果 | | :--- | :--- | | typeof 123 | number | | typeof '123' | string | | typeof true | boolean | | typeof undefined | undefined | | typeof Symbol\(\) | symbol | | typeof function | Function | | typeof null | object | | typeof \[1,2\] | object | | typeof {} | object | ## instanceof instanceof運算符用于測試構造函數的prototype屬性是否出現在對象的原型鏈中的任何位置 ``` [1, 2] instanceof Array const Person = function() {} const p1 = new Person() p1 instanceof Person ``` instanceof更多是用來檢測自定義對象 ## 判斷對象變量到底是什么類型的方法 ``` function is(type, obj) { var clas = Object.prototype.toString.call(obj).slice(8, -1); return obj !== undefined && obj !== null && clas === type; } is('String', 'test'); // true is('String', new String('test')); // true Object.prototype.toString 返回一種標準格式字符串,所以上例可以通過 slice 截取指定位置的字符串,如下所示: Object.prototype.toString.call([]) // "[object Array]" Object.prototype.toString.call({}) // "[object Object]" Object.prototype.toString.call(2) // "[object Number]" ``` # 類型轉換 ![](https://img.kancloud.cn/d4/70/d470ad60245385d5d8d5be1bc078ff40_910x648.jpg) # this ## this的綁定規則: 1. 在非嚴格模式下,默認綁定的this指向全局對象,嚴格模式下this指向undefined 2. 函數調用 foo\(\) 這里的this也會指向全局對象 3. test.foo\(\) this指向test對象, 指向調用者 4. new foo\(\) 在函數內部,this 指向新創建的對象。 5. 當使用 Function.prototype 上的 call 或者 apply 方法時,函數內的 this 將會被 顯式設置為函數調用的第一個參數。 ``` function a() { return () => { return () => { console.log(this) } } } console.log(a()()()) ``` 首先箭頭函數其實是沒有 this 的,箭頭函數中的 this 只取決包裹箭頭函數的第一個普通函數的 this。在這個例子中,因為包裹箭頭函數的第一個普通函數是 a,所以此時的 this 是 window。另外對箭頭函數使用 bind 這類函數是無效的。 ``` let a = {} let fn = function () { console.log(this) } fn.bind().bind(a)() // => ? ``` 可以從上述代碼中發現,不管我們給函數 bind 幾次,fn 中的 this 永遠由第一次 bind 決定,所以結果永遠是 window。 ``` var foo=function(m,n){ console.log(n); return { foo:function(o){ console.log(o); return foo(o,m); } } } //問題一: var result=foo(1); result.foo(2); result.foo(3); result.foo(4); //問題二: var result=foo(2).foo(3).foo(4).foo(5); //問題三: var result=foo(1); result.foo(2).foo(3); result.foo(4).foo(5); //問題一二三分別輸出什么? 說出執行步驟 ``` # == 和 === == 如果對比雙方的類型不一樣的話,就會進行類型轉換 ![](https://img.kancloud.cn/ad/8e/ad8e42d28ca8cb24aed5cb4d67baa948_1005x426.jpg) ``` [] == ![] // ``` === 就是判斷兩者類型和值是否相同 true, ! 的優先級比 == 大,所以 !\[\] 轉為1 即 \[\] == 1 ,對象和number判斷會將對象轉為基本類型,即 1==1 結果為true # let var const let 、const與var的區別 1. 變量不會提示,塊級作用域,使用前需要先定義,如果在聲明之前訪問這些變量,會導致報錯 2. 重復聲明報錯 3. 不綁定全局作用域,全局作用域中,let 聲明的變量不會掛在window上,var聲明的會 let和const的區別 const 用于聲明常量,其值一旦被設定不能再被修改,否則會報錯 # 閉包 ## 什么是閉包 《JavaScript高級程序設計》這樣描述: ``` 閉包是指有權訪問另一個函數作用域中的變量的函數; ``` 《JavaScript權威指南》這樣描述: ``` 從技術的角度講,所有的JavaScript函數都是閉包:它們都是對象,它們都關聯到作用域鏈。 ``` 《你不知道的JavaScript》這樣描述: ``` 當函數可以記住并訪問所在的詞法作用域時,就產生了閉包,即使函數是在當前詞法作用域之外執行。 ``` ``` function fn1() { var name = 'iceman'; function fn2() { console.log(name); } return fn2; } var fn3 = fn1(); fn3(); ``` 這樣就清晰地展示了閉包: 自由變量將從作用域鏈中去尋找,但是 依據的是**函數定義時的作用域鏈,而不是函數執行時**, 1. fn2的詞法作用域能訪問fn1的作用域 2. 將fn2當做一個值返回 3. fn1執行后,將fn2的引用賦值給fn3 4. 執行fn3,輸出了變量name ## 循環中使用閉包解決 `var` 定義函數的問題 for \(var i = 1; i &lt;= 5; i++\) { \(function\(j\) { setTimeout\(function timer\(\) { console.log\(j\) }, j \* 1000\) }\)\(i\) } ## 閉包優缺點 優點: 1. 因為在閉包內部保持了對外部活動對象的訪問,但外部的變量卻無法直接訪問內部,避免了全局污染; 2. 可以當做私有成員,彌補了因js語法帶來的面向對象編程的不足; 3. 可以長久的在內存中保存一個自己想要保存的變量. 缺點: 1. 可能導致內存占用過多,因為閉包攜帶了自身的函數作用域 2. 閉包只能取得外部包含函數中得最后一個值 # 深淺拷貝 ## 淺拷貝 對象類型在賦值的過程中其實是復制了地址,從而會導致改變了對象里的數據,其他也都會被改變,且不會拷貝對象的內部的子對象。 ## 深拷貝 JSON.parse\(JSON.stringify\(object\)\) 1. 會忽略 undefined 2. 會忽略 symbol 3. 不能序列化函數 4. 不能解決循環引用的對象 # 原型 * 所有的引用類型(數組、對象、函數),都具有對象特性,即可自由擴展屬性(null除外) * 所有的引用類型(數組、對象、函數),都有一個**proto**屬性,屬性值是一個普通的對象 * 所有的函數,都有一個prototype屬性,屬性值也是一個普通的對象 * 所有的引用類型(數組、對象、函數),**proto**屬性值指向它的構造函數的prototype屬性值 創建原型的三種方式: 第一種:字面量 ``` var o1 = {name: '01} var o2 = new Object({name: 'o2'}); ``` 第二種:構造函數 ``` function Person(name) {this.name = name;} var o3 = new M('o3'); ``` 第三種:Object.create ``` var p = {name: 'p'}; var o4 = Object.create(p); ``` # 原型鏈 當試圖得到一個對象的某個屬性時,如果這個對象本身沒有這個屬性,那么會去它的**proto**(即它的構造函數的prototype)中尋找,沒有找到,還會繼續往上找。這樣一直往上找,你會發現是一個鏈式的結構,所以叫做“原型鏈”。如果一直找到最上層都沒有找到,那么就宣告失敗,返回undefined。最上層是什么 —— Object.prototype.**proto** === null ![](https://img.kancloud.cn/d2/de/d2de9dce75674e0136ef30b8834bf070_1128x547.png) ![](https://img.kancloud.cn/f3/27/f327107efed91fcf71599551f91022c7_618x781.jpg) # new 運算符 new 運算符實現原理 ![](https://img.kancloud.cn/93/f8/93f868fd690bb13f86830cdc5be346b8_1165x512.png) # 繼承 ## 構造函數繼承 原理: 將父級的構造函數this指向到子類構造函數this上面 ``` function Person() { this.name = "person"; } function Child() { Person.call(this); this.age = 22; } ``` 缺點: 父級的原型鏈上的變量和方法無法繼承過來 ## 原型鏈繼承 原理: 子類的原型(prototype)等于父類實例 ``` function Person() { this.name = "person"; } function Child() { this.age = 22; } Child.prototype = Person.prototype; ``` 缺點: 原型中所有屬性是被很多實例共享的,共享對于函數非常合適,對于包含基本值的屬性 也還可以。但如果屬性包含引用類型就會導致改變一個就是改變所有。 ## 組合繼承 原理: 不共享的使用構造函數,共享的使用原型鏈,子類的原型等于Object.create\(父類原型\),同時覆蓋子類原型的construct 。(使用new Person \(\) 會造成父類構造函數執行兩遍。不能將父類的原型鏈(prototype)直接賦值給子類,會造成實例無法區分是使用子類還是父類創建的,因為是同一個prototype。Object.create\(\) 會創建一個中間對象,將父類和子類隔離) ``` function Person() { this.name = "person"; } function Child() { Person.call(this); this.age = 22; } Child.prototype = Object.create(Person.prototype); Child.prototype.construct = Child; ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看