JS部分
call 与 apply
apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。
call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法
都“可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由thisObj指定的新对象”
apply:最多只能有两个参数——新this对象和一个数组argArray。如果给该方法传递多个参数,则把参数都写进这个数组里面,当然,即使只有一个参数,也要写进数组里。
apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
语法:apply([thisObj [,argArray] ]);,调用一个对象的一个方法,2另一个对象替换当前对象。
说明:如果argArray不是一个有效数组或不是arguments对象,那么将导致一个
TypeError,如果没有提供argArray和thisObj任何一个参数,那么Global对象将用作thisObj。
call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。
let obj3 = {
age:10,
fnt:function(gender){
console.log(this.name+'性别:'+gender)
}
}
let obj4 = {
name:'小明',
fnt:function(){
console.log(this.age)
}
}
obj4.fnt.call(obj3)
obj3.fnt.apply(obj4,['男'])
都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。
js怎么创建私有变量
JS没有私有属性的概念;所有的属性都是公用的;
私有变量的概念:在任何函数中定义的变量,都是私有变量,因为不能在函数外部访问这些变量;
- 私有变量:包括函数的参数/局部变量和函数内部定义的其他函数;
- 特权使用:内部创建一个必报,必报可以直接访问私有变量;因此创建用于访问私有变量的公用方法,称为特权方法
- 可以通过构造方法传参来访问私有变量,这种方法的缺点是会为每一个实例创建一组新的方法,不能实现共享。
js中命名函数与匿名函数的区别
-
以函数声明的方式声明命名函数
var baz = function e() {
console.log(“bar2”);
}; -
以函数表达式的方式声明匿名函数
var baz = function() {
console.log(“bar2”);
};
- 匿名函数不会被因为函数名而冲突掉
- 具名函数表达式可以明确地在调用栈中看到
for in 与for of
- for of 是遍历数组里的每一项,无法循环遍历对象
- for in循环遍历的是数组的键值(索引),而for of是循环遍历的是数组的值
- for in 会遍历自定义属性,for of不会
let arr = ['a','b','c','d']
arr.name = "数组"
for (const key in arr) {
console.log(key,arr[key])
}
console.log('---分割线---')
for (const item of arr) {
console.log(item)
}
noConflict()方法重新定义jquery默认的$符号
立即执行函数
宏任务和微任务
- 表示异步任务的两种分类
先执行宏任务,再执行微任务
宏任务(macroTask):script 中代码、setTimeout、setInterval、I/O、UI render;
微任务(microTask): Promise、Object.observe、MutationObserver。
Event Loop
Event Loop 是一个很重要的概念,指的是计算机系统的一种运行机制。
JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题。
I/O操作很慢,所以这个线程的大部分运行时间都在空等I/O操作的返回结果。这种运行方式称为"同步模式"(synchronous I/O)或"堵塞模式"(blocking I/O)。
每当遇到I/O的时候,主线程就让Event Loop线程去通知相应的I/O程序,然后接着往后运行,所以不存在等待时间。等到I/O程序完成操作,Event Loop线程再把结果返回主线程。主线程就调用事先设定的回调函数,完成整个任务。
Object.freeze(obj)
冻结对象,不能修改,不能添加
on 和 addEventListener的区别
- on下面的事件会替换掉前面的
- addEventListener 都会触发
- 阻止事件冒泡:绑定在红色的div事件上
e.stopPropagation();
aa.addEventListener('click',()=>{
console.log('aaa')
// true事件捕获,会先从外面触发
},true)
防抖和节流
防抖:在限制的一定时间之内,我们只能让这个方法执行一次,最后一次的点击去执行
节流:在限制的时间内,只执行第一次
- 防抖
//防抖debounce代码:
function debounce(fn,delay) {
var timeout = null; // 创建一个标记用来存放定时器的返回值
return function (e) {
// 每当用户输入的时候把前一个 setTimeout clear 掉
clearTimeout(timeout);
// 然后又创建一个新的 setTimeout, 这样就能保证interval 间隔内如果时间持续触发,就不会执行 fn 函数
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
};
}
// 处理函数
function handle() {
console.log('防抖:', Math.random());
}
//滚动事件
window.addEventListener('scroll', debounce(handle,500));
- 节流
let btn = document.getElementById("btn")
let timr = true
const throuttle = (fn,delay) => {
return () => {
// 如果定时器没有走完里面的方法,则不往下走
if(!timr) return
timr = false
setTimeout(() => {
fn()
timr = true
}, delay);
}
}
function success(){
console.log('aaa')
}
btn.addEventListener('click',throuttle(success,2000))
值类型 /引用类型
值类型:数字 字符串 布尔值
引用类型:数组和对象
浅拷贝和深拷贝
深拷贝在计算机中开辟了一块内存地址用于存放复制的对象,而浅拷贝仅仅是指向被拷贝的内存地址,如果原地址中对象被改变了,那么浅拷贝出来的对象也会相应改变。
拷贝的对象的值中如果有函数,undefined,symbol,经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失;
给数组对象添加一个新属性
let newArr = obj.map((item,index) =>{
return Object.assign(item,{index:index})
})
ES6
import * as xxx from ‘xxx’
import * as xxx from ‘xxx’ 会将 “xxx” 中所有 export 导出的内容组合成一个对象返回(或import * as obj from ‘xx’ 这种写法是把所有的输出包裹到obj对象里)
import * as filters from '@/utils/filter'
Loadshjs
router与route的区别
route相当于当前正在跳转的路由对象。。可以从里面获取name,path,params,query等。
router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。。。经常用的跳转链接就可以用this.$router.push,和router-link跳转一样
vue部分
脚手架中如何使用filter
utils文件夹中index文件
export const fmtGender = function (val) {
return val ? '女' : '男'
}
export const fmtMoney = function (val) {
return '$' + val
}
main 文件中
import * as filters from '@/utils/filter'
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
虚拟dom和真实dom区别
- 虚拟dom不会进行排版与重绘操作
- 虚拟dom进行频繁修改,然后一次性比较并修改真实dom中需要修改的部分(注意),最后并在真实dom中进行排版与重绘,减少过多dom节点排版与重绘损耗
- 真实dom频繁排版与重绘的效率是相当低的
- 虚拟dom有效降低大面积(真实dom节点)的重绘与排版,因为最终于真实dom比较差异,可以只渲染局部(同2)
- 总之,一切为了减弱频繁的大面积重绘引发的性能问题,不同框架不一定需要虚拟dom,关键是看框架是否频繁
虚拟dom的缺点
无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化
虚拟dom的实现原理
- 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象
- diff 算法 — 比较两棵虚拟 DOM 树的差异;
- pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
小程序与vue传参
- 小程序组件之间传参
- 调用组件的page
//wxml
<selectMenu bind:select="selectCity" list="{{cityList}}" title="城市"> </selectMenu>
//wxjs
selectCity(e){
this.setData({
currentCityid:e.detail.id
})
this.getShowlist()
},
- 组件内的js
// 外面属性传过来的需要在里面声明属性
properties: {
title:{
type:String
},
methods: {
select(e) {
let obj = this.data.list[this.data.activeIndex]
// 这边是事件发生,那边是select监听的,后面是需要传过去的东西
this.triggerEvent("select", obj )
}
}
- 组件的wxml
<view wx:key="id" bindtap="select" >{{item.name}}</view>
- vue组件之间的传参
详细连接
- 父往子用props子往父用$emit
- 祖孙之间使用依赖注入
//祖代组件
provide: function() {
return {
//
}
},
//孙代组件
// 通过inject接收
inject: ['obj'],
- 同级兄弟:使用中央事件总线,创造单独的vue实例利用$on监听 $emit触发
- 事件传参
- 小程序是通过data- id= "{{item.id}}"将id传入到js中,js中在事件的e的对象中获取传入的值
//wxml
<view class="pergoods" wx:for='{{goods}}' bindtap="jumpDetail" data-detail="{{item}}" data-id='{{item.id}}' wx:key='index'>
//wxjs
jumpGoods(e) {
let id = e.currentTarget.dataset.id;
}
- vue是直接将所需要传的参数方法事件中,在事件方法的e中直接获取
<div v-for="(item, index) in list" :key="item.id" @click="tap(item.id)">
methods: {
tap(id){
console.log(id)
}
},
-
跳转页面时传参
-
小程序中页面跳转时的传参
- 在前往的页面URL后面跟上参数
wx.navigateTo({
url: '../goodspage/goodspage?ti=' + detail + '&tt=' + index
})
- 在目标页面的初次渲染的函数中获取参数
onLoad: function (options) {
options是传入的所有参数的对象展示出来
},
- vue路由传参
连接
vue-loader
v-loader是加载器,作用是编译成浏览器可以识别的代码,能把.vue组件转化成JavaScript模块
- 为什么我们要转译这个vue组件
可以动态的渲染一些数据
对三个标签都做了优化,script中可以直接使用es6 style也默认可以使用sass,并且提供了作用域的作用
另外开发阶段,还提供了热加载
还可以在标签上直接src引用
- 懒加载是延迟加载
- 预加载是提前加载
- template 是结构 script是行为 style是表现
webpack常用的插件
ProvidePlugin
vue.nextTick()
- 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。简单解释:当数据更新了,在dom中渲染后,自动执行该函数
与setInterval(() => { }, 0); 作用一样。
怎么实现双向绑定的
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
let obj = {}
let age = 20
Object.defineProperty(obj, 'age', {
// get 和 set自动调用
get() {
console.log('有人访问')
// 修改的值返回出去
return age
},
set(val) {
// if(isNaN(val)) throw "非正整数" throw 抛出异常
console.log('有人赋值了')
age = val
app.innerHTML = obj.age
}
})
vue$set
向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性
- 一个对象或者数组修改时,页面没有相应
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set,Vue.set的一个别名
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
//
vm.items.splice(newLength)
- v-model 的原理
是语法糖 @input + :vaule
vue-router
小程序部分
一个小程序中怎么从一个小程序跳到另一个小程序
"navigateToMiniProgramAppIdList": [
"目标小程序的appid"
],
小程序里面怎么直接返回首页
小程序适配各个机型
小程序登录授权
wx.getUserInfo
<button open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">点击授权</button>
bindGetUserInfo(res) {
let info = res;
if (info.detail.userInfo) {
console.log("点击了同意授权");
wx.login({
success: function (res) {
console.log(res);
}
})
} else {
console.log("点击了拒绝授权");
}
- 判断是否登录
wx.checkSession({
success () {
//session_key 未过期,并且在本生命周期一直有效
},
fail () {
// session_key 已经失效,需要重新执行登录流程
wx.login() //重新登录
}
})