前端知识点汇总。一
前端知识点汇总:
1.js的闭包
-
闭包的3个特性:
函数嵌套函数
函数内部可以引用函数外部的参数和变量
参数和变量不会被垃圾回收机制回收
上面三局话啥意思? 其实个人感觉有点绕,用代码解释比较简单。///方法aaa中定义了一个变量name,name等于 “1111”。定义了一个函数 function()(此处函数嵌套函数) function aaa(){ var name = "1111" return function(){ //此处name 引用了它外部的变量。 return name } }; var b = aaa(); //运行b(),返回出来了name,说明这边的name并没有被垃圾回收。 b();
-
闭包的作用
其实上面说的特性就已经表明了闭包的作用。那我们再看一段代码来巩固一下。 -
function aaa(){ var num = 0 return function(){ return ++num } };var b = aaa();b();b();b()
此处输出值应该是多少?
-
常见场景
我们知道的闭包的特性,那我们的应该用这个闭包来做什么呢?。在哪些场景会用到呢?
在这么一个场景:客户进入页面我们就要提醒他,他今天操作了多少条单据了,大于多少条他就可以收工回家了。
那我们在他每次操作完单据,就给他触发一次方法。
示列代码:function gohome(){ var twice = 0 return function(){ return ++twice ; } }; var b = gohome();b()
突然,客户说,哎呀 我想自己填一个数值进去,你这计算的不一定准确,或者说他想早点下班。
那我们最后写成的需求就是:
function gohome(){ var twice = 0; return function(x=0){ if(x === 0) return ++twice ; return twice = twice + x; } }; var b = gohome();b(100) //可以复制到控制台自行打印
突然,客户又说,哎呀。我不想一次加一个 ,我想一次加10个!并且我要从1000开始算! 这样领导以为我干活认真!好,那就走起
function gohome(start,times){ var twice = start; return function(x=0){ twice = times + twice +x; return twice ; } }; var b = gohome(1000,10);b()//可以复制到控制台自行打印
思考:那闭包一定就好吗? 并不是,闭包只有在全局事件中会使用,因为闭包事件并不会释放内存,会导致内存升高,最终会导致内存泄露,所以不能乱用。
2.js的原型链
-
什么是原型链?
//控制台输出 function Person(age) { this.age = age } Person.prototype.name2 = 'gogogo' //prototype就是Person的原型链 Person.prototype
突然感觉网上讲的比我好多啦,抄张图。
开局一张图...对于这方面的理解。。小的技术还不够深入,懂,但是不知道怎么用。。。但是!总结了一些他们之间相互获取的方法,作为记录防止以后用到。
function AAA(){}
var a = new AAA();
a.__proto__ === AAA.prototype;
AAA.prototype.constructor === AAA;
3.js的继承
继承的实现方式:
首先定义一个父类:
function Person(name){
this.name = name;
this.sum = function(){
return this.name;
}
}
Person.prototype.age = 10
-
原型链继承
原理:新建一个对象,再让他的原型等于Person,等于他继承了Person
代码示列:function Per(){ this.name = 'ker'; } Per.prototype = new Person(); var per1 = new Per(); per1.age //10 per1.sum() // ker var per2 = new Per(); //一个实例修改了原型属性,另一个实例的原型属性也会被修改 per1.__proto__.name = 'ker3'; per2.__proto__.name // 'ker3'; //新实例无法向父类构造函数传参 var per3 = new Per('ker4'); per3.name //ker
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
2.构造函数继承
原理:用.call()和apply()将父类构造函数引入子类函数(在子类函数做父类函数自执行)
call和apply的作用(改变自身的this指向,)--作用一样,只是用法不一样。
(课外知识,bind(),可以百度搜搜,这三个方法实现了方法与方法之间的借用,很不错。同样的,继承的原理就是借用。看到这边你没有想到Bind()的作用和我们写的代码很像? ()=> 你可以理解为这个就是bind())
代码示列:
function Person2(name2){
this.name2 = name2;
this.sum2 = function(){
return this.name2 +"我是第二个";
}
}
function Con(name){
//在子实例中可向父实例传参
Person.call(this,name);
//可以继承多个构造函数属性(call多个)
Person2.call(this,name);
this.age = 12;
}
//
var con1 = new Con('jer11');
con1.name //jer11
con1.name2 // jer11
con1.sum2() // jer11我是第二个
var con2 = new Con('jer22');
//这边俩个方法俩个不相同的方法,所以叫做不能复用。
con2.sum2() === con1.sum2() false
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。
3、每个新实例都有父类构造函数的副本,臃肿。
3.原型链继承+构造函数继承(组合继承,常用)
function LiuXXX(name){
Person.call(this,name);
}
LiuXXX.prototype = new Person();
var xiaoliu = new LiuXXX('liuxiao');
xiaoliu.name // liuxiao
xiaoliu.sum()// liuxiao
优点:结合了两种模式的优点,传参和复用
缺点:父类方法调用了两次, 而且不能判断实例的构造函数是子类还是父类
其实到这边差不多了,后面还有寄生继承,原型寄生继承,寄生组合继承(常用),大家可以去了解一下。 这边大概就是js的一些基础。下面我们就会讲到我们常用的一些方法和语法。
4.es5与es6的不同,es6重要的特性.
es5 和es6的不同,或者说es6比es5多了哪些东西?
-
export : 每次我们在写js代码时,都会有一个 export.... 或者 export defalut 。其实这就是es6的语法。这是es6将每个js文件都模块化了。大家有个概念就好。代码演示:
//xxx.js var x = 1; var y = 2; var z = 3; export {x,y,z} //llll.js import {x,y,z} from xxx.js //按需加载 require('路径名+文件名'); //异步加载文件 const main = document.querySelector('main'); import(`./section-modules/${someVariable}.js`) .then(module => { module.loadPageInto(main); }) .catch(err => { main.textContent = err.message; });
-
let const var 的区别
话不多说 上代码。
var a = 1; var a = 2; a // 2 var a = 1; var a; a // 1 const a = 1; const a; // Uncaught SyntaxError: Identifier 'a' has already been declared let a = 1; let a ; a // undefined let a = 1 ; let a = 2; a // 2;
-
一些操作对象的简单方法
Object.assign(); //这个方法不会复制getter和setter //后面一个对象会覆盖前面一个对象 如果值一样; const target = { a: 1, b: 1 }; const source1 = { b: 2, c: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3} //这个方法是一个浅拷贝,对于对象中的对象无法进行复制,只会丢失。 const DEFAULTS = { url: { host: 'example.com', port: 7070 }, }; processContent({ url: {port: 8000} }) // { // url: {port: 8000} // } Object.assign();//一般和 ...list 合起来用 Object.key(obj);//获取对象属性名的数组 Object.values(obj);//获取对象值的数组;
-
Proxy 拦截器
这个东西很深入,用法很多。先看代码
let target = { name: 'Tom', age: 24 } let handler = { get: function(target, key) { console.log('getting '+key); return target[key]; // 不是target.key }, set: function(target, key, value) { console.log('setting '+key); target[key] = value; } } let proxy = new Proxy(target, handler) proxy.name // 实际执行 handler.get proxy.age = 25
proxy 拦截了target的动作,对应动作。
get:属性的读取。可以被继承。set:属性的赋值。
apply:拦截函数的调用。代码示列:
get : const proxy = new Proxy({}, { //目标,目标key,原始的操作行为所在的那个对象,一般是proxy实例 get: function(target, key, receiver) { //TO DO } }); const d = Object.create(proxy); d.a === d // true set: const handler = { //set必须要返回true,否则报错 //分别对应目标,目标key,传入值,原始的操作行为所在的那个对象,一般是proxy实例 set: function(obj, prop, value, receiver) { obj[prop] = receiver; return true; } }; const proxy = new Proxy({}, handler); proxy.foo = 'bar'; proxy.foo === proxy apply: var target = function () { return 'I am the target'; }; var handler = { //分别对应目标,目标的上下文(this),参数 apply: (target,ctx,args) { return 'I am the proxy'; } }; var p = new Proxy(target, handler); p()
Proxy 对象可以拦截目标对象的任意属性,这使得它很合适用来写 Web 服务的客户端。
const service = createWebService('http://example.com/data'); service.employees().then(json => { const employees = JSON.parse(json); // ··· });
上面代码新建了一个 Web 服务的接口,这个接口返回各种数据。Proxy 可以拦截这个对象的任意属性,所以不用为每一种数据写一个适配方法,只要写一个 Proxy 拦截就可以了。
function createWebService(baseUrl) { return new Proxy({}, { get(target, propKey, receiver) { return () => httpGet(baseUrl + '/' + propKey); } }); }
后端的proxy代理也是这个原理。
-
Promise!Promise!Promise!
重要的事情说三遍~
先看代码//基础用法 let promise = new Promise(function(resolve,reject){ //your code if(/*action success*/) resolve(value);//value是你操作成功后想传给后面的值 else reject(error);//一般抛错,或者传出错误信息; }); //列子 function timeout(ms){ return new Promise((resolve,reject)=>{ setTimeout(resolve,ms,'done') }) } timeout(100).then(res=>{ console.log(res); }) //用promise实现aynsc function getJson(url){ const getData = new Promise((resolve,reject)=>{ }) }
-
解构赋值
var foo = ["one", "two", "three", "four"]; var [one, two, three] = foo; console.log(one); // "one" console.log(two); // "two" console.log(three); // "three"
-
延展操作符
代码:
//数组拷贝 var arr = [1, 2, 3]; var arr2 = [...arr]; // 等同于 arr.slice() arr2.push(4); console.log(arr2)//[1, 2, 3, 4] //构造数据 const stuendts = ['Jine','Tom']; const persons = ['Tony',... stuendts,'Aaron','Anna']; conslog.log(persions)// ["Tony", "Jine", "Tom", "Aaron", "Anna"] //函数调用 function sum(x, y, z) { return x + y + z; } const numbers = [1, 2, 3]; //不使用延展操作符 console.log(sum.apply(null, numbers)); //使用延展操作符 console.log(sum(...numbers));// 6