這段時間忽然發現JS原生好多東西都忘記了,但有些東西確實很重要,因此又從新再梳理一次。主要有函數的3種定義方法,ES5函數this指向,call與appl用法,JS常見的4種設計模式,原型鏈,原型鏈和繼承的方式(ES5和ES6)
//ES5 function getSum(){} function (){}//匿名函數 //ES6 ()=>{}//若是{}內容只有一行{}和return關鍵字可省,
//ES5 var sum=function(){} //ES6 let sum=()=>{}//若是{}內容只有一行{}和return關鍵字可省,
var sum=new GetSum(num1,num2)
1.函數聲明有預解析,並且函數聲明的優先級高於變量;
2.使用Function構造函數定義函數的方式是一個函數表達式,這種方式會致使解析兩次代碼,影響性能。第一次解析常規的JavaScript代碼,第二次解析傳入構造函數的字符串html
在ES5中函數內容的this指向和調用方法有關node
包括函數名()和匿名函數調用,this指向windowes6
function getSum() { console.log(this) //window } getSum() (function() { console.log(this) //window })() var getSum=function() { console.log(this) //window } getSum()
對象.方法名(),this指向對象設計模式
var objList = { name: 'methods', getSum: function() { console.log(this) //objList對象 } } objList.getSum()
new 構造函數名(),this指向構造函數數組
function Person() { console.log(this); //指向構造函數Person } var personOne = new Person();
利用call和apply來實現,this就是call和apply對應的第一個參數,若是不傳值或者第一個值爲null,undefined時this指向windowapp
function foo() { console.log(this); } foo.apply('我是apply改變的this值');//我是apply改變的this值 foo.call('我是call改變的this值');//我是call改變的this值
箭頭函數不能夠看成構造函數使用,也就是不能用new命令實例化一個對象,不然會拋出一個錯誤
箭頭函數的this是和定義時有關和調用無關
調用就是函數調用模式dom
(() => { console.log(this)//window })() let arrowFun = () => { console.log(this)//window } arrowFun() let arrowObj = { arrFun: function() { (() => { console.log(this)//arrowObj })() } } arrowObj.arrFun();
1.IE5以前不支持call和apply,bind是ES5出來的;
2.call和apply能夠調用函數,改變this,實現繼承和借用別的對象的方法;函數
調用方法,用一個對象替換掉另外一個對象(this)
對象.call(新this對象,實參1,實參2,實參3.....)
對象.apply(新this對象,[實參1,實參2,實參3.....])性能
1.間接調用函數,改變做用域的this值
2.劫持其餘對象的方法this
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({})
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指向
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('男')
同:都是改變this指向,均可接收參數
異:bind和call是接收單個參數,apply是接收數組
類型 | 概念 | 應用 |
---|---|---|
節流 | 某個時間段內,只執行一次 | 滾動條,resize事件一段時間觸發一次 |
防抖 | 處理函數截止後一段時間依次執行 | scroll,resize事件觸發完後一段時間觸發 |
節流:
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)); //事件處理函數
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));
對象繼承屬性的一個鏈條
var Person = function (name) { this.name = name; }//person是構造函數 var o3personTwo = new Person('personTwo')//personTwo是實例
原型對象都有一個默認的constructor屬性指向構造函數
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('張三');
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原型鏈
JS是一門弱類型動態語言,封裝和繼承是他的兩大特性
將父類的實例做爲子類的原型
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;
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } (function(){ // 建立一個沒有實例方法的類 var Super = function(){}; Super.prototype = Animal.prototype; //將實例做爲子類的原型 Cat.prototype = new Super(); })();
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繼承的實現方式
函數的參數是函數或返回函數
map,reduce,filter,sort
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) } }
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"));
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...