这段时间忽然发现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...