一、Vue.use与Vue.prototype的区别和用法
相同点:都是注册插件的方式,没有本质区别,都是在vue.prototype上添加了一个方法
不同点:vue.use适用于注册vue生态内的插件(vuex、router、elementUI),vue.prototype适用于注册生态外的插件(echarts、);
//1.1、vue.prototype用法
需要设置全局变量,在main.js中,Vue实例化的代码里添加。 不想污染全局作用域。这种情况下,你可以通过在原型上定义它们使其在每个Vue实例中可用。
vue.prototype.$echarts = echarts //变量前加上$,是防止被组件中的变量意外覆盖
//1.2vue.use用法
通过全局方法Vue.use()使用插件
Vue.usew会自动阻止多次注册插件
它需要在你调用new Vue()启动应用之前完成
注意:Vue.use() 方法至少传入一个参数,该参数类型必须是 Object 或 Function,如果是 Object 那么这个 Object 需要定义一个 install方法,如果是Function那么这个函数就被当做install方法。在 Vue.use()执行时install会默认执行,当install执行时第一个参数就是Vue,其他参数是Vue.use()执行时传入的其他参数。
方式一:单个组件以及公共组件的使用
//方式一
1.在vue项目中src/assets/js/创建js文件 例:如文章下面的common.js文件
2.在main.js引用common->然后实例化
/*引入公共函数*/
import common from './assets/js/common'
Vue.use(common);
3、在任何.vue组件中的生命周期利用this.方法名调用,因为已经在main.js全局实例化了
4、在单个.vue组件中使用
4.1、在.vue文件中引入import { unique } from '%/utils/utils'
4.2、let params = unique(this.proportionArr)
common.js文件————>//公共方法
export default{
install(Vue){
//这里是示例方法 getTime是方法名 function()可以携带参数
Vue.prototype.getTime = function(){
var date = new Date()
var y = date.getFullYear()
var m = date.getMonth() + 1
m = m < 10 ? ('0' + m) : m
var d = date.getDate()
d = d < 10 ? ('0' + d) : d
alert(y + m + d)
};
Date.prototype.Format = function(fmt){
let o = {
"M+": this.getMonth() + 1,
"d+": this.getDate(),
"h+": this.getHours(),
"m+": this.getMinutes(),
"s+": this.getSeconds(),
};
if(/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length));
for(let k in o){
if(new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
return fmt;
};
Vue.filter('formatDate', function(value,fmt){
if(!fmt) fmt = 'yyyy-MM-dd hh:mm:ss'
return new Date(value).Format(fmt)
});
Vue.prototype.throttle = function (fn,delay) {
var startTime = Date.now();
return function(){
let context = this;
let args = arguments;
let nowTime = Date.now();
if(nowTime-startTime >= delay){
fn.apply(context,args);
startTime = Date.now();
}
}
}
}
}
方式二:公共方法封装方式(熟悉对外接口写法)
common2.js
//export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
function _debounce(fn, delay = 200) {
var timer
return function() {
var th = this
var args = arguments
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function() {
timer = null
fn.apply(th, args)
}, delay)
}
}
// 节流
function _throttle(fn, interval = 200) {
var last
var timer
return function() {
var th = this
var args = arguments
var now = +new Date()
if (last && now - last < interval) {
clearTimeout(timer)
timer = setTimeout(function() {
last = now
fn.apply(th, args)
}, interval)
} else {
last = now
fn.apply(th, args)
}
}
}
export { _debounce, _throttle }
export function unique(arr) {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i].id == arr[j].id) {
arr.splice(i, 1);
j--;
}
}
}
return arr;
}
二、class高阶封装
在ES6中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。class 的本质是 function。它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。
一、生成实例对象的传统方法是通过构造函数。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
二、Es6通过class关键字,可以定义类;基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
//上述方法用class实现,使用的时候,也是直接对类使用new命令,和构造函数的用法完全一致。
class Point {
constructor(x, y){
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
四、ES6 的类,完全可以看作构造函数的另一种写法(类的数据类型就是函数,类本身就指向构造函数);。
class Point {
// ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true
五、事实上,类的所有方法都定义在类的prototype属性上面
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
//上述三个方法其实都是定义在Point.prototype上面。
};
六、注意:类的内部所有定义的方法,都是不可枚举的
class Point {
constructor(x, y) {
// ...
}
toString() {
// ...
}
}
Object.keys(Point.prototype)//返回给定对象的所有可枚举属性的字符串数组
// []
Object.getOwnPropertyNames(Point.prototype)//返回一个数组,成员是参数对象自身的全部属性的属性名,不管该属性是否可遍历
// ["constructor","toString"]
3.1、class的constructor() 方法
3.3、constructor()方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加。
class Point {
}
// 等同于
class Point {
constructor() {}
}
3.4、类的实例:类的属性和方法,除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
var point = new Point(2, 3);
point.toString() // (2, 3)
point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true
注意:上面代码中,x和y都是实例对象point自身的属性(因为定义在this对象上),所以hasOwnProperty()方法返回true,而toString()是原型对象的属性(因为定义在Point类上),所以hasOwnProperty()方法返回false。这些都与 ES5 的行为保持一致。
3.5、静态方法:类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
静态方法: 类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod(); // TypeError: foo.classMethod is not a function
注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。
class Foo {
static bar() {
this.baz();
}
static baz() {
console.log('hello');
}
baz() {
console.log('world');
}
}
Foo.bar() // hello
3.6、私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问。
class IncreasingCounter {
#count = 0;
get value() {
console.log('Getting the current value!');
return this.#count;
}
increment() {
this.#count++;
}
}
// #count就是私有属性,只能在类的内部使用(this.#count)。如果在类的外部使用,就会报错。
const counter = new IncreasingCounter();
counter.#count // 报错
counter.#count = 42 // 报错
3.7、通过 extends 实现类的继承。
class Child extends Father { ... }
3.8、this指向
class Logger {
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined
printName方法中的this,默认指向Logger类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境(由于class内部是严格模式,所以 this 实际指向的是undefined),从而导致找不到print方法而报错。
一个比较简单的解决方法是,在构造方法中绑定this,这样就不会找不到print方法了。
class Logger {
constructor() {
this.printName = this.printName.bind(this);
}
// ...
}
或者
class Obj {
constructor() {
this.getThis = () => this;
}
}
const myObj = new Obj();
myObj.getThis() === myObj // true