摘要:效果不同事物之間的屬性即使屬性名相同,相互也不會發生沖突。命名空間的特點相互獨立,而不沖突。而函數執行后的返回值,就是當前類的實例在構造函數當中,類中函數中出現的指代當前類的一個實例,不同實例之間的方法和屬性是不同的。
對象
對象數據類型的作用:把描述同一個事物(同一個對象)的屬性和方法放在同一個內存空間下,起到了分組的作用。
效果:不同事物之間的屬性即使屬性名相同,相互也不會發生沖突。
單例模式單例模式: 把各種屬性相同的歸類,分組的編程模式
作用:防止沖突
// 在單例模式中,把person叫做命名空間 var person = { name: "ling", age: 24 };
把描述同一件的事件,屬性,方法,放在同一個對象下,放在命名空間中.
命名空間:開辟堆內存,把屬性名和屬性值存儲起來,地址賦值給變量,然后該變量就是作為明明空間的表示存在的,給開辟的空間起個名字叫做命名空間。
命名空間的特點:相互獨立,而不沖突。
模塊化開發
利用單例模式做模塊化開發。
模塊化開發:對于一個相對來說比較大型項目,需要多人協作的開發,一般情況下會根據當前項目的需求劃分成幾個功能板塊,每個人負責一部分,同時開發,最后把每個人的代碼進行合并。
缺點: 生產效率低下,不能實現批量生產.
工廠模式工廠模式:
把實現同一件事情的相同代碼放到一個函數中. --> 函數的封裝 --> 低耦合,高內聚 (作用:減少頁面中的冗余代碼,提高代碼的重復利用率)
耦合 --> 相同
內聚 --> 重復利用率
function Person (name, age) { var obj = {}; obj.name = name; obj.age = age; obj.writeJS = function() { console.log(this.name); } return obj; }
工廠模式中引出的一些概念:
繼承:子類繼承父類中的屬性和方法 多態:當前方法的多種形態 后臺語言中,多態包含重載(方法名相同,參數不同,參數不同包含:參數類型和參數個數)和重寫 JS 不存在重載,方法名一樣的話,后面的會把前面的覆蓋掉,最后只保存一個。 // 3year,6year // 5year,8year,10year 重寫:子類重寫父類的方法 封裝:函數的封裝,作用:低耦合,高內聚。構造函數模式
構造函數模式的目的:
創建一個自定義類,并且創建這個類的實例.
構造函數模式和工廠模式的區別?
執行方式不同
工廠模式普通方式執行 函數名()
構造函數通過new函數名() 通過new執行后,定義的函數稱之為類。而函數執行后的返回值,就是當前類的實例
在構造函數當中, 類中(函數中)出現的this.xxx = xxx; this指代當前類的一個實例,不同實例之間的方法和屬性是不同的。
注意點:
類的首字母大寫
ES5中所有的class都是數據類型,類和普通函數一樣,都形成一個私有作用域,然后形參賦值-->預解析-->代碼從上到下執行.
JS中所有的類都是函數數據類型的,它通過new執行變成一個類,但是實際上本身也是一個普通函數,JS中所有的實例都是對象數據類型的.
構造函數細節
在構造函數模式中new 函數名()執行,如果函數名()不需要傳遞參數的話,后面的小括號可以省略.
this的問題,在類中出現的this.xxx = xxx中this都是當前類的實例,而方法中的this需要看方法執行的時候,前面是否有.點才能知道this是誰.
function Fn() { this.x = 10; this.getX = function() { // 需要看getX執行時候才知道. console.log(this, "this"); console.log(this.x); } } var f1 = new Fn(); f1.getX(); // 方法中的this是f1 --> 100 var ss = f1.getX; // 方法中的this是window --> undefined ss();
類有普通函數的一面,當函數執行的時候,var 變量名其實只是當前形成的私有作用域中的私有變量而已,和實例沒有任何關系.
在構造函數模式中,瀏覽器會默認的把實例返回(返回的是一個對象數據類型)。如果手動寫了return語句:
返回的是一個基本數據類型的值,當前實例是不變的
返回的是一個引用數據類型 的值,當前的實例會被自己return的引用數據類型的值.
檢測某一個實例對象是否屬于類,使用:instanceof
檢測一個屬性是否屬于對象,使用:in , 返回true,是當前屬性.
檢測一個私有屬性是否屬于對象,(這個方法檢測私有屬性)只要有存在私有屬性,就返回true。不管是否存在共有屬性都返回true.
console.log(window.hasOwnProperty("alert")); // true
檢測一個對象是否是共有屬性:
function hasPubPrototy(obj, attr) { // 保證是它的一個屬性并且還不是私有的屬性. return (attr in obj) && !obj.hasOwnPrototype(attr); }
isPrototypeOf 測試一個對象是否存在于另一個對象的原型鏈上
原型鏈模式構造函數模式中擁有了類和實例的概念,并且實例和實例之間是相互獨立開的 稱之為實例識別
基于構造函數模式的原型模式解決了:方法或者屬性共有的問題(把實例之間相同的屬性和方法提取成公有的屬性和方法)
規則:
每一個函數數據類型(普通類型,類)都有一個天生自帶的屬性:prototype, 并且這個屬性是一個對象數據類型的值.
并且在prototype上瀏覽器天生給它加了一個屬性constructor(構造函數),屬性值是當前函數(類)本身.
每一個對象數據類型(普通對象,實例,protptype,內置對象...)也天生自帶一個屬性:__proto__, 屬性值是當前所屬類的原型.
JS中所有的類都是函數數據類型.
所有的對象類型都是Object類的實例. (對象不知道是哪個類的實例,都屬于Object類的實例)
Object是所有數據類型的基類(最底層的類)
在Object.prototype上沒有__proto__這個屬性.
原型鏈:
通過對象名.屬性名的方式獲取屬性值的時候。
首先在對象的私有屬性中查找,如果私有屬性中存在這個屬性,則獲取的是私有屬性值
如果私有屬性沒有,則通過__proto__找到所屬類的原型。(類的原型上定義的屬性和方法都是當前實例的共有的屬性和方法)
如果原型上存在的話,獲取的是共有的屬性值
如果原型上也沒有的話,則繼續通過原型上的__proto__繼續向上查找,一直找到Object.prototype為止.
基類上的也不存在,則是null
批量設置原型上的共有屬性和方法
別名
function Fn() { this.x = 100; this.y = 200; this.z = 300; } var pro = Fn.prototype; // 把原來原型指向的地址賦值給pro變量,操作同一個內存空間 pro.getX = function() { console.log(this.x); } pro.getY = function() { console.log(this.y); } pro.getZ = function() { console.log(this.y); } var f1 = new Fn();
重構原型對象
瀏覽器天生給Fn.prototpye開辟的堆內存里邊才有constructor,而如果指向新的 {}對象,沒有constructor屬性.這樣constructor指向就不是Fn而是Object。
為了和原來瀏覽器天生的Fn.prototype保持一致,需要手動的添加constructor指向
使用Fn.prototype重新指向的方式增加內置類共有屬性
Array.prototype = { construcotr: Array, unique: function() { } } console.log(Array.prototype); // 這種方式會把已經存在原型上的共有方法替換掉,所以使用`修改Fn.prototype指向的方法`修改內置類的話,瀏覽器是屏蔽掉的
原型模式中this的情況
在類中this.xxx = xxx; this指代當前類的實例.
在某一個方法(私有+共有)中的this,看執行的時候.前面是誰,this就是誰
確定this是誰,然后把this替換成對應代碼,最后按照原型鏈查找的機制,一步步的查找結果.
function Fn() { this.x = 100; this.y = 200; this.getY = function() { console.log(this.y); } } Fn.prototype = { constructor: Fn, y: 300, getX: function() { console.log(this.x); }, getY: function() { console.log(this.y); } } var f = new Fn(); f.getX(); // 100 f.__proto__.getX(); // undefiend Fn.prototype.getX(); // undefined f.getY(); // 200 f.__proto__.getY(); // 300 Fn.prototype.getY(); // 300
數組去重和鏈式調用
var arr = [123, 12, 2, 34, 231, 324234]; // 數組去重 Array.prototype.Unique = function() { // this var obj = {}; for (var i=0; i數組才能使用我們Array原型上定義的屬性和方法
實現需求:
(5).plus(10).reduces(2) // 5+10-2 // 13
Number.prototype.plus = function(n) { console.log(this); return this + n; } Number.prototype.reduces = function(n) { return this-n; }; (5).plus(10).reduces(2); // 13繼承
可枚舉和不可枚舉
for-in 循環只遍歷私有屬性和自定義共有屬性(默認可以把自己私有屬性和它所屬類的原型上擴展的屬性和方法都可以枚舉/遍歷到),但是一般情況下只需要遍歷私有屬性。
方法1:
prototypeIsEnumerable(); 判斷可枚舉的私有屬性
Object.prototype.test = function() {} var obj = {name: "ss", age: 10}; for (var key in obj) { if (obj.prototypeIsEnumerable(key)) { console.log(obj[key]); } }
方法2:
hasOwnPrototype(); 判斷是私有屬性
Object.prototype.test = function() {} var obj = {name: "ss", age: 10}; for (var key in obj) { if (obj.hasOwnPrototype(key)) { console.log(obj[key]); } }
Object.create()
創建一個擁有指定原型和若干個指定屬性的對象.
Object.create(proObj)
創建對象
把第一個參數proObj作為當前對象的原型
var obj = { getX: function() {} }; var obj2 = Object.create(obj); obj.getX(); obj.getY = function() { console.log(0); } obj2.getY(); // 0
模擬Object.create();
// 模擬Object.create(); function object(obj) { function Tmp() {} Tmp.prototype = obj; return new Tmp(); }
使用:
function object(obj) { function Tmp() {} Tmp.prototype = obj; return new Tmp(); } var obj = { x: 100 } var newObj = object(obj); function Sum() {} Sum.prototype = object(obj); Sum.prototype.construcotr = Sum; // 優點:可以操作各個層級的對象,不影響其他對象。原型繼承
子類繼承父類的所有屬性和方法(私有+公有)方法:子類.prototype = new 父類
特點:把父類中的私有+公有的都繼承了子類原型上(子類共有).
// #div1.__proto__ -> HTMLDivElement.prototype -> HTMLElement.prototype -> Element.prototype -> Node.prototype -> EventTarget.prototype(DOM二級事件) —> Object.prototype function _Object() {} _Object.prototype = { constructor: Object, hasOwnPrototype: function() {}, toString: function() {} } function _EventTarget() {} _EventTarget.prototype = new _Object(); _EventTarget.prototype.addEventListener = function() {} function _Node() {} _Node.prototype = new _EventTarget(); _Node.prototype.createElement = function() {} var node = new _Node(); // 子類的原型 等于 父類的實例
原型繼承,并不是把父類的屬性和方法克隆一份一模一樣給子類.而是在子類和父類之間增加了原型鏈的連接.子類需要父類的方法,需要一級級向上查找。
function A() { this.x = 100; } A.prototype.getX = function() { return this.x; } function B() { thix.x = 200; } B.prototype = new A(); var b = new B();call繼承
特點:call把父類私有屬性和私有方法,克隆一份,作為子類的私有屬性和私有方法.
function A() { this.x = 100; } A.prototype.getX = function() { console.log(this.x); } function B() { // this -> b A.call(this); // A.call(b); 把A函數 執行,讓A函數中的this變為b實例. 和父類沒有任何關系 } var b = new B();冒充對象繼承
/* 冒充對象繼承 把父類私有+共有克隆一份一模一樣給子類私有 */ function A() { this.x = 100; } A.prototype.getX = function() { console.log(this.x); } function B() { var tmp = new A(); for (var key in tmp) { if (tmp.prototypeIsEnumerable(key)) { } this[key] = tmp[key]; } tmp = null; } var b = new B();混合模式繼承
混合模式繼承:原型模式+call繼承
function A() { this.x = 100; } A.prototype.getX = function() { return this.x; } function B() { A.call(this); } B.prototype = new A(); B.prototype.constructor = B; var b = new B();寄生組合式繼承
父類的原型給了子類的原型
function A() { this.x = 100; } A.prototype.getX = function() { return this.x; } function B() { A.call(this); } B.prototype = Object.create(A.prototype); // 父類的原型給了子類的原型 B.prototype.constructor = B; var b = new B();中間類繼承
function avgFn() { Array.prototype.sort.call(function(a, b) { return a - b; }); Array.prototype.pop.call(arguments); Array.prototype.shift.call(arguments); return (eval(arguments.join("+") / arguments.length)).toFixed(2); } // 中間類繼承 function avgFn() { arguments.__proto__ = Array.prototype; // Array.prototype.slice.call(arguments); arguments.sort(function(a, b) { return a - b; }).pop().shift(); return (eval(arguments.join("+") / arguments.length)).toFixed(2); }原型中的this
原型中的公共方法執行的時候,this是誰
看方法執行的時候,. 點前面是誰,this就是誰
function Fn() { this.x = 100; this.getX = function() { console.log(this.x); } } Fn.prototype.getX = function() { console.log(this.x); } Fn.prototype.setX = function(n) { this.x = n; } var f1 = new Fn(); var f2 = new Fn(); f1.getX(); // 100 f1.__proto__.getX(); // this->f1.__proto__, console.log(f1.__proto__.x); // undeinfed Fn.prototype.setX(300); // this--> Fn.prototype, Fn.prototype.x = 300 // 在公有增加x屬性 f1.getX(); // 100 f1.__proto__.getX(); // 300 f1.setX(500); // 修改私有屬性x f1.getX(); // 500 f1.__proto__.getX(); // 300 f1.y = 1000; // 給f1本身增加一個私有屬性和f2沒有關系 f1.__proto__.y = 2000; // 在原型上增加一個y=1000,f2也可以獲取y的值。內置類擴展
內置類的原型擴展方法
只要在當前實例原型鏈上,不管那一個類instancofe檢測出來的都為true
Array內置類的原型:
擴展數組去重:
Array.prototype.unique = function unique() { var obj = {}; for (var i=0; i基于內置類的原型擴展方法,注意,不要沖突,需要加特殊前綴,防止覆蓋已經存在的內置方法.
惰性思想作用: 優化經常被調用的函數
// 惰性思想:第一次在給utils賦值的時候我們就已經把兼容性處理好了,把最后的結果存放在flag變量中,以后再 // 每個方法中,只要是ie6,7,8,不兼容的,不需要重新的檢測, 只需要使用flag的值即可。 var utils = (function() { // 統一通過一個變量來檢測 ie 6,7,8. var flag = "getComputedStyle" in window; // flag存儲的變量不銷毀,存儲的是當前瀏覽器是否兼容getComputedStyle。 false,當前瀏覽器是ie6,7,8 return { listToArray: function(likeArr) { // var arr = []; // try { // arr = Array.prototype.slice.call(likeArr, 0); // } catch(e) { // for (var i=0; i
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83127.html
閱讀 2077·2023-04-25 21:11
閱讀 2966·2021-09-30 09:47
閱讀 2277·2021-09-24 09:48
閱讀 4434·2021-08-23 09:43
閱讀 899·2019-08-30 15:54
閱讀 566·2019-08-28 18:01
閱讀 1402·2019-08-27 10:55
閱讀 591·2019-08-27 10:55