摘要:前言這段時間突然發現原生好多東西都忘記了但有些東西確實很重要所以又重新再梳理一次。
前言
這段時間突然發現JS原生好多東西都忘記了,但有些東西確實很重要,所以又重新再梳理一次。主要有函數的3種定義方法,ES5函數this指向,call與appl用法,JS常見的4種設計模式,原型鏈,原型鏈和繼承的方式(ES5和ES6)1.函數的3種定義方法 1.1 函數聲明
//ES5 function getSum(){} function (){}//匿名函數 //ES6 ()=>{}//如果{}內容只有一行{}和return關鍵字可省,1.2 函數表達式(函數字面量)
//ES5 var sum=function(){} //ES6 let sum=()=>{}//如果{}內容只有一行{}和return關鍵字可省,1.3 構造函數
var sum=new GetSum(num1,num2)1.4 三種方法的對比
1.函數聲明有預解析,而且函數聲明的優先級高于變量;
2.使用Function構造函數定義函數的方式是一個函數表達式,這種方式會導致解析兩次代碼,影響性能。第一次解析常規的JavaScript代碼,第二次解析傳入構造函數的字符串
在ES5中函數內容的this指向和調用方法有關
2.1 函數調用模式包括函數名()和匿名函數調用,this指向window
function getSum() { console.log(this) //window } getSum() (function() { console.log(this) //window })() var getSum=function() { console.log(this) //window } getSum()2.2 方法調用
對象.方法名(),this指向對象
var objList = { name: "methods", getSum: function() { console.log(this) //objList對象 } } objList.getSum()2.3 構造器調用
new 構造函數名(),this指向構造函數
function Person() { console.log(this); //指向構造函數Person } var personOne = new Person();2.4 間接調用
利用call和apply來實現,this就是call和apply對應的第一個參數,如果不傳值或者第一個值為null,undefined時this指向window
function foo() { console.log(this); } foo.apply("我是apply改變的this值");//我是apply改變的this值 foo.call("我是call改變的this值");//我是call改變的this值3.ES6中函數的調用
箭頭函數不可以當作構造函數使用,也就是不能用new命令實例化一個對象,否則會拋出一個錯誤
箭頭函數的this是和定義時有關和調用無關
調用就是函數調用模式
(() => { console.log(this)//window })() let arrowFun = () => { console.log(this)//window } arrowFun() let arrowObj = { arrFun: function() { (() => { console.log(this)//arrowObj })() } } arrowObj.arrFun();4.call,apply和bind
1.IE5之前不支持call和apply,bind是ES5出來的;
2.call和apply可以調用函數,改變this,實現繼承和借用別的對象的方法;
調用方法,用一個對象替換掉另一個對象(this)
對象.call(新this對象,實參1,實參2,實參3.....)
對象.apply(新this對象,[實參1,實參2,實參3.....])
1.間接調用函數,改變作用域的this值
2.劫持其他對象的方法
var foo = { name:"張三", logName:function(){ console.log(this.name); } } var bar={ name:"李四" }; foo.logName.call(bar);//李四 實質是call改變了foo的this指向為bar,并調用該函數
3.兩個函數實現繼承
function Animal(name){ this.name = name; this.showName = function(){ console.log(this.name); } } function Cat(name){ Animal.call(this, name); } var cat = new Cat("Black Cat"); cat.showName(); //Black Cat
4.為類數組(arguments和nodeList)添加數組方法push,pop
(function(){ Array.prototype.push.call(arguments,"王五"); console.log(arguments);//["張三","李四","王五"] })("張三","李四")
5.合并數組
let arr1=[1,2,3]; let arr2=[4,5,6]; Array.prototype.push.apply(arr1,arr2); //將arr2合并到了arr1中
6.求數組最大值
Math.max.apply(null,arr)
7.判斷字符類型
Object.prototype.toString.call({})4.3 bind
bind是function的一個函數擴展方法,bind以后代碼重新綁定了func內部的this指向,不會調用方法,不兼容IE8
var name = "李四" var foo = { name: "張三", logName: function(age) { console.log(this.name, age); } } var fooNew = foo.logName; var fooNewBind = foo.logName.bind(foo); fooNew(10)//李四,10 fooNewBind(11)//張三,11 因為bind改變了fooNewBind里面的this指向4.4 call,apply和bind原生實現
call實現:
Function.prototype.newCall = function(context, ...parameter) { context.fn = this; context.fn(...parameter); delete context.fn; } let person = { name: "Abiel" } function sayHi(age,sex) { console.log(this.name, age, sex); } sayHi.newCall (person, 25, "男"); // Abiel 25 男
apply實現:
Function.prototype.newApply = function(context, parameter) { if (typeof context === "object") { context = context || window } else { context = Object.create(null) } let fn = Symbol() context[fn] = this context[fn](parameter); delete context[fn] }
bind實現:
Function.prototype.bind = function (context,...innerArgs) { var me = this return function (...finnalyArgs) { return me.call(context,...innerArgs,...finnalyArgs) } } let person = { name: "Abiel" } function sayHi(age,sex) { console.log(this.name, age, sex); } let personSayHi = sayHi.bind(person, 25) personSayHi("男")4.5 三者異同
同:都是改變this指向,都可接收參數
異:bind和call是接收單個參數,apply是接收數組
類型 | 概念 | 應用 |
---|---|---|
節流 | 某個時間段內,只執行一次 | 滾動條,resize事件一段時間觸發一次 |
防抖 | 處理函數截止后一段時間依次執行 | scroll,resize事件觸發完后一段時間觸發 |
節流:
5.1 節流let throttle = function(func, delay) { let timer = null; return function() { if (!timer) { timer = setTimeout(function() { func.apply(this, arguments); timer = null; }, delay); } }; }; function handle() { console.log(Math.random()); } window.addEventListener("scroll", throttle(handle, 1000)); //事件處理函數5.2 防抖
function debounce(fn, wait) { var timeout = null; return function() { if (timeout !== null) clearTimeout(timeout);//如果多次觸發將上次記錄延遲清除掉 timeout = setTimeout(function() { fn.apply(this, arguments); timer = null; }, wait); }; } // 處理函數 function handle() { console.log(Math.random()); } // 滾動事件 window.addEventListener("onscroll", debounce(handle, 1000));6.原型鏈 6.1 定義
對象繼承屬性的一個鏈條
6.2構造函數,實例與原型對象的關系var Person = function (name) { this.name = name; }//person是構造函數 var o3personTwo = new Person("personTwo")//personTwo是實例
原型對象都有一個默認的constructor屬性指向構造函數
6.3 創建實例的方法1.字面量
let obj={"name":"張三"}
2.Object構造函數創建
let Obj=new Object() Obj.name="張三"
3.使用工廠模式創建對象
function createPerson(name){ var o = new Object(); o.name = name; }; return o; } var person1 = createPerson("張三");
4.使用構造函數創建對象
function Person(name){ this.name = name; } var person1 = new Person("張三");6.4 new運算符
1.創了一個新對象;
2.this指向構造函數;
3.構造函數有返回,會替換new出來的對象,如果沒有就是new出來的對象
4.手動封裝一個new運算符
var new2 = function (func) { var o = Object.create(func.prototype); //創建對象 var k = func.call(o); //改變this指向,把結果付給k if (typeof k === "object") { //判斷k的類型是不是對象 return k; //是,返回k } else { return o; //不是返回返回構造函數的執行結果 } }
更多詳情:詳談JavaScript原型鏈
6.5 對象的原型鏈 7.繼承的方式JS是一門弱類型動態語言,封裝和繼承是他的兩大特性
7.1原型鏈繼承將父類的實例作為子類的原型
1.代碼實現
定義父類:
// 定義一個動物類 function Animal (name) { // 屬性 this.name = name || "Animal"; // 實例方法 this.sleep = function(){ console.log(this.name + "正在睡覺!"); } } // 原型方法 Animal.prototype.eat = function(food) { console.log(this.name + "正在吃:" + food); };
子類:
function Cat(){ } Cat.prototype = new Animal(); Cat.prototype.name = "cat"; // Test Code var cat = new Cat(); console.log(cat.name);//cat console.log(cat.eat("fish"));//cat正在吃:fish undefined console.log(cat.sleep());//cat正在睡覺! undefined console.log(cat instanceof Animal); //true console.log(cat instanceof Cat); //true
2.優缺點
簡單易于實現,但是要想為子類新增屬性和方法,必須要在new Animal()這樣的語句之后執行,無法實現多繼承
實質是利用call來改變Cat中的this指向
1.代碼實現
子類:
function Cat(name){ Animal.call(this); this.name = name || "Tom"; }
2.優缺點
可以實現多繼承,不能繼承原型屬性/方法
為父類實例添加新特性,作為子類實例返回
1.代碼實現
子類
function Cat(name){ var instance = new Animal(); instance.name = name || "Tom"; return instance; }
2.優缺點
不限制調用方式,但不能實現多繼承
將父類的屬性和方法拷貝一份到子類中
1.子類:
function Cat(name){ var animal = new Animal(); for(var p in animal){ Cat.prototype[p] = animal[p]; } Cat.prototype.name = name || "Tom"; }
2.優缺點
支持多繼承,但是效率低占用內存
通過調用父類構造,繼承父類的屬性并保留傳參的優點,然后通過將父類實例作為子類原型,實現函數復用
1.子類:
function Cat(name){ Animal.call(this); this.name = name || "Tom"; } Cat.prototype = new Animal(); Cat.prototype.constructor = Cat;7.6 寄生組合繼承
function Cat(name){ Animal.call(this); this.name = name || "Tom"; } (function(){ // 創建一個沒有實例方法的類 var Super = function(){}; Super.prototype = Animal.prototype; //將實例作為子類的原型 Cat.prototype = new Super(); })();7.7 ES6的extends繼承
ES6 的繼承機制是先創造父類的實例對象this(所以必須先調用super方法),然后再用子類的構造函數修改this,鏈接描述
//父類 class Person { //constructor是構造方法 constructor(skin, language) { this.skin = skin; this.language = language; } say() { console.log("我是父類") } } //子類 class Chinese extends Person { constructor(skin, language, positon) { //console.log(this);//報錯 super(skin, language); //super();相當于父類的構造函數 //console.log(this);調用super后得到了this,不報錯,this指向子類,相當于調用了父類.prototype.constructor.call(this) this.positon = positon; } aboutMe() { console.log(`${this.skin} ${this.language} ${this.positon}`); } } //調用只能通過new的方法得到實例,再調用里面的方法 let obj = new Chinese("紅色", "中文", "香港"); obj.aboutMe(); obj.say();
更多詳情請戳:JS繼承的實現方式
8.高階函數 8.1定義函數的參數是函數或返回函數
8.2 常見的高階函數map,reduce,filter,sort
8.3 柯里化1.定義:只傳遞給函數一部分參數來調用它,讓它返回一個函數去處理剩下的參數
fn(a,b,c,d)=>fn(a)(b)(c)(d)
2.代碼實現:
let currying = function(fn) { // args 獲取第一個方法內的全部參數 var args = Array.prototype.slice.call(arguments, 1) return function() { // 將后面方法里的全部參數和args進行合并 var newArgs = args.concat(Array.prototype.slice.call(arguments)) // 把合并后的參數通過apply作為fn的參數并執行 return fn.apply(this, newArgs) } }8.4 反柯里化
1.定義:
obj.func(arg1, arg2)=>func(obj, arg1, arg2)
2.代碼實現:
Function.prototype.uncurrying = function() { var that = this; return function() { return Function.prototype.call.apply(that, arguments); } }; function sayHi () { return "Hello " + this.value +" "+[].slice.call(arguments); } let sayHiuncurrying=sayHi.uncurrying(); console.log(sayHiuncurrying({value:"world"},"hahaha"));8.5偏函數
1.定義:指定部分參數來返回一個新的定制函數的形式
2.例子:
function foo(a, b, c) { return a + b + c; } function func(a, b) { return foo(a,b,8); }參考文獻:
https://www.cnblogs.com/tugen...
https://www.cnblogs.com/humin...
https://www.cnblogs.com/cheng...
https://www.cnblogs.com/cheng...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/94286.html
摘要:模塊模式概念模式最初被定義為一種在傳統軟件工程中為類提供私有和共有封裝的方法。應用將暴露的公有指針指向到私有函數和屬性上參考設計模式設計模式系列文章設計模式之工廠模式設計模式之單例模式設計模式之外觀模式設計模式之模塊模式揭示模塊模式 Module(模塊)模式 概念 Module模式最初被定義為一種在傳統軟件工程中為類提供私有和共有封裝的方法。 通過這種方式,能夠使一個單獨的對象擁有共有...
摘要:實際上就是做了這樣一件事情顯式的指定是回顧一下隱式模式顯示模式觀點里所有函數都接受個參數第一個第二個是函數被調用時一定會有這個參數如果你用調用函數就是顯式的傳遞和如果你用語法直接調用函數那就去幫你偷偷的傳遞。 JS面向對象之三【this】 (對象和函數之間的關系) 上一篇,談了對象和對象的關系,現在我們談談對象和函數的關系 先說結論,也就是觀點1 觀點1: JS里函數和對象沒有關系,J...
摘要:好程序員前端培訓入門之基礎知識梳理匯總,前端工程師是當前各大企業都比較稀缺的人才,薪資待遇和就業前景都很不錯。作用域鏈的前端,始終是當前執行代碼所在環境的變量對象。 好程序員Web前端培訓入門之JS基礎知識梳理匯總,Web前端工程師是當前各大企業都比較稀缺的人才,薪資待遇和就業前景都很不錯。不論是專業還是非專業,有基礎亦或是無基礎,都想通過學習Web前端實現高薪就業。不過,學習要一...
摘要:好程序員前端培訓入門之基礎知識梳理匯總,前端工程師是當前各大企業都比較稀缺的人才,薪資待遇和就業前景都很不錯。作用域鏈的前端,始終是當前執行代碼所在環境的變量對象。 好程序員Web前端培訓入門之JS基礎知識梳理匯總,Web前端工程師是當前各大企業都比較稀缺的人才,薪資待遇和就業前景都很不錯。不論是專業還是非專業,有基礎亦或是無基礎,都想通過學習Web前端實現高薪就業。不過,學習要一...
閱讀 3122·2021-11-18 10:02
閱讀 2627·2021-10-13 09:47
閱讀 3075·2021-09-22 15:07
閱讀 807·2019-08-30 15:43
閱讀 1822·2019-08-30 10:59
閱讀 1704·2019-08-29 15:34
閱讀 1715·2019-08-29 15:06
閱讀 453·2019-08-29 13:28