js inheritance
Preface
Inheritance occupies a very important position in js, so there are many ways of inheritance in js, but each inheritance method has advantages and disadvantages. Here are several ways of inheritance.
To achieve inheritance, you first need a parent class. In js, there is actually no concept of class. Although class is very similar to class in es6, it is actually only syntactic sugar on es5.
function People(name){
//属性
this.name = name || 'Annie'
//实例方法
this.sleep=function(){
console.log(this.name + '正在睡觉')
}
}
//原型方法
People.prototype.eat = function(food){
console.log(this.name + '正在吃:' + food);
}
1. Prototype chain inheritance
The instance of the parent class serves as the prototype of the child class
function Woman(){
}
Woman.prototype= new People();
Woman.prototype.name = 'haixia';
let womanObj = new Woman();
advantage:
-
Simple and easy to implement, new instances of the parent class and attribute subclasses can be accessed
Disadvantages:
-
You can add instance properties to the subclass. If you want to add new prototype properties and methods, you need to follow the new parent class constructor
-
Unable to achieve multiple inheritance
-
When creating a subclass instance, you cannot pass parameters to the parent class constructor
2. Borrowing constructor inheritance (forged objects, classic inheritance)
Copy the instance attributes of the parent class to the child class
function Woman(name){
//继承了People
People.call(this); //People.call(this,'tom);
this.name = name || 'kitty'
}
let womanObj = new Woman();
advantage:
-
Solved the problem of passing parameters from the subclass constructor to the parent class constructor
-
Multiple inheritance can be achieved (call or apply multiple parent classes)
Disadvantages:
-
The methods are defined in the constructor and cannot be reused
-
Cannot inherit prototype properties/methods, only inherit the instance properties and methods of the parent class
3. Instance inheritance (prototype inheritance)
function Wonman(name){
let instance = new People();
instance.name = name || 'wangxiaoxia';
return instance;
}
let wonmanObj = new Wonman();
advantage:
Disadvantages:
4. Combined inheritance
Call the parent class constructor, inherit the properties of the parent class, and realize function reuse by using the parent class instance as the subclass prototype
function People(name,age){
this.name = name || 'wangxiao'
this.age = age || 27
}
People.prototype.eat = function(){
return this.name + this.age + 'eat sleep'
}
function Woman(name,age){
People.call(this,name,age)
}
Woman.prototype = new People();
Woman.prototype.constructor = Woman;
let wonmanObj = new Woman(ren,27);
wonmanObj.eat();
Disadvantages:
advantage:
-
Functions can be reused
-
There is no problem with reference attributes
-
Can inherit properties and methods, and can inherit the properties and methods of the prototype
5. Parasitic combinatorial inheritance
Repair the deficiencies of combined inheritance through parasitic methods, and achieve perfect inheritance
//父类
function People(name,age){
this.name = name || 'wangxiao'
this.age = age || 27
}
//父类方法
People.prototype.eat = function(){
return this.name + this.age + 'eat sleep'
}
//子类
function Woman(name,age){
//继承父类属性
People.call(this,name,age)
}
//继承父类方法
(function(){
// 创建空类
let Super = function(){
};
Super.prototype = People.prototype;
//父类的实例作为子类的原型
Woman.prototype = new Super();
})();
//修复构造函数指向问题
Woman.prototype.constructor = Woman;
let womanObj = new Woman();
6.es6 inheritance
Less code, easy to understand
//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的protopyte属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//es5中constructor为隐式属性
class People{
constructor(name='wang',age='27'){
this.name = name;
this.age = age;
}
eat(){
console.log(`${
this.name} ${
this.age} eat food`)
}
}
//继承父类
class Woman extends People{
constructor(name = 'ren',age = '27'){
//继承父类属性
super(name, age);
}
eat(){
//继承父类方法
super.eat()
}
}
let wonmanObj=new Woman('xiaoxiami');
wonmanObj.eat();
The difference between ES5 inheritance and ES6 inheritance:
es5 inheritance first is to create your own this point in the subclass, and finally add the method to this
Child.prototype=new Parent() || Parent.apply(this) || Parent.call(this)
es6 inheritance is to use keywords to first create the instance object this of the parent class, and finally modify this in the subclass class
Concluding remarks:
Syntactic sugar of many codes in es6, many methods are simple and easy to use. In the case of browser compatibility, change the original method.
Although many frameworks are now es6, it is recommended for beginners to take a look at the principles implemented in es5.
===================================================================
js design pattern
One, singleton mode
1. Definition
Ensure that a class has only one instance, and provide a global access point to access it
2. Core
Ensure that there is only one instance and provide global access
3. Realization
In the development of the vue scaffolding project, we need to axios
intercept request and response interception. The axios instance that calls the package number multiple times is only set once, and after the package axios
is a singleton.
The following is a case of axios singleton mode in vue-cli4:
Generally, I will create a network folder in the src directory of the project, and then create a http.js and an api.js file in it. The http.js file is used to encapsulate our axios, and api.js is used to manage our interface uniformly.
// 在http.js中引入axios
import axios from 'axios'; // 引入axios
import QS from 'qs'; // 引入qs模块,用来序列化post类型的数据,后面会提到
// vant的toast提示框组件,大家可根据自己的ui组件更改。
import {
Toast } from 'vant';
Environmental switching
Our project environment may have a development environment, a test environment and a production environment. We use node's environment variables to match our default interface url prefix. Axios.defaults.baseURL can set the default request address of axios, not much to say.
// 环境的切换
if (process.env.NODE_ENV == 'development') {
axios.defaults.baseURL = 'https://www.baidu.com';}
else if (process.env.NODE_ENV == 'debug') {
axios.defaults.baseURL = 'https://www.ceshi.com';
}
else if (process.env.NODE_ENV == 'production') {
axios.defaults.baseURL = 'https://www.production.com';
}
Set request timeout
Set the default request timeout time through axios.defaults.timeout. For example, if it exceeds 10s, the user will be notified that the current request has timed out, please refresh, etc.
axios.defaults.timeout = 10000;
Post request header settings
When requesting a post, we need to add a request header, so we can make a default setting here, that is, set the request header of the post toapplication/x-www-form-urlencoded;charset=UTF-8
axios.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded;charset=UTF-8';
Request interception
We can intercept a request before sending the request. Why do we intercept it? What do we intercept the request for? For example, some requests need to be accessed after the user logs in, or when post requests, we need to serialize the data we submit. At this time, we can perform an interception before the request is sent to perform the operation we want.
Request interception
// 先导入vuex,因为我们要使用到里面的状态对象
// vuex的路径根据自己的路径去写
import store from '@/store/index';
// 请求拦截器axios.interceptors.request.use(
config => {
// 每次发送请求之前判断vuex中是否存在token
// 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
const token = store.state.token;
token && (config.headers.Authorization = token);
return config;
},
error => {
return Promise.error(error);
})
Response interception
// 响应拦截器
axios.interceptors.response.use(
response => {
// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
// 否则的话抛出错误
if (response.status === 200) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
// 服务器状态码不是2开头的的情况
// 这里可以跟你们的后台开发人员协商好统一的错误状态码
// 然后根据返回的状态码进行一些操作,例如登录过期提示,错误提示等等
// 下面列举几个常见的操作,其他需求可自行扩展
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
break;
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
Toast({
message: '登录过期,请重新登录',
duration: 1000,
forbidClick: true
});
// 清除token
localStorage.removeItem('token');
store.commit('loginSuccess', null);
// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
// 404请求不存在
case 404:
Toast({
message: '网络请求不存在',
duration: 1500,
forbidClick: true
});
break;
// 其他错误,直接抛出错误提示
default:
Toast({
message: error.response.data.message,
duration: 1500,
forbidClick: true
});
}
return Promise.reject(error.response);
}
}
});
At this point, the singleton encapsulation of axios is basically completed, and then the unified management of the api will not be explained in detail.
4. Application scenarios
Encapsulate vuex and axios, any vue project can be directly reused, realize axios unified call, single-channel modification vuex
Second, the factory model
The factory pattern is our most commonly used instantiation object pattern. It is a pattern that replaces the new operation with a factory method.
Because the factory pattern is equivalent to creating instance object new, we often have to generate instance objects based on the class Class. For example, A a=new A() The factory pattern is also used to create instance objects, so in the future, we will have to pay more attention to it. Can you consider using the factory model? Although doing so may do more work, it will bring greater scalability and minimal modification to your system.
function Animal(opts){
var obj = new Object();
obj.color = opts.color;
obj.name= opts.name;
obj.getInfo = function(){
return '名称:'+ onj.name+', 颜色:'+ obj.color;
}
return obj;
}
var cat = Animal({
name: '波斯猫', color: '白色'});
cat.getInfo();