1,构造函数
传统的JavaScript中只有对象,没有类的概念,它是基于原型的面向对象语言,原型上的属性都共享的。如果想生成一个对象实例,需要先定义一个构造函数,然后通过new 操作来完成。
1,传统的创建方式: 构造函数也是函数,区别普通函数是:函数名称第一个单词大写
function Person(name, age) {
this.name = name;
this.age = age
}
// 原型链上添加方法
Person.prototype.hello = function() {
console.log()
}
// 创建对象, 必须使用new
var person = new Person('zlm', 21)
// 对象上有原型的属性和方法
person.hello()
在面向对象的编程中,类是一个用于创建对象,并且为对象的状态和行为提供初始值的模板。
2,Class 引入
1, ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
class MyClass{
constructor(){}
method(){}
}
然后通过new MyClass() 来创建一个对象实例,而且:通过new操作符创建实例的时候,构造方法(constructor) 是被自动调用,的,这意味着可以在构造方法中做一些初始化的工作。
class MyClass{
constructor(name){
this.name = name
}
hello(){
alert(this.name)
}
}
let p1 = new MyClass('zlm')
p1.hello()
注意:类方法之间是没有逗号的,加了会报错。
ES6的类,完全可以看作构造函数的另一种写法。
class Point {
// ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true
使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。
上面代码表明,类的数据类型就是函数,类本身就指向构造函数。
3,什么是类
在JavaScript中,类是函数的一种,一些人说在JavaScript中class是一种"语法糖",因为我们实际上可以在没有class关键字的情况下声明一个类。在Es6之前,我们可以通过function去实现一个类,确实可以将类视为一种语法糖来定义构造函数及其原型方法。但与class的方式创建一个类有着重要的差异。由class创建的函数由特殊的内部属性标记,与常规函数不同,如果没有new,则无法调用类构造函数
1, constructor方法
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
constructor() {}
constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
class MyClass {
constructor() {
return Object.create(null);
}
}
new MyClass() instanceof MyClass
类的构造函数,不使用new是没法调用的,会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。
上面代码中,constructor函数返回一个全新的对象,结果导致实例对象不是Foo类的实例。
2, 类的实例对象
生成类的实例对象的写法,与ES5完全一样,也是使用new命令。如果忘记加上new,像函数那样调用Class,将会报错。
// 报错
var p1 = MyClass(2, 3);
// 正确
var p1 = new MyClass(2, 3);
3,calss的静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该
方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class MyClass {
static classMethod() {
return 'hello';
}
}
MyClass.classMethod() // 'hello'
var p1 = new MyClass();
p1.classMethod()
MyClass类的classMethod方法前有static关键字,表明该方法是一个静态方法,可以直接在MyClass类上调用(MyClass.classMethod()),而不是在MyClass类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。 注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。 Class 的静态属性和实例属性
(1)静态属性
静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。
(2)实例属性
类的实例属性可以用等式,写入类的定义之中
4,项目实战
1, 封装的Http 请求类
真正的项目中,请求头参数可以根据项目需求进行添加,
let ucmsToken = {};
export const setUcmsToken = (tokenName, tokenValue) => {
ucmsToken = { tokenName, tokenValue };
};
/**
* 合并请求options
* TODO:目前只支持headers的对象merge
* @param {*} defOptions
* @param {*} options
*/
const mergeOptions = (defOptions = {}, options = {}) => {
const headers = Object.assign({}, defOptions.headers, options.headers);
return Object.assign({}, defOptions, options, { headers });
};
class Http {
/**
* http get
* @param {*} url
* @param {*} options
*/
static async get(url, options) {
const defOptions = {
headers: {
"X-Portal-Token": xxx
},
mode: "cors",
credentials: "omit"
};
const { tokenName, tokenValue } = ucmsToken;
if (tokenName && tokenValue) {
Object.assign(defOptions.headers, {
"SC-AUTH-TOKEN": tokenValue,
[tokenName]: tokenValue
});
}
const response = await fetch(url, mergeOptions(defOptions, options));
return response.json();
}
/**
* http post
* @param {*} url
* @param {*} data
* @param {*} options
*/
static async post(url, data = {}, options) {
const defOptions = {
headers: {
"Content-Type": "application/json;charset=UTF-8",
"X-Portal-Token": xxx
},
method: "post",
body: JSON.stringify(data),
mode: "cors",
credentials: "omit"
};
const { tokenName, tokenValue } = ucmsToken;
if (tokenName && tokenValue) {
Object.assign(defOptions.headers, {
"SC-AUTH-TOKEN": tokenValue, // !登陆成功之后,接口返回的tokenValue
[tokenName]: tokenValue
});
}
const response = await fetch(url, mergeOptions(defOptions, options));
return response.json();
}
/**
* http put
* @param {*} url
* @param {*} data
* @param {*} options
*/
static async put(url,data={},options){
const defOptions = {
headers:{
'Content-Type': 'application/json',
"X-Portal-Token": xxx
},
method:"put",
body:JSON.stringify(data),
mode: "cors",
credentials: "omit"
}
const { tokenName, tokenValue } = ucmsToken;
if (tokenName && tokenValue) {
Object.assign(defOptions.headers, {
"SC-AUTH-TOKEN": tokenValue,
[tokenName]: tokenValue
});
}
const response = await fetch(url,mergeOptions(defOptions,options))
return response.json()
}
(2) 第二个实战项目:跨域消息传递,postMessage的封装
export const uuid = () => Math.random().toString(36).substr(2) + Date.now().toString(36)
const handleEmit = function ({ $request, params }) {
const eventPool = this.eventPool[$request]
if (eventPool) {
for (let i = 0; i< eventPool.length; i++) {
if (eventPool[i].cb) eventPool[i].cb(params)
if (eventPool[i].once) {
eventPool.splice(i, 1)
i--
}
}
}
}
const listen = function () {
const addEventListener = window.addEventListener || window.attachEvent
const type = window.addEventListener ? 'message' : 'onmessage'
addEventListener(type, (event) => {
// 不处理非目标源请求
if (event.origin !== this.targetOrigin && this.targetOrigin !== '*') return
const { data: { $type, $request, params } } = event
switch ($type) {
case 'emit': {
handleEmit.call(this, { $request, params })
break
}
default:
}
}, false)
}
class PostMessage {
constructor (targetOrigin = '*', targetWindow = window.parent) {
this.targetOrigin = targetOrigin
this.targetWindow = () => typeof targetWindow === 'function' ? targetWindow() :
targetWindow
this.eventPool = {}
listen.call(this)
}
emit (event, params) {
const payload = { $request: event, $type: 'emit', params }
this.targetWindow().postMessage(payload, this.targetOrigin)
}
on (event, cb) {
const $uuid = uuid()
if (!this.eventPool[event]) this.eventPool[event] = []
if (cb) this.eventPool[event].push({ cb, $uuid })
return $uuid
}
off (event, eventId) {
if (!eventId) {
delete this.eventPool[event]
} else if (this.eventPool[event]) {
const eventIndex = this.eventPool[event].findIndex(item => item.$uuid === eventId)
if (eventIndex !== -1) this.eventPool[event].splice(eventIndex, 1)
}
}
once (event, cb) {
const $uuid = uuid()
if (!this.eventPool[event]) this.eventPool[event] = []
if (cb) this.eventPool[event].push({ cb, $uuid, once: true })
}
}
export default PostMessage
使用方法: 1,初始化:
var innerWindow = document.querySelector('#iframe').contentWindow
var PM = new PostMessage('*', innerWindow)
var PM = new PostMessage('*', window.parent)
// 默认参数即是('*', window.parent), 等同于
var PM = new PostMessage()
2, 实例方法:
| 方法 | 参数 | 说明 |
|---|---|---|
emit | (eventName, params) | eventName 事件名, 系统双方约定. params 传递给对方的数据 |
on | (eventName, callback) | eventName 同上. callback 监听到事件后应该执行的函数, 参数为对方传递的params, 函数体自定义. 特别说明, on方法有一个返回值, 是该次监听的ID |
once | (eventName, callback) | 参数同上, 无返回值. once只会监听一次, callback只会执行一次 |
off | (eventName[,ID]) | eventName 同上. 如果有ID, 关闭该ID的监听行为, 如果无ID, 关闭该事件的全部监听行为 |