摘要:效果不同事物之間的屬性即使屬性名相同,相互也不會發(fā)生沖突。命名空間的特點相互獨立,而不沖突。而函數(shù)執(zhí)行后的返回值,就是當前類的實例在構(gòu)造函數(shù)當中,類中函數(shù)中出現(xiàn)的指代當前類的一個實例,不同實例之間的方法和屬性是不同的。
對象
對象數(shù)據(jù)類型的作用:把描述同一個事物(同一個對象)的屬性和方法放在同一個內(nèi)存空間下,起到了分組的作用。
效果:不同事物之間的屬性即使屬性名相同,相互也不會發(fā)生沖突。
單例模式單例模式: 把各種屬性相同的歸類,分組的編程模式
作用:防止沖突
// 在單例模式中,把person叫做命名空間 var person = { name: "ling", age: 24 };
把描述同一件的事件,屬性,方法,放在同一個對象下,放在命名空間中.
命名空間:開辟堆內(nèi)存,把屬性名和屬性值存儲起來,地址賦值給變量,然后該變量就是作為明明空間的表示存在的,給開辟的空間起個名字叫做命名空間。
命名空間的特點:相互獨立,而不沖突。
模塊化開發(fā)
利用單例模式做模塊化開發(fā)。
模塊化開發(fā):對于一個相對來說比較大型項目,需要多人協(xié)作的開發(fā),一般情況下會根據(jù)當前項目的需求劃分成幾個功能板塊,每個人負責一部分,同時開發(fā),最后把每個人的代碼進行合并。
缺點: 生產(chǎn)效率低下,不能實現(xiàn)批量生產(chǎn).
工廠模式工廠模式:
把實現(xiàn)同一件事情的相同代碼放到一個函數(shù)中. --> 函數(shù)的封裝 --> 低耦合,高內(nèi)聚 (作用:減少頁面中的冗余代碼,提高代碼的重復利用率)
耦合 --> 相同
內(nèi)聚 --> 重復利用率
function Person (name, age) { var obj = {}; obj.name = name; obj.age = age; obj.writeJS = function() { console.log(this.name); } return obj; }
工廠模式中引出的一些概念:
繼承:子類繼承父類中的屬性和方法 多態(tài):當前方法的多種形態(tài) 后臺語言中,多態(tài)包含重載(方法名相同,參數(shù)不同,參數(shù)不同包含:參數(shù)類型和參數(shù)個數(shù))和重寫 JS 不存在重載,方法名一樣的話,后面的會把前面的覆蓋掉,最后只保存一個。 // 3year,6year // 5year,8year,10year 重寫:子類重寫父類的方法 封裝:函數(shù)的封裝,作用:低耦合,高內(nèi)聚。構(gòu)造函數(shù)模式
構(gòu)造函數(shù)模式的目的:
創(chuàng)建一個自定義類,并且創(chuàng)建這個類的實例.
構(gòu)造函數(shù)模式和工廠模式的區(qū)別?
執(zhí)行方式不同
工廠模式普通方式執(zhí)行 函數(shù)名()
構(gòu)造函數(shù)通過new函數(shù)名() 通過new執(zhí)行后,定義的函數(shù)稱之為類。而函數(shù)執(zhí)行后的返回值,就是當前類的實例
在構(gòu)造函數(shù)當中, 類中(函數(shù)中)出現(xiàn)的this.xxx = xxx; this指代當前類的一個實例,不同實例之間的方法和屬性是不同的。
注意點:
類的首字母大寫
ES5中所有的class都是數(shù)據(jù)類型,類和普通函數(shù)一樣,都形成一個私有作用域,然后形參賦值-->預解析-->代碼從上到下執(zhí)行.
JS中所有的類都是函數(shù)數(shù)據(jù)類型的,它通過new執(zhí)行變成一個類,但是實際上本身也是一個普通函數(shù),JS中所有的實例都是對象數(shù)據(jù)類型的.
構(gòu)造函數(shù)細節(jié)
在構(gòu)造函數(shù)模式中new 函數(shù)名()執(zhí)行,如果函數(shù)名()不需要傳遞參數(shù)的話,后面的小括號可以省略.
this的問題,在類中出現(xiàn)的this.xxx = xxx中this都是當前類的實例,而方法中的this需要看方法執(zhí)行的時候,前面是否有.點才能知道this是誰.
function Fn() { this.x = 10; this.getX = function() { // 需要看getX執(zhí)行時候才知道. 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();
類有普通函數(shù)的一面,當函數(shù)執(zhí)行的時候,var 變量名其實只是當前形成的私有作用域中的私有變量而已,和實例沒有任何關(guān)系.
在構(gòu)造函數(shù)模式中,瀏覽器會默認的把實例返回(返回的是一個對象數(shù)據(jù)類型)。如果手動寫了return語句:
返回的是一個基本數(shù)據(jù)類型的值,當前實例是不變的
返回的是一個引用數(shù)據(jù)類型 的值,當前的實例會被自己return的引用數(shù)據(jù)類型的值.
檢測某一個實例對象是否屬于類,使用:instanceof
檢測一個屬性是否屬于對象,使用:in , 返回true,是當前屬性.
檢測一個私有屬性是否屬于對象,(這個方法檢測私有屬性)只要有存在私有屬性,就返回true。不管是否存在共有屬性都返回true.
console.log(window.hasOwnProperty("alert")); // true
檢測一個對象是否是共有屬性:
function hasPubPrototy(obj, attr) { // 保證是它的一個屬性并且還不是私有的屬性. return (attr in obj) && !obj.hasOwnPrototype(attr); }
isPrototypeOf 測試一個對象是否存在于另一個對象的原型鏈上
原型鏈模式構(gòu)造函數(shù)模式中擁有了類和實例的概念,并且實例和實例之間是相互獨立開的 稱之為實例識別
基于構(gòu)造函數(shù)模式的原型模式解決了:方法或者屬性共有的問題(把實例之間相同的屬性和方法提取成公有的屬性和方法)
規(guī)則:
每一個函數(shù)數(shù)據(jù)類型(普通類型,類)都有一個天生自帶的屬性:prototype, 并且這個屬性是一個對象數(shù)據(jù)類型的值.
并且在prototype上瀏覽器天生給它加了一個屬性constructor(構(gòu)造函數(shù)),屬性值是當前函數(shù)(類)本身.
每一個對象數(shù)據(jù)類型(普通對象,實例,protptype,內(nèi)置對象...)也天生自帶一個屬性:__proto__, 屬性值是當前所屬類的原型.
JS中所有的類都是函數(shù)數(shù)據(jù)類型.
所有的對象類型都是Object類的實例. (對象不知道是哪個類的實例,都屬于Object類的實例)
Object是所有數(shù)據(jù)類型的基類(最底層的類)
在Object.prototype上沒有__proto__這個屬性.
原型鏈:
通過對象名.屬性名的方式獲取屬性值的時候。
首先在對象的私有屬性中查找,如果私有屬性中存在這個屬性,則獲取的是私有屬性值
如果私有屬性沒有,則通過__proto__找到所屬類的原型。(類的原型上定義的屬性和方法都是當前實例的共有的屬性和方法)
如果原型上存在的話,獲取的是共有的屬性值
如果原型上也沒有的話,則繼續(xù)通過原型上的__proto__繼續(xù)向上查找,一直找到Object.prototype為止.
基類上的也不存在,則是null
批量設(shè)置原型上的共有屬性和方法
別名
function Fn() { this.x = 100; this.y = 200; this.z = 300; } var pro = Fn.prototype; // 把原來原型指向的地址賦值給pro變量,操作同一個內(nèi)存空間 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();
重構(gòu)原型對象
瀏覽器天生給Fn.prototpye開辟的堆內(nèi)存里邊才有constructor,而如果指向新的 {}對象,沒有constructor屬性.這樣constructor指向就不是Fn而是Object。
為了和原來瀏覽器天生的Fn.prototype保持一致,需要手動的添加constructor指向
使用Fn.prototype重新指向的方式增加內(nèi)置類共有屬性
Array.prototype = { construcotr: Array, unique: function() { } } console.log(Array.prototype); // 這種方式會把已經(jīng)存在原型上的共有方法替換掉,所以使用`修改Fn.prototype指向的方法`修改內(nèi)置類的話,瀏覽器是屏蔽掉的
原型模式中this的情況
在類中this.xxx = xxx; this指代當前類的實例.
在某一個方法(私有+共有)中的this,看執(zhí)行的時候.前面是誰,this就是誰
確定this是誰,然后把this替換成對應代碼,最后按照原型鏈查找的機制,一步步的查找結(jié)果.
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
數(shù)組去重和鏈式調(diào)用
var arr = [123, 12, 2, 34, 231, 324234]; // 數(shù)組去重 Array.prototype.Unique = function() { // this var obj = {}; for (var i=0; i數(shù)組才能使用我們Array原型上定義的屬性和方法
實現(xiàn)需求:
(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 循環(huán)只遍歷私有屬性和自定義共有屬性(默認可以把自己私有屬性和它所屬類的原型上擴展的屬性和方法都可以枚舉/遍歷到),但是一般情況下只需要遍歷私有屬性。
方法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()
創(chuàng)建一個擁有指定原型和若干個指定屬性的對象.
Object.create(proObj)
創(chuàng)建對象
把第一個參數(shù)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; // 優(yōu)點:可以操作各個層級的對象,不影響其他對象。原型繼承
子類繼承父類的所有屬性和方法(私有+公有)方法:子類.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函數(shù) 執(zhí)行,讓A函數(shù)中的this變?yōu)閎實例. 和父類沒有任何關(guān)系 } 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
原型中的公共方法執(zhí)行的時候,this是誰
看方法執(zhí)行的時候,. 點前面是誰,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沒有關(guān)系 f1.__proto__.y = 2000; // 在原型上增加一個y=1000,f2也可以獲取y的值。內(nèi)置類擴展
內(nèi)置類的原型擴展方法
只要在當前實例原型鏈上,不管那一個類instancofe檢測出來的都為true
Array內(nèi)置類的原型:
擴展數(shù)組去重:
Array.prototype.unique = function unique() { var obj = {}; for (var i=0; i基于內(nèi)置類的原型擴展方法,注意,不要沖突,需要加特殊前綴,防止覆蓋已經(jīng)存在的內(nèi)置方法.
惰性思想作用: 優(yōu)化經(jīng)常被調(diào)用的函數(shù)
// 惰性思想:第一次在給utils賦值的時候我們就已經(jīng)把兼容性處理好了,把最后的結(jié)果存放在flag變量中,以后再 // 每個方法中,只要是ie6,7,8,不兼容的,不需要重新的檢測, 只需要使用flag的值即可。 var utils = (function() { // 統(tǒng)一通過一個變量來檢測 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
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/83127.html
閱讀 2079·2023-04-25 21:11
閱讀 2968·2021-09-30 09:47
閱讀 2280·2021-09-24 09:48
閱讀 4438·2021-08-23 09:43
閱讀 900·2019-08-30 15:54
閱讀 567·2019-08-28 18:01
閱讀 1404·2019-08-27 10:55
閱讀 594·2019-08-27 10:55