函數javascript
原型(prototype)css
thisjava
new的理解閉包
1.一、預處理階段app
注意:js預處理階段會掃描全部var聲明的變量,把var聲明的變量或函數存放到詞法做用域裏,若是是變量初始值爲「undefined」,若是是函數則指向函數;ide
全局(window)函數
詞法做用域(Lexical Environment):頂級的Lexical Environment是window;測試
一、先掃描函數聲明後掃描變量(var聲明);this
二、處理函數聲明有衝突,會覆蓋;處理變量聲明時有衝突,會忽略。spa
函數
詞法做用域(Lexical Environment):每調用一次,產生一個Lexical Environment;
一、先函數的參數:好比arguments(函數內部對象,表明函數實參,可經過下標獲取調用函數時傳的實參);
二、先掃描函數聲明後掃描變量(var聲明);
三、處理函數聲明有衝突,會覆蓋;處理變量聲明時有衝突,會忽略。
1.二、執行階段
一、給預處理階段的成員賦值
二、若是沒有用var聲明的變量,會成爲最外部LexicalEnvironment的成員(即window對象的變量)
函數內部對象:arguments
<script> /*提示:*/ // arguments是每個函數內部的一個對象 // 能夠訪問實際傳遞給函數的參數的信息。 // 聲明的時候參數的個數與實際調用時無關 function add(a,b){ console.log(add.length);// 形參的個數 console.log(arguments.length);// 實際傳過來的參數 var total = 0; for(var i = 0;i< arguments.length;i++){ total += arguments[i]; } return total;// 返回實參的總和 } // 調用時傳的實參 var result = add(1,2,3,4,5); var result2 = add(1,2); console.log(result);// 15 console.log(result2);// 3 </script>
提示:js的做用域不是塊級別的;js的做用域是函數級別的。
2.一、塊做用域
2.二、函數做用域
2.三、動態做用域
2.四、詞法做用域
代碼示例:
<script> //js做用域 // 定義:用來查找變量的值的規則集;決定一個變量的範圍 // 提示:js的做用域不是塊級別的;js的做用域是函數級別的。 // javascript使用的是詞法做用域,它的最重要的特徵是它的定義過程發生在代碼的書寫階段 /*如下js代碼用當即調用寫法(私有化),避免變量衝突*/ //一、塊做用域:代碼在花括號裏面有效(js沒有塊做用域) (function(){ for(var i=0;i<5;i++){ var a = i ; } // 在花括號外面能夠訪問到i,a console.log(i);// 5 console.log(a);// 4 })(); //二、函數做用域:代碼在function()函數的花括號裏面有效 (function(){ var message = "函數外部的"; function fn(){ var message = "函數內部的"; console.log(message);// 函數內部的 } console.log(message);// 函數外部的 })(); //三、動態做用域:在運行時決定(是this指向的表現;誰調用,this指向誰);動態做用域實際上是指this的詞法做用域 // 動態做用域並不關心函數和做用域是如何聲明以及在任何處聲明的,只關心它們從何處調用。 // 換句話說,做用域鏈是基於調用棧的,而不是代碼中的做用域嵌套 (function(){ var a = 2; function foo() { console.log( a ); } function bar() { var a = 3; foo();// 此時this===window } bar();// 2 })(); /* var a = 2; bar = { a:3, foo:function(){ console.log(this.a); } } bar.foo();//3 */ //四、詞法做用域:詞法做用域(也稱爲靜態做用域或閉包) // js的做用域解析,用new Function建立函數 (function(){ // 閉包 var a = 2; function bar() { var a = 3; return function(){ console.log(a);// 此時捕獲a=3 }; } var foo = bar(); foo();// 3 })(); // 若是處於詞法做用域,也就是如今的javascript環境。變量a首先在foo()函數中查找,沒有找到。因而順着做用域鏈到全局做用域中查找,找到並賦值爲2。因此控制檯輸出2 // 若是處於動態做用域,一樣地,變量a首先在foo()中查找,沒有找到。這裏會順着調用棧在調用foo()函數的地方,也就是bar()函數中查找,找到並賦值爲3。因此控制檯輸出3 //小結:兩種做用域的區別,簡而言之,詞法做用域是在定義時肯定的,而動態做用域是在運行時肯定的 </script>
3.一、什麼是閉包
因爲在Javascript語言中,只有函數內部的子函數才能讀取局部變量,所以能夠把閉包簡單理解成「定義在一個函數內部的函數,內部函數並訪問父函數的局部變量」。
理解閉包:
一、閉包能夠理解爲一個對象,裏面包含函數以及被函數捕獲的變量 , 一個圈裏包含函數與捕獲的變量
二、也能夠只把函數捕獲的變量稱之爲閉包。
<script> //如何寫會產生閉包 function P(){ var a = 5; var b = 6; return function C(){ console.log(b);//此時捕獲變量b,值爲6 } } var result = P(); result();// 6 </script>
產生閉包的條件:
一、函數內部包含子函數;
二、子函數訪問父函數的變量;
3.二、閉包的好處
用途:一個是前面提到的能夠讀取函數內部的變量,另外一個就是讓這些變量的值始終保持在內存中。
<script> // 閉包實例 function Person(){ var age = 1; this.getAge = function(){ return age ; } this.setAge = function(val){ age = val; } } var p = new Person(); p.setAge(20); console.log(p.getAge()); </script>
代碼示例:
<script type="text/javascript"> /*閉包--理解*/ // 提示:this由運行時決定! // 題目一:理解r1與r2的輸出 function addFactory(){ var adder = 5; return function(data){ adder += data;// 此時adder變量是閉包捕獲到的值 return adder; } } var adder1 = addFactory(); var r1 = adder1(1);//6 r1 = adder1(1);//7 var adder2 = addFactory(); var r2 = adder2(2);//7 r2 = adder2(2);//9 // 題目二:下面的代碼輸出什麼 var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name;// 輸出"The Window";this = window; //return object.name;// 輸出"My object" }; } }; //alert(object.getNameFunc()());// The Window // 理解二: var fun = object.getNameFunc();// 返回一個函數,此時函數this指向window;window.fun() alert(fun());// 因此,輸出是:"The Window" // 題目三: var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this;//this = object; return function(){ return that.name;//閉包捕獲父函數的that,that = object; }; } }; alert(object.getNameFunc()());// My Object // 理解三: // var obj = object.getNameFunc(); // alert(obj());// 此時函數因爲內部的name是object調用 </script>
4.一、對象
4.二、函數
4.三、原型(prototype)
javascript對象部署:
JavaScript是一種經過原型實現繼承的語言;在JavaScript中全部都是對象,原型(prototype)也是一個對象,經過原型能夠實現對象的屬性繼承;
prototype:在js中是函數特有的屬性;指向該函數的原型(this.prototype)
__proto__:在js中是全部對象都有的屬性;指向此對象的構造器(函數)的原型對象(prototype)
<!-- 對象都有這屬性(找對象的父類對象):__proto__; 只有函數有的屬性(找函數的原型,是個對象):prototype; 對象(或函數)的構造器(頂級構造器時Function()):constructor; --> <script> function Aaa(){} //undefined var aaa = new Aaa(); //undefined aaa.__proto__; //{constructor: ƒ} Aaa.prototype; //{constructor: ƒ} aaa.__proto__ === Aaa.prototype; //true aaa.constructor; //ƒ Aaa(){} Aaa.constructor; //ƒ Function() { [native code] } aaa.constructor.constructor //ƒ Function() { [native code] } </script>
原型理解:
1. 函數Foo的__proto的值等於Foo.prototype,對嗎? 錯,函數Foo.__proto__===Function.prototype,函數Foo的實例的__proto__屬性的值等於函數Foo.prototype 2.Object的prototype能夠修改嗎?能與不能緣由是什麼? //能夠,函數(對象)的原型能夠任意修改或繼承 不能夠,由於Object.prototype是隻讀,因此不能賦值;但能夠修改或添加 3. 頂級constructor是誰? Function() 4.頂級原型對象是誰? Object 5.對象的construtor成員是個屬性仍是個方法? 能夠是屬性,也能夠是方法(通常不建議這麼寫,耗資源,在每次new是都要執行不少代碼) 6.Function有沒有__proto__,爲何?值等於Object.prototype嗎? 1.有(是對象都有),與prototype相等,由於Function是頂級構造器,因此,函數的__proto__屬性指向的構造器原型是與Function.prototype相等; 2.不等於,Function.prototype與Function.__proto__指向function.prototype 7.全部的構造器的__proto__都等於其對應的prototype 錯,等於Function.prototype;由於對象的__proto__屬性指向的是對象的構造器的prototype(函數的構造器是Function()) 8.建立類形式的繼承的四部曲是什麼? 1.建立父類 2.建立子類 3.肯定繼承關係:A.prototype = Object.create(B.prototype); 4.修改構造器(由於繼承後的構造器指向是父類的原型指向的構造器,也就是說,子類的原型指向的構造器===父類的原型指向的構造器) 9.Function的constructor於prototype值能夠修改嗎? 不能夠,Function是頂級構造器,Function.__proto__指向Function.prototype 10.Object.prototype === Object.__proto__嗎? 不相等,Object.prototype是object.prototype;Object.__proto__是function.prototype 11. Function.prototype === Function.__proto__嗎? 相等,(由於Function是頂級構造器,__proto__指向Function.prototype)Function.prototype===Function.__proto__ 12. function F(){}; var f1 = new F(); f1.__proto__ === Object.prototype嗎? 不對,f1.__proto__ === F.prototype;f1.__proto__.__proto__ === Object.prototype;
4.五、this
原則:
一、this由運行時決定!
二、函數中 this 到底指向誰 , 由調用此函數時的對象決定 , 而不是由定義函數所在的對象決定。
在JavaScript中this表示:誰調用它,this就是誰。
如何改變this指向:
call:
apply:
<script> /* var data = {}; Array.prototype.push.call(data,100,200); Array.prototype.push.apply(data,[1,2,3,8,10]); console.log(data); */ </script>
4.六、new的理解
簡單的能夠理解爲:new改變了this指向的對象;
<script type="text/javascript"> /* // 提示: // 暴露外部使用的一個接口 var jQuery = window.jQuery = window.$ = function(selector){ return new jQuery.fn.init(selector); } // 處理原型對象 jQuery.fn = jQuery.prototype = {} jQuery.fn.init.prototype = jQuery.fn; // 實現繼承,而且只處理只有一個參數,也就是插件的擴展 jQuery.extend = jQuery.fn.extend = function(){} // 添加靜態方法 jQuery.extend({}); // 添加實例方法 jQuery.fn.extend({}); // 1.獲取節點對象 var jq1 = jQuery(".pp"); 或 var jq1 = jQuery.fn.init(".pp"); */ // 提供全局訪問接口($()、jQuery()) (function () { /// 暫時把window的全局變量存起來,用作處理變量衝突 var _$ = window.$; var _jQuery = window.jQuery; //暴露外部使用的一個接口(獲取節點對象) var jQuery = window.jQuery = window.$ = function(selector){ return new jQuery.fn.init(selector);// init.prototype; }; //處理原型對象 jQuery.fn = jQuery.prototype = { init:function(selector){ var elements = document.querySelectorAll(selector); Array.prototype.push.apply(this,elements); return this; }, version:"1.0.0", length:0, size:function(){ return this.length; } }; // jQuery.fn.init.prototype === init.prototype; // jQuery.prototype; jQuery.fn.init.prototype = jQuery.fn; //實現繼承,而且只處理只有一個參數,也就是插件的擴展 jQuery.extend = jQuery.fn.extend = function(){ var o = arguments[0]; for(var p in o){ this[p] = o[p]; } }; /// 測試:(繼承方法) // var obj = {name:"張三三"} // var jq = $(".pp"); // jq.extend(obj); //添加靜態方法 jQuery.extend({ trim:function(text){ return (text||"").replace(/^\s+|\s+$/g,"");// 替換text字符串的開頭和結尾匹配任何空白字符爲空(即,替換開頭和結尾的空格字符爲空) }, noConflict:function(){ window.$ = _$; window.jQuery = _jQuery; return jQuery; } }); /// 測試:(命名衝突) // var jq = jQuery.noConflict();//返回一個jQuery函數,解決與全局的jQuery屬性衝突 // var obj = jq(".pp"); //添加實例方法 jQuery.fn.extend({ get:function(num){ return this[num]; }, each:function(fn){ for(var i = 0 ;i< this.length; i++){ fn(i,this[i]); } return this; }, css:function(){ var l = arguments.length; if(l == 1){ return this[0].style[arguments[0]]; } else { var name = arguments[0]; var value = arguments[1]; this.each(function(index,ele) { ele.style[name] = value; }); } return this; } }); })(); </script>