Object.getOwnPropertyDescriptors()
ES2017 引入了Object.getOwnPropertyDescriptors方法,返回指定对象所有自身属性(非继承属性)的描述对象。
Think More,Do Less
ES2017 引入了Object.getOwnPropertyDescriptors方法,返回指定对象所有自身属性(非继承属性)的描述对象。
Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
Object.entries的基本用途是遍历对象的属性。
Object.entries方法的另一个用处是,将对象转为真正的Map结构。
Object.entries方法的另一个用处是,将对象转为真正的Map结构。
Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
如果参数不是对象,Object.values会先将其转为对象。由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以,Object.values会返回空数组。
vue2组件懒加载浅析
一、 什么是懒加载
懒加载也叫延迟加载,即在需要的时候进行加载,随用随载。
二、为什么需要懒加载
在单页应用中,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,延时过长,不利于用户体验,而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时
三、如何与webpack配合实现组件懒加载
1、在webpack配置文件中的output路径配置chunkFilename属性
output: {
path: resolve(__dirname, 'dist'),
filename: options.dev ? '[name].js' : '[name].js?[chunkhash]',
chunkFilename: 'chunk[id].js?[chunkhash]',
publicPath: options.dev ? '/assets/' : publicPath
},
chunkFilename路径将会作为组件懒加载的路径
2、配合webpack支持的异步加载方法
() => import(URL), webpack2官网推荐使用, 属于es7范畴, 需要配合babel的syntax-dynamic-import插件使用, 具体使用方法如下
npm install --save-dev babel-core babel-loader babel-plugin-syntax-dynamic-import babel-preset-es2015
use: [{
loader: 'babel-loader',
options: {
presets: [['es2015', {modules: false}]],
plugins: ['syntax-dynamic-import']
}
}]
四、具体实例中实现懒加载
1、路由中配置异步组件
export default new Router({
routes: [
{
mode: 'history',
path: '/my',
name: 'my',
component: resolve => require(['../page/my/my.vue'], resolve),//懒加载
},
]
})
2、实例中配置异步组件
components: {
historyTab: resolve => {require(['../../component/historyTab/historyTab.vue'], resolve)},//懒加载
//historyTab: () => import('../../component/historyTab/historyTab.vue')
},
3、全局注册异步组件
Vue.component('mideaHeader', () => {
System.import('./component/header/header.vue')
})
五、配置异步组件实现懒加载的问题分析
1、多次进出同一个异步加载页面是否会造成多次加载组件?
答:否,首次需要用到组件时浏览器会发送请求加载组件,加载完将会缓存起来,以供之后再次用到该组件时调用
2、在多个地方使用同一个异步组件时是否造成多次加载组件?如:
//a页面
export default {
components: {
historyTab: resolve => {require(['../../component/historyTab/historyTab.vue'], resolve)},//懒加载
},
}
//b页面
export default {
components: {
historyTab: resolve => {require(['../../component/historyTab/historyTab.vue'], resolve)},//懒加载
},
}
答:否,理由同上
3、如果在两个异步加载的页面中分别同步与异步加载同一个组件时是否会造成资源重用? 如:
//a页面
import historyTab from '../../component/historyTab/historyTab.vue';
export default {
components: {
historyTab
},
}
//b页面
export default {
components: {
historyTab: resolve => {require(['../../component/historyTab/historyTab.vue'], resolve)},//懒加载
},
}
答: 会, 将会造成资源重用, 根据打包后输出的结果来看, a页面中会嵌入historyTab组件的代码, b页面中的historyTab组件还是采用异步加载的方式, 另外打包chunk;
解决方案: 组件开发时, 如果根页面没有导入组件的情况下,而是在其他异步加载页面中同时用到组件, 那么为实现资源的最大利用,在协同开发的时候全部人都使用异步加载组件
4、在异步加载页面中载嵌入异步加载的组件时对页面是否会有渲染延时影响?
答:会, 异步加载的组件将会比页面中其他元素滞后出现, 页面会有瞬间闪跳影响;
解决方案:因为在首次加载组件的时候会有加载时间, 出现页面滞后, 所以需要合理的进行页面结构设计, 避免首次出现跳闪现象;
六、懒加载的最终实现方案
1、路由页面以及路由页面中的组件全都使用懒加载
优点:(1)最大化的实现随用随载
(2)团队开发不会因为沟通问题造成资源的重复浪费
缺点:(1)当一个页面中嵌套多个组件时将发送多次的http请求,可能会造成网页显示过慢且渲染参差不齐的问题
2、路由页面使用懒加载, 而路由页面中的组件按需进行懒加载, 即如果组件不大且使用不太频繁, 直接在路由页面中导入组件, 如果组件使用较为频繁使用懒加载
优点:(1)能够减少页面中的http请求,页面显示效果好
缺点:(2)需要团队事先交流, 在框架中分别建立懒加载组件与非懒加载组件文件夹
3、路由页面使用懒加载,在不特别影响首页显示延迟的情况下,根页面合理导入复用组件,再结合方案2
优点:(1)合理解决首页延迟显示问题
(2)能够最大化的减少http请求, 且做其他他路由界面的显示效果最佳
缺点:(1)还是需要团队交流,建立合理区分各种加载方式的组件文件夹
七、采用第三种方案进行目录结构设计
八、具体代码实现设计
1、路由设计:
import Router from 'vue-router';
import Vue from 'vue';
Vue.use(Router);
export default new Router({
routes: [
{
mode: 'history',
path: '/home',
name: 'home',
component: resolve => require([URL], resolve),//懒加载
children: [
{
mode: 'history',
path: '/home/:name',
name: 'any',
component: resolve => require(['../page/any/any.vue'], resolve),//懒加载
},
]
},
{
mode: 'history',
path: '/store',
name: 'store',
component: resolve => require(['../page/store/store.vue'], resolve),//懒加载,
children: [
{
mode: 'history',
path: '/store/:name',
name: 'any',
component: resolve => require(['../page/any/any.vue'], resolve),//懒加载
},
]
},
{
mode: 'history',
path: '/my',
name: 'my',
component: resolve => require(['../page/my/my.vue'], resolve),//懒加载,
children: [
{
mode: 'history',
path: '/my/:name',
name: 'any',
component: resolve => require(['../page/any/any.vue'], resolve),//懒加载
},
]
},
]
})
(1)首层的路由根组件分别对应的tab页面
(2)根目录后跟着各个子路由页面,子路由采用动态路由配合路由的编程式导航再加上vuex,最优化提高开发效率
直接贴上代码:
/**
* Created by ZHANZF on 2017-3-20.
*/
//vuex配置
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
//路由组件存储器
routers: {}
},
getters: {
routers: state => {
return state.data;
}
},
mutations: {
//动态增加路由
addRouter: (state, data) => {
state.routers = Object.assign({}, state.routers, {
[data.name]: data.component
});
}
},
actions: {
acMethods({commit}) {
}
},
})
//根目录中注册路由组件
window.midea = {
registerRouter(name, component) {
Store.commit('addRouter', {
name: name,
component: component
})
}
};
//页面使用路由导航
openAnyPage() {
midea.registerRouter('module', resolve => {require(['../module/module.vue'], resolve)});//懒加载
this.$router.push({path: '/home/module', query: {title: this.title}});
}
//页面中使用动态组件
http://www.google-analytics.com/ga.js"> src="">http://www.cnblogs.com/any.js">
export default {
data () {
return {
routeName: '',
currentRouter: '',
title: '',
}
},
created() {
this.routeName = this.$route.params.name;
this.title = this.$route.query.title;
this.currentRouter = this.$store.state.routers[this.routeName];
},
methods: {
}
}
二、动态组件的设计
直接用即用即加的方式在实例或路由中直接配置异步组件
本文主要讲三个 问题
首先我们说下在 JS 中,常常让我们感到困惑的地方,就是 prototype 和 __proto__ 到底是干嘛的
1. __proto__ 就是 Javascript中 所谓的原型 (这里,我们还是拿具体的例子来说明吧)
function A (name) { // 这里是一个构造函数
thia.name = name
}
var Aobj = { // 这里是一个 对对象字面量
name: ''
}
// 我们分别打印出来这二个对象看看
console.dir(A)
console.dir(Aobj)
这里我们可以很明显的看到
构造函数的 __proto__ 属性 指向了 function()
对象字面量的 __proto__ 属性 指向了 Object
为什么 指向的 是不一样的呢?
思考下:
确实是 不一样的, 因为 构造函数本身也是一个 函数, 所以它 的原型 指向 function()
而对象字面量 是一个 对象, 那么他的 原型肯定是指向 Object
扩展思考,如果 是一个数组 对象, 那么它的 __proto__ 会指向什么呐?
const arr = [112,22,3333]
console.dir(arr)
没错, 这里的 __proto__ 就指向了 Array[0]
总结 :一个对象的 __proto__ 属性和自己的内部属性[[Prototype]]指向一个相同的值 (通常称这个值为原型)
tips:firefox、chrome等浏览器把对象内部属性 [[Prototype]] 用 __proto__ 的形式暴露了出来.(老版本的IE并不支持 __proto__ ,IE11中已经加上了 __proto__ 属性)
2. prototype : 看看上面的 截图,你会发现 只有 构造函数 中 有这个玩意儿, 对的。 prototype 确实 是 在 function 中特有的。 别的对象类型中 都不会有的属性。
我们在看这个 function 对象属性的 时候就会发现这么一个 prototype 的属性,它的值是 一个 Object 。 点开这个 obj 我们就会发现啊, 这个 obj 的constructor 属性 指向了 这个构造函数本身。 是不是很神奇,至于为什么会是这样子的。
留一个 思考题吧, 为什么在 javascript 中,函数对象的 prototype 属性的 constructor 指向是 函数本身?
(在下面的介绍中,我们会 回答到这个问题)
同样,我们来先看一个例子。
function B(name) {
this.name = name
this.getName = function() {
console.log(this.name)
}
var c = 'test'
console.log(c)
}
var b = new B('testb') // test
console.log(b) // B: { name: 'testb',getName: function() {} }
B('testc') // test
看到上面的 输出 是不是觉得又很诧异了。
确实, 为什么 在 new 的时候, 构造函数居然 执行了一次。
同样, 在非严格模式下, 我们直接执行 构造函数, B('testc') 相当于:
// window.name = 'testc'
// window.getName = function() { console.log(this.name) }
思考:
我们的函数B既可以直接执行,又可以new一下返回一个对象。function和object到底是什么关系,new的时候发生了什么?
还是上面的 问题, 当我们执行 var b = new B('testb') 的时候发生了什么?
MDN 上的介绍是这样的说的:
对于 var b = new B('testb')
// javascript 实际上执行的是:
var o = new Object() // 生成一个 新的 对象 b 这里 可以约等于 var b = {}
o.__proto__ = B.prototype // 这里就是 函数对象中 独有的 prototype 属性。
// 这个独有的 prototype 属性 包含了一个 constructor 属性方法,指向的就是 构造函数, 也就是 这里的 function B(name) {}
B.call(o) // tips :这里 就需要注意了,因为很多同学都搞不清楚 这里是什么意思。
// 由于 call 的使用 将这里this是指向o, 所以就 可以 把什么this.name/getName 强行的绑定到o上。同时,需要注意的一点就是, 这里的 构造函数 执行科一遍, 只不过是 将 this 指向的 属性和方法,都 强行的 给 新创建的 这个 o 对象 绑定了一遍。
var b = o // 把 这个 o 返回给了 b 。 从而完成了 var b = new B('testb') 的过程
// 如果 还是不明白是 什么意思的话。 我们来看看 call 是干嘛用的
// 关于 call 的使用说明
var o1 = {
name: '111',
getName: function() {
console.log(this.name)
}
}
var o2 = {
name: '222'
}
o1.getName.call(o2) // 222
所以 这个时候,我们反过头来 看看 这个 new 的对象都有哪些 属性 和方法。
我们 可以 来 做一个 小实验,来 证明下,我们以上所说的东西。
function A (name) { // 这里是一个构造函数
this.name = name
}
var o = {}
o.__proto__ = A.prototype
A.call(o)
var a = o
var b = new A()
console.log(a)
console.log(b)
果然 和 我们想象 的一模一样。
至于 js 为什么要 把 新建 对象的 原型 指向 构造函数的 prototype 属性。
我们可以这样来理解。 因为 通过 new 方法来创建的 obj 。肯定是需要 一个 标记 来找到自己的 构造器函数。
所以 为了让 整个 程序结构看上去 合理。 我们需要 把 新建 对象的 原型 指向 构造函数的 prototype 属性。
`
所以到最后,我们 总结一下 。
在 javascript 中 prototype 和 proto 到底有什么区别。
prototype 是 面向 构造函数,来思考,
proto 是 面向 实例化 后 的对象 来思考就对了。
`
最后再 给一个例子, 是一个,我们经常会在开发中用到的 例子。
var Person = function(){}
Person.prototype.sayName = function() {
alert('my name is xxx')
}
Person.prototype.age = 12
var p = new Person()
p.sayName()
// 当我们 实例化 之后, 在我们 去执行 p.sayName() 的 时候,我们就会去 this 内部去 查找(这里就是 构造函数 Person 内部去找。 可是 没找到啊。只是一个 空函数, 怎么办呢?)
// 这个时候 就会沿着 原型链向上追溯, 但是如何 追溯呢?
// 这里就要用到 __proto__ 属性 来作为 追溯的 桥梁。
// 因为 实例化对象的 __proto__ 属性 指向的就是 构造函数的 prototype 属性所对应的 对象啊
最后 终于 愉快的 找到了,自己的对象啦~ 单身狗就可能一直找不到,或者看不懂这篇文章。
好了,以上就是 在 看 vuejs 源码 的时候 关于 new 的 一个 知识 扩展。
其实Vue.js不是一个框架,因为它只聚焦视图层,是一个构建数据驱动的Web界面的库。Vue.js通过简单的API提供高效的数据绑定和灵活的组件系统。
Vue.js的特性如下:
1.轻量级的框架
2.双向数据绑定
3.指令
4.插件化
1.与Angular的区别
相同点:
1.都支持指令:内置指令和自定义指令。
2.都支持双向数据绑定。
不同点:
1.AngularJS的学习成本高,而Vue.js本身提供的API都比较简单、直观。
2.在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。Vue.js使用基于依赖追踪的观察并且使用异步队列更新。所有的数据都是独立触发的。对于庞大的应用来说,这个优化差异还是比较明显的。
2.与React的区别
相同点:
1.react采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用。
2.中心思想相同:一切都是组件,组件实例之间可以嵌套。
3.都提供合理的钩子函数,可以让开发者定制化地去处理需求。
4.都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载。
不同点:
Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作DOM。
主要是基于分层的目的,让彼此的职责分开。View通过Controller来和Model联系,Controller是View和Model的协调者,View和Model不直接联系,基本联系都是单向的。用户User通过控制器Controller来操作模板Model从而达到视图View的变化。MVC模型关注的是Model的不变,所以,在MVC模型里,Model不依赖于View,但是 View是依赖于Model的。MVC是比较直观的架构模式,用户操作->View(负责接收用户的输入操作)->Controller(业务逻辑处理)->Model(数据持久化)->View(将结果反馈给View)。
MVP是从MVC模式演变而来的,都是通过Controller/Presenter负责逻辑的处理+Model提供数据+View负责显示。在MVP中,Presenter完全把View和Model进行了分离,主要的程序逻辑在Presenter里实现。并且,Presenter和View是没有直接关联的,是通过定义好的接口进行交互,从而使得在变更View的时候可以保持Presenter不变。
MVVM是把MVC里的Controller和MVP里的Presenter改成了ViewModel。MVVM在概念上是真正将页面与数据逻辑分离的模式。View的变化会自动更新到ViewModel,ViewModel的变化也会自动同步到View上显示,因此在View和Model之间没有联系,通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的,因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应到View上。这种自动同步是因为ViewModel中的属性实现了Observer,当属性变更时都能触发对应的操作。MVVM模式的框架有:AngularJS+Vue.js
JS中this关键字很常见,但是它似乎变幻莫测,让人抓狂。这篇文章就来揭示其中的奥秘。
借助阮一峰老师的话:它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。这句话看似平常,可是要非常注意三个字:“运行时”,这说明this关键字只与函数的执行环境有关,而与声明环境没有关系。也就是这个this到底代表的是什么对象要等到函数运行时才知道,有点类似函数定义时的参数列表只在函数调用时才传入真正的对象。理解了这一点对后面this关键字规律的掌握有很大帮助。
this关键字虽然会根据环境变化,但是它始终代表的是调用当前函数的那个对象。这就引出了JS中函数调用的问题。在JS中调用函数的模式可以分为4种: 方法调用模式、函数调用模式、构造器调用模式、apply调用模式。这些模式在如何初始化关键参数this上存在差异。
一、方法调用模式
当函数被保存为一个对象的属性时,它就可称为这个对象的方法。当一个方法被调用时,this被绑定到这个对象上。如果调用表达式包含一个提取属性的动作(. 或 []),那么它被称为方法调用。例如:
|
|
sayName函数作为对象obj的方法调用,所以函数体中的this就代表obj对象。
二、函数调用模式
当一个函数并非一个对象的属性时,那么它就是被当做函数来调用的。在此种模式下,this被绑定为全局对象,在浏览器环境下就是window对象。例如:
sayName以函数调用模式调用,所以函数体中的this代表window对象。
三、构造函数模式
如果在一个函数前面加上new关键字来调用,那么就会创建一个连接到该函数的prototype成员的新对象,同时,this会被绑定到这个新对象上。这种情况下,这个函数就可以成为此对象的构造函数。例如:
|
|
Obj作为构造函数被调用,函数体内的this被绑定为新创建的对象person。
四、apply调用模式
在JS中,函数也是对象,所有函数对象都有两个方法:apply和call,这两个方法可以让我们构建一个参数数组传递给调用函数,也允许我们改变this的值。例如:
|
|
当以函数调用模式调用sayName时,this代表window;当用apply模式调用sayName,并给它传入的第一个参数为person时,this被绑定到person对象上。如果不给apply传入任何参数,则this代表window。
自此,函数调用的4种模式就都介绍完了,this的绑定规律也就是以上几种,万变不离其宗。为了简单明了的介绍4种模式,以上的例子都比较简单,那么下面就跟我一起做一个稍复杂的练习,检验下自己是否真正掌握了this绑定对象的方法吧!
|
|
首先心中时刻提醒自己this是在函数执行时被绑定的,不要被任何赋值语句打乱阵脚。
先看第一个执行语句:person1.sayName(); 首先确定这是方法调用模式,对象为person1,再看sayName被赋值为全局函数对象showName,在showName执行时,this绑定的是person1,所以结果为”kxy”。
再看第二个执行语句:person2.sayName(); 这还是方法调用模式,对象为person2,调用的是它的sayName方法。再看sayName函数体,发现函数体最终执行的函数是fun,fun是用函数调用模式调用的。而fun最终也被赋值为showName函数,因为fun是用函数调用模式调用的,所以这里的this绑定为window,结果为”window“。
open() 方法可以查找一个已经存在或者新建的浏览器窗口。
语法:
window.open([URL], [窗口名称], [参数字符串])
参数说明:
URL:可选参数,在窗口中要显示网页的网址或路径。如果省略这个参数,或者它的值是空字符串,那么窗口就不显示任何文档。
窗口名称:可选参数,被打开窗口的名称。
1.该名称由字母、数字和下划线字符组成。
2.”_top”、”_blank”、”_selft”具有特殊意义的名称。
_blank:在新窗口显示目标网页
_self:在当前窗口显示目标网页
_top:框架网页中在上部窗口中显示目标网页
3.相同 name 的窗口只能创建一个,要想创建多个窗口则 name 不能相同。
4.name 不能包含有空格。
参数字符串:可选参数,设置窗口参数,各参数用逗号隔开。
1.简介
CSS Sprites在国内很多人叫css精灵,是一种网页图片应用处理方式。它允许将一个页面涉及到的所有零星图片都包含到一张大图中, 利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位, 访问页面时避免图片载入缓慢的现象。
2.优点
(1)CSS Sprites能很好地减少网页的http请求,从而大大的提高页面的性能,这是CSS Sprites最大的优点,也是其被广泛传播和应用的主要原因;
(2)CSS Sprites能减少图片的字节;
(3)CSS Sprites解决了网页设计师在图片命名上的困扰,只需对一张集合的图片命名,不需要对每一个小图片进行命名,从而提高了网页制作效率。
(4)CSS Sprites只需要修改一张或少张图片的颜色或样式来改变整个网页的风格。
3.缺点
(1)图片合并麻烦:图片合并时,需要把多张图片有序的合理的合并成一张图片,并留好足够的空间防止版块出现不必要的背景。
(2)图片适应性差:在高分辨的屏幕下自适应页面,若图片不够宽会出现背景断裂。
(3)图片定位繁琐:开发时需要通过工具测量计算每个背景单元的精确位置。
(4)可维护性差:页面背景需要少许改动,可能要修改部分或整张已合并的图片,进而要改动css。在避免改动图片的前提下,又只能(最好)往下追加图片,但这样增加了图片字节。
tag:
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true