摘要:我們都說構(gòu)造函數(shù)開頭首字母大寫但那只是人為的規(guī)定并不是語法。只是一個(gè)操作符,任何函數(shù)都能通過來執(zhí)行,并不只是構(gòu)造函數(shù),只不過我們認(rèn)為之后的都是構(gòu)造函數(shù)。
這一篇文章主要是講述一些有關(guān)js的小知識(shí)點(diǎn)。因?yàn)槲乙膊皇呛芫囊环矫嬷荒馨炎约褐赖囊稽c(diǎn)點(diǎn)寫出來。取名大雜燴也是這意思吧,既然是道菜那么就來嘗嘗我的手藝吧。
第一道菜
1.首先,我想說一下事件綁定。
事件綁定我們都知道有:on + "type"的事件綁定還有addEventListener的事件綁定。
在以前因?yàn)楦鞣N原因?qū)е挛覀冊(cè)诓煌臑g覽器上面實(shí)現(xiàn)一樣的功能出現(xiàn)了兼容的寫法,首先我們先來看看事件綁定的兼容寫法。
function bindEvent(obj, type, handle) { if(window.addEventListener){ obj.addEventListener(type, handle, false); } if(window.attachEvent){ // IE obj.attachEvent("on" + type, handle); } obj["on" + type] = handle; }
事件解除除了on + "type"其他的就是怎么綁定怎么解除。
function delEvent(obj, type, handle) { if(window.removeEventListener){ obj.removeEventListener(type, handle, false); } if(window.detachEvent){ // IE obj.attachEvent("on" + type, handle); } obj["on" + type] = null; }
順帶提一下IE與其它瀏覽器獲取target和event的兼容方式。
function handle(e){ let event = e || window.event; // IE let target = e.target || e.srcElement; }
下一篇我會(huì)詳細(xì)介紹DOM事件綁定和DOM事件等級(jí)。
第二道菜
2.這個(gè)知識(shí)點(diǎn)我們來說一下繼承。
說到j(luò)s的繼承,我是學(xué)后端的在C ++ 、Java里面都跟js的繼承不一樣,所以一開始不好理解也覺得怪怪的。雖然ES6形式上有點(diǎn)像吧。那我們先來看看js一開始的繼承。
function Father(){ this.a = 1; } Father.prototype.show = function () { console.log(this.a); } function Son(){ Father.call(this); } let son = new Son(); console.log(son.a); console.log(son.show());
我們可以發(fā)現(xiàn)這種是拿不到父級(jí)原型上的函數(shù)的。
我們?cè)賮砜纯吹诙N
function Father(){ this.a = 1; } Father.prototype.show = function () { console.log(this.a); } function Son(){ Father.call(this); } Son.prototype = Father.prototype; //多了這一行 let son = new Son(); console.log(son.a); console.log(son.show());
我們發(fā)現(xiàn)拿到了原型上的函數(shù),但這樣就是最好的了嗎?我們一起來看看。當(dāng)我們查看Son的時(shí)候發(fā)現(xiàn)了一個(gè)奇怪的事。
我們可以看到Son的constructor變成了Father,這是為什么呢?因?yàn)閏onstructor是原型上的函數(shù),我們改變了Son的原型,因?yàn)镕ather的constructor是Father所以Son的constructor就變成了Father。而且這種方法我們改變Son.prototype時(shí)Father.prototype也會(huì)改變,那這說明我們的方法還是不夠完美。
我們?cè)賮砜纯吹谌N
function Father(){ this.a = 1; } Father.prototype.show = function () { console.log(this.a); } function Son(){ Father.call(this); } function F(){}; //借用中間層來防止Son改變Father的原型 F.prototype = Father.prototype; Son.prototype = new F(); Son.prototype.constructor = Son; //改變Son的constructor let son = new Son(); console.log(son.a); console.log(son.show()); console.log(son.constructor);
說到了構(gòu)造函數(shù)那我們就看看什么是構(gòu)造函數(shù)。
function Father(){ this.a = 1; } ```這個(gè)是不是構(gòu)造函數(shù)?如果說是那你就錯(cuò)了,因?yàn)槟闼季S固定了。我們都說構(gòu)造函數(shù)開頭首字母大寫但那只是人為的規(guī)定并不是語法。還有如果有人問你```this```是誰,你可以放肆的告訴他,你沒調(diào)用我知道是誰啊。```new```只是一個(gè)操作符,任何函數(shù)都能通過new來執(zhí)行,并不只是構(gòu)造函數(shù),只不過我們認(rèn)為```new```之后的都是構(gòu)造函數(shù)。 + 那你知道```new```的時(shí)候發(fā)生了什么嗎?我們一般都說四步走 + 首先創(chuàng)建一個(gè)新的對(duì)象。 + 改變這個(gè)對(duì)象的this + 改變這個(gè)對(duì)象的原型 + 返回這個(gè)對(duì)象 我們?cè)囍鴮懸粚?/pre>function myNew(){ let obj = {}; let Constructor = arguments[0]; obj.__proto__ = Constructor.prototype; Constructor.apply(obj, arguments); return obj; } let a = myNew(Son); console.log(a); ```
補(bǔ)充:
我們都知道ES6那么他的繼承跟我們的繼承有什么區(qū)別呢?我們來看一下ES6的繼承。class Father { constructor(){ this.a = 1; } show(){ console.log(this.a); } } class Son extends Father { constructor(){ super(); } } let son = new Son(); console.log(son.a); console.log(son.show());
我們發(fā)現(xiàn)是一樣的。只不過是這種實(shí)現(xiàn)方式更加讓人容易理解并且接受尤其是對(duì)于習(xí)慣了C++/Java之類語言的人。
其實(shí)class這種實(shí)現(xiàn)方式只是一個(gè)‘語法糖’,當(dāng)我們用typeof Son的時(shí)候我們發(fā)現(xiàn)他是一個(gè)function,其實(shí)它就是一個(gè)函數(shù)只不過更加語義化了,而且里面定義的方法其實(shí)是定義在了它的原型上面,我們輸出一下Father看看。第三道菜
3.我們?cè)賮斫榻B一下call、bind、apply
它們都是用來改變this的,只不過有一些小的差別。
call和apply除了傳參方式的不同外,沒有不同的地方。
bind返回一個(gè)函數(shù),call、apply立即執(zhí)行。
演示我覺得應(yīng)該不用了吧,因?yàn)槲也皇窃趯懳臋n,那么我們說一些什么呢,就說說怎么模擬實(shí)現(xiàn)吧。我這里用的是ES6的語法,我只是覺得這樣寫比較簡單但總體思路不變。
下面以這個(gè)為例:var a = 3; var obj = { a: 1 } function show(g) { console.log(this.a, g); }call
Function.prototype.callh = function(context){ let args = [...arguments].slice(1); //首先獲取到傳遞的參數(shù) context.fn = this; // 獲取當(dāng)前的調(diào)用者,并添加一個(gè)方法 context.fn(...args); // 傳入?yún)?shù) delete context.fn; //刪除新增的函數(shù) } show.callh(obj, 2);apply
Function.prototype.applyh = function(context){ let args = arguments[1]; // 跟call一樣,只不過apply傳進(jìn)來的是數(shù)組,所以arguments[1]指的是后面的參數(shù) context.fn = this; context.fn(...args); delete context.fn; show.applyh(obj, [2]); }bind(重點(diǎn))
// 簡易版 Function.prototype.bindh = function(context){ let args = [...arguments].slice(1); let that = this; return function (argument) { // bind返回一個(gè)函數(shù) let args2 = [...arguments].slice(0); that.call(context, ...args.concat(args2)); } } show.bindh(obj)(5);
但上面bind的方式有一點(diǎn)錯(cuò)誤。我們來看看js里面的bind和我們的在new之后有什么區(qū)別。
上面是js的后面是模擬的。看到了吧。因?yàn)樵偷脑?,我們來改進(jìn)一下。
Function.prototype.bindh = function(context){ let args = [...arguments].slice(1); let that = this; function bnd(){} let fn = function (argument) { let args2 = [...arguments].slice(0); return that.call(this instanceof fn ? this : context, ...args.concat(args2)); } bnd.prototype = this.prototype; fn.prototype = new bnd(); return fn; }這樣就行了。
第四道菜
4.再來講一講this
this一直是我們困惑的問題,有時(shí)候能看懂但代碼一多,調(diào)用一多,我們就蒙了,下面我來簡單介紹一下。
在默認(rèn)情況下this指向window(非嚴(yán)格模式)
誰調(diào)用指向誰
call.apply
bind
new
我想到的差不多就這幾種吧,你或許會(huì)發(fā)現(xiàn)其實(shí)是按this綁定的優(yōu)先級(jí)升序排序的。如果你看懂了bind的模擬實(shí)現(xiàn)也許會(huì)知道為什么bind的優(yōu)先級(jí)會(huì)高于call、apply。我覺得弄清楚這些this應(yīng)該不是多大的問題吧,來一段代碼看看。
var a = 3; var obj = { a: 1, fn(){ console.log(this.a); } + } function show() { console.log(this.a); } show(); //3 obj.fn(); //1 show.call(obj); // 1 show.apply(obj); // 1 show.bind(obj)(); // 1 show.bind(window).call(obj); //3 bind優(yōu)先級(jí)高,跟綁定順序沒區(qū)別希望這些菜能滿足您的胃口,但愿也能給您填飽一些肚子。我以后還會(huì)繼續(xù)努力提高自己的廚藝,希望嘗到這個(gè)菜的人都會(huì)喜歡。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/100698.html
摘要:前言這段時(shí)間突然發(fā)現(xiàn)原生好多東西都忘記了但有些東西確實(shí)很重要所以又重新再梳理一次。 showImg(https://segmentfault.com/img/bVbqqkr?w=874&h=382); 前言 這段時(shí)間突然發(fā)現(xiàn)JS原生好多東西都忘記了,但有些東西確實(shí)很重要,所以又重新再梳理一次。主要有函數(shù)的3種定義方法,ES5函數(shù)this指向,call與appl用法,JS常見的4種設(shè)計(jì)模...
摘要:相當(dāng)于繞過了瀏覽器端,自然就不存在跨域問題。三者的區(qū)別與服務(wù)器的交互數(shù)據(jù)始終在同源的請(qǐng)求中攜帶即使不需要,即在瀏覽器和服務(wù)器間來回傳遞。而和不會(huì)自動(dòng)把數(shù)據(jù)發(fā)給服務(wù)器,僅在本地保存。和雖然也有存儲(chǔ)大小的限制,但比大得多,可以達(dá)到或更大。 本文提供最簡便的解答方式,方便快速記憶,復(fù)盤,詳細(xì)答案可自己再搜一下。 js基礎(chǔ)知識(shí) 1. javascript typeof返會(huì)的數(shù)據(jù)類型有哪些 ob...
摘要:探討判斷橫豎屏的最佳實(shí)現(xiàn)前端掘金在移動(dòng)端,判斷橫豎屏的場景并不少見,比如根據(jù)橫豎屏以不同的樣式來適配,抑或是提醒用戶切換為豎屏以保持良好的用戶體驗(yàn)。 探討判斷橫豎屏的最佳實(shí)現(xiàn) - 前端 - 掘金在移動(dòng)端,判斷橫豎屏的場景并不少見,比如根據(jù)橫豎屏以不同的樣式來適配,抑或是提醒用戶切換為豎屏以保持良好的用戶體驗(yàn)。 判斷橫豎屏的實(shí)現(xiàn)方法多種多樣,本文就此來探討下目前有哪些實(shí)現(xiàn)方法以及其中的優(yōu)...
摘要:直搗黃龍黃龍即黃龍府,轄地在今吉林一帶,應(yīng)該是指長春市農(nóng)安縣,為金人腹地。一直打到黃龍府。指搗毀敵人的巢穴。有人會(huì)說組合優(yōu)于繼承的。的變更會(huì)自動(dòng)更新依賴的組件??梢圆僮鲗?duì)象實(shí)例,的變更會(huì)自動(dòng)更新組件,屬性設(shè)置方法調(diào)用。 刀耕火種 刀耕火種是新石器時(shí)代殘留的農(nóng)業(yè)經(jīng)營方式。又稱遷移農(nóng)業(yè),為原始生荒耕作制。 var TodoApp = Nuclear.create({ add: f...
閱讀 3111·2021-10-14 09:50
閱讀 1318·2021-10-08 10:21
閱讀 3771·2021-10-08 10:16
閱讀 3156·2021-09-27 14:02
閱讀 3208·2021-09-23 11:21
閱讀 2327·2021-09-07 10:17
閱讀 466·2019-08-30 14:00
閱讀 2203·2019-08-29 17:26