[toc]
## previously
JS中的對象和函數匯總
>對象數據類型的值
>- `{}`普通對象
> - `[]` 數組
> - `/^$/` 正則
> - `Math` 數學函數
> - 一般類的實例都是對象數據類型
> - 函數的`prototype`屬性
>
> - 實例的`__proto__`屬性
> - ...
>
> 函數數據類型值
> - 普通函數
> - 所有的類(內置類和自定義類)
> - ...
```
typeof Object === 'function'
typeof String === 'function'
typeof Fn === 'function'
```
## 原型(xx.prototype)
>1、 所有的函數都天生自帶一個屬性:prototype(原型),它是一個對象數據類型的值,在這個對象中存儲了為其類的實例提供的公共屬性和方法。
>
>2、 prototype這個對象,瀏覽器會默認為其開辟一個堆內存,在這個堆內存中天生自帶一個屬性:constructor(構造函數),這個屬性存儲的值就是當前函數本身。
>
>3、 每一個類的實例(每一個對象)都天生自帶一個屬性:`__proto__`,屬性值是當前對象所屬類的原型(prototype)。
>
>4、 每一個類的原型的`__proto__`都指向`Object`類的原型
```
function Fn(name,age){
}
```
```
function Fn(name,age){
this.name = name;
this.age = age;
this.say = function(){
console.log(`my name is ${this.name}!i am ${this.age}years old!`)
}
}
Fn.prototype.say = function(){
console.log('hello world!');
}
Fn.prototype.eat = function(){
console.log('i love food!');
}
var f1 = new Fn('ahhh',11);
var f1 = new Fn('ahhh2',70);
```

## 原型鏈(`__proto__`)
也是一種設計模式,原型鏈模式
若一個對象下的屬性或方法在自己身上找不到,會順著`__proto__`網上找,`__proto__`指向的是另外一個對象,這個對象中有的方法和屬性,都能傳遞給下層的對象

### this問題
> 關于原型鏈中提供的私有(公有)方法中的THIS指向問題
> 1、 看點前面是誰,THIS就是誰
> f1.say():this->f1
> f1.__proto__.say():this->f1.__proto__
> Fn.prototype.say():this->Fn.prototype
> ...
>2、 把需要執行方法中的THIS進行替換
>3、 替換完成后,如果想要知道結果,值需按照原型鏈的查找機制去查找即可
### 向原型上批量增加屬性和方法
```
function Fn(name,age){
this.name = name;
this.age = age;
}
Fn.prototype.aa = function(){
};
Fn.prototype.bb = function(){
};
...
var f = new Fn('xxx',28);
```
#### 設置別名
```
//設置別名
var pro = Fn.prototype; //=>指向同一個堆內存
```
#### 重新構造原型(內置類不支持,內置類想添加方法和屬性只能一個個加)
```
Fn.prototype = {
//=>讓原型指向自己開辟的堆內存有一個問題,自己開辟的堆內存中沒有constructor這個屬性,所以實例在調取constructor的時候找到的是Object,這樣不好,此時我們應該重新設置以下constructor,保證機制的完整性
constructor:Fn
,aa:function(){
}
,bb:function(){
}
};
```
#### 基于內置類的原型擴展方法
>1、 我們新增加的方法最好設置一個前綴,防止我們新增加的方法和內置的方法沖突,把內置的方法替換掉
>2、 返回的結果依然是當前類的實例,這樣就可以繼續調取當且類的其它方法操作了。
```
//其中obj只是一個key的清單
function distinct(ary){
var obj = {};
for(var i=0;i<ary.length;++i){
var item = ary[i];
if(typeof obj[item]!=='undefined'){
ary[i] = ary[ary.length-1];
ary.length--;
i--;
continue;
}
obj[item] = item;
}
}
//內置方法的方法是一個具名函數
Array.prototype.myDistinct = function myDistinct(){
//=>this:ary當期那要處理的數組
var obj = {};
for(var i=0;i<this.length;++i){
var item = this[i];
if(typeof obj[item]!=='undefined'){
this[i] = this[this.length-1];
this.length--;
i--;
continue;
}
obj[item] = item;
}
obj = null;
return this;
}
```

## 習題
實現(3).plus(2).minus(1) =>4
>[warning] **注意:** `()`能將一個數值包裝成一個真正的數字類型的實例。(可以使用實例中的方法),其次數值類的this就是數字本身。
```
Number.prototype.plus = function plus(){
var value = Number(arguments[0])||0;
return this+arguments[0];
}
Number.prototype.minus = function minus(){
var value = Number(arguments[0])||0;
return this-arguments[0];
}
console.log((3).plus(2).minus(1))
```
## 函數
### previously
Function -> 函數類
類都天生自帶一個屬性`prototype`
它的原型上有`call`、`apply`、`bind`等方法
它的原型的`__proto__`也指向`Object.prototype`。
所有函數(包括類)都是`Function`的實例
**所有函數都是`Function`這個類的實例,So所有函數都能作為一個實例存在,也就是一個對象。**

`Object`類的`__proto__`指向`Function`,而`Function`的`prototype`指向的是`Object.prototype`。
并且`Function`的`__proto__`指向自己的prototype

`Function`的原型是**函數數據類型**的值,但相關操作和之前的一模一樣。->anonymous/Empty
### 三種角色
>函數本也會有一些自己的屬性:
>`legnth`:0 形參的個數
>`name`:“Fn”函數名
>`prototype`: 類的原型,在原型上定義的方法都是當前Fn這個類實例的公有方法
>`__proto__`:把函數當做一個普通的對象,指向Function這個類的原型
>函數在整個JS中是最復雜也是最重要ode只是
>1、 一個函數存在多面性
>->它本身就是一個普通的函數,執行的時候形成私有的作用域(閉包),形參賦值,預解釋,代碼執行,執行完成后棧內存銷毀/不銷毀
>->“類”:它有自己的實例,也有一個叫做prototype屬性是自己的原型,它的實例都指向自己的原型
>->“普通對象”:和var obj={}中的obj一樣,也是一個對象,它作為對象可以有一些自己私有的屬性,也可以通過`__proto__`找到Function.prototype
三種角色之間沒有必然聯系
```
function Fn(){
var num = 500;
this.x = 100;
}
Fn.prototype.geX = function(){
console.log(this.x);
}
Fn.aaa = 1000;
//類
var f= new Fn;
f.num -> undefined
f.aaa -> undefined;
//普通函數
var res = Fn(); //->Fn中的this是window
res = undefined;
//普通對象
Fn.aaa = 1000;
```
### call
```
//改變this關鍵字
//Function.prototype.call = function(){}
var obj = {name:'ahhh'}
function fn(){
console.log(this);
}
fn();
// obj.fn();
fn.call(obj)
//->首先我們讓原型上的call方法執行,在執行call方法的時候,我們讓fn方法中的this變為第一個參數的值,即obj;然后再把fn這個函數執行
Function.prototype.myCall = function(context){
//->myCall方法中的this就是當前我要操作和改變其this關鍵字的那個函數名
//->1、讓fn中的this關鍵字變為context的值
//->讓this這個函數中的"this關鍵字"變為context
var that = eval(this.toString().replace("this",context));
//->2、讓fn方法再執行
that();
};
fn.myCall(obj);
```
```
function fn1(){console.log(1)};
function fn2(){console.log(2)};
fn1.call(fn2);
```
```
fn1.call.call(fn2);
```
首先fn1通過原型鏈找到callFunction.prototype上的call方法,然后再讓call方法通過原型再找到Function原型上的call(因為call本身的值也是一個函數,所以同樣可以找到Function.prototype),在第二次再找到call的時候讓方法執行,方法中的this是fn1.call,首先讓這個方法中的this變為fn2,然后再讓fn1.call執行
```
var obj = {name:'ahhh'}
function fn(num1,num2){
console.log(num1+num2);
console.log(this);
}
fn.call(100,200);
fn.call(obj,100,200);
fn.call(); //this->window
fn.call(null);//this->window
fn.call(undefined);//this->window
```
嚴格模式下this指向
```
"use strict";//=>告訴當前瀏覽器接下來的JS代碼將按照嚴格模式進行編寫
fn.call(); //this->undefined
fn.call(null);//this->null
fn.call(undefined);//this->undefined
```
### apply
apply和方法的作用是一模一樣的,都是用來改變this關鍵字并且把方法執行;而且在嚴格模式下和非嚴格模式下對于第一個參數是null/undefined這種情況的規律也是一樣的
```
fn.call(obj,100,200);
fn.apply(obj,[100,200]);
```
call在給fn傳遞參數的時候,是一個個傳遞值的,而apply不是一個個傳的,而是把要給fn傳遞的參數值統一的放在一個數組中進行操作的->但是也相當于一個個的給fn的形參賦值
### bind
這個方法在IE6~8不兼容
此方法和call/apply類似,都是用來改變this關鍵字的
```
fn.call(obj,1,2); //->改變this和執行fn函數是都一起完成了
//->預處理:事先把fn的this改變為我們想要的結果,并且把對應的參數值也準備好,以后要用到了,直接執行即可
var tempFn = fn.bind(obj,1,2); //->只是改變了fn中的this為obj,并且給fn傳遞了兩個參數1、2,但此時并沒有把fn這個函數執行,執行bind會有一個返回值,這個返回值tempFn就是我們把fn的this改變后的那個結果
tempFn();
```
- 空白目錄
- window
- location
- history
- DOM
- 什么是DOM
- JS盒子模型
- 13個核心屬性
- DOM優化
- 回流與重繪
- 未整理
- 文檔碎片
- DOM映射機制
- DOM庫封裝
- 事件
- 功能組件
- table
- 圖片延遲加載
- 跑馬燈
- 回到頂部
- 選項卡
- 鼠標跟隨
- 放大鏡
- 搜索
- 多級菜單
- 拖拽
- 瀑布流
- 數據類型的核心操作原理
- 變量提升
- 閉包(scope)
- this
- 練習題
- 各種數據類型下的常用方法
- JSON
- 數組
- object
- oop
- 單例模式
- 高級單例模式
- JS中常用的內置類
- 基于面向對象創建數據值
- 原型和原型鏈
- 可枚舉和不可枚舉
- Object.create
- 繼承的六種方式
- ES6下一代js標準
- babel
- 箭頭函數
- 對象
- es6勉強筆記
- 流程控制
- switch
- Ajax
- eval和()括號表達式
- 異常信息捕獲
- 邏輯與和或以及前后自增
- JS中的異步編程思想
- 上云
- 優化技巧
- 跨域與JSONP
- 其它跨域相關問題
- console
- HTML、XHTML、XML
- jQuery
- zepto
- 方法重寫和方法重載
- 移動端
- 響應式布局開發基礎
- 項目一:創意簡歷