所有作为参数传入的值都会变成Arguments
对象的数组元素,即使在函数声明中没有指定参数名。
callee
和length
属性。
-
callee属性 指代当前正在执行的函数
-
length属性 传递给函数的参数个数,以及Arguments对象中数组元素的个数
Arguments
对象
arguments
是一个对应于传递给函数的参数的类数组对象。
示例:
function func1(a, b, c) {
console.log(arguments[0]);
// expected output: 1
console.log(arguments[1]);
// expected output: 2
console.log(arguments[2]);
// expected output: 3
}
func1(1, 2, 3);
可以被转换为一个真正的Array:
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
// ES2015
const args = Array.from(arguments);
const args = […arguments];
Arguments
对象的主要用途:
-
用来判断有多少个参数传入函数,还可以用来指代未命名的参数
-
除了数组元素和length属性,还可以通过callee属性来指代匿名函数本身。
Arguments.callee当前正在执行的函数
arguments.callee
,指代当前正在执行的函数,通过它可以引用匿名函数自身。该属性只定义在函数体中。
示例:
// 在匿名函数内使用callee属性来引用匿名函数自身
var fn = function(x) {
if(x<2) return 1;
else return x * arguments.callee(x-1)
}
var y = fn(5); // 120
Arguments.length传给函数的参数个数
arguments.length
,Arguments
对象的length
属性表示给当前函数的参数个数。该属性只能定义在函数体中。
该属性表示的是实际传入的参数个数,不是声明的参数个数。
示例:
alert(“实参长度:” +arguments.length);
alert("形参长度: " +arguments.callee.length);
// 使用Arguments对象来检查传入参数个数的正确性
function check(args) {
var actual = args.length; // 实际的参数个数
var expected = args.callee.length; // 期待的参数个数
if( actual != expected ) {
throw new Error(“参数个数有误,期望值:” + expected + “;实际值:” + actual);
}
}
function fn(x,y,z) {
check(arguments); // 检查参数个数的正确性
return x+y+z;
}
Object.keys()
Object.keys()
方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
语法
Object.keys(obj)
参数
obj
要返回其枚举自身属性的对象。
返回值
一个表示给定对象的所有可枚举属性的字符串数组。
示例:
// simple array
var arr = [‘a’, ‘b’, ‘c’];
console.log(Object.keys(arr)); // console: [‘0’, ‘1’, ‘2’]
// array like object
var obj = { 0: ‘a’, 1: ‘b’, 2: ‘c’ };
console.log(Object.keys(obj)); // console: [‘0’, ‘1’, ‘2’]
// array like object with random key ordering
var anObj = { 100: ‘a’, 2: ‘b’, 7: ‘c’ };
console.log(Object.keys(anObj)); // console: [‘2’, ‘7’, ‘100’]
// getFoo is a property which isn’t enumerable
var myObj = Object.create({}, {
getFoo: {
value: function () { return this.foo; }
}
});
myObj.foo = 1;
console.log(Object.keys(myObj)); // console: [‘foo’]
Object.getOwnPropertyNames()
Object.getOwnPropertyNames()
方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol
值作为名称的属性)组成的数组。
语法Object.getOwnPropertyNames(obj)
参数
obj
一个对象,其自身的可枚举和不可枚举属性的名称被返回。
返回值
在给定对象上找到的自身属性对应的字符串数组。
示例:
var arr = [“a”, “b”, “c”];
console.log(Object.getOwnPropertyNames(arr).sort()); // [“0”, “1”, “2”, “length”]
// 类数组对象
var obj = { 0: “a”, 1: “b”, 2: “c”};
console.log(Object.getOwnPropertyNames(obj).sort()); // [“0”, “1”, “2”]
// 使用Array.forEach输出属性名和属性值
Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {
console.log(val + " -> " + obj[val]);
});
// 输出
// 0 -> a
// 1 -> b
// 2 -> c
//不可枚举属性
var my_obj = Object.create({}, {
getFoo: {
value: function() { return this.foo; },
enumerable: false
}
});
my_obj.foo = 1;
console.log(Object.getOwnPropertyNames(my_obj).sort()); // [“foo”, “getFoo”]
Object.create()
Object.create()
方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
。
const person = {
isHuman: false,
printIntroduction: function() {
console.log(My name is ${this.name}. Am I human? ${this.isHuman}
);
}
};
const me = Object.create(person);
me.name = ‘Matthew’; // “name” is a property set on “me”, but not on “person”
me.isHuman = true; // inherited properties can be overwritten
me.printIntroduction();
// expected output: “My name is Matthew. Am I human? true”
语法Object.create(proto,[propertiesObject])
参数
proto
新创建对象的原型对象。
propertiesObject
可选。需要传入一个对象,该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。
返回值
一个新对象,带着指定的原型对象和属性。
例外
如果propertiesObject
参数是 null
或非原始包装对象,则抛出一个 TypeError
异常。
用 Object.create
实现类式继承
// Shape - 父类(superclass)
function Shape() {
this.x = 0;
this.y = 0;
}
// 父类的方法
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info(‘Shape moved.’);
};
// Rectangle - 子类(subclass)
function Rectangle() {
Shape.call(this); // call super constructor.
}
// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log(‘Is rect an instance of Rectangle?’,
rect instanceof Rectangle); // true
console.log(‘Is rect an instance of Shape?’,
rect instanceof Shape); // true
rect.move(1, 1); // Outputs, ‘Shape moved.’
如果你希望能继承到多个对象,则可以使用混入的方式。
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}
// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function() {
// do a thing
};
Object.assign
会把 OtherSuperClass
原型上的函数拷贝到 MyClass
原型上,使 MyClass
的所有实例都可用 OtherSuperClass
的方法。
使用 Object.create 的 propertyObject
参数
var o;
// 创建一个原型为null的空对象
o = Object.create(null);
o = {};
// 以字面量方式创建的空对象就相当于:
o = Object.create(Object.prototype);
o = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: {
writable:true,
configurable:true,
value: “hello”
},
// bar会成为所创建对象的访问器属性
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) {
console.log(“Setting o.bar
to”, value);
}
}
});
function Constructor(){}
o = new Constructor();
// 上面的一句就相当于:
o = Object.create(Constructor.prototype);
// 当然,如果在Constructor函数中有一些初始化代码,Object.create不能执行那些代码
// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
o = Object.create({}, { p: { value: 42 } })
// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
o.p = 24
o.p
//42
o.q = 12
for (var prop in o) {
console.log(prop)
}
//“q”
delete o.p
//false
//创建一个可写的,可枚举的,可配置的属性p
o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});
vue准备工作
-
学习认识flow,Vuejs源码目录设计,Vuejs源码构建,从入口开始(了解Vue准备)。
-
Flow
是facebook
出品的JavaScript
静态类型检查工具。 -
Vue
的源码利用了flow
做了静态类型检查。
flow的工作方式:
通常类型检查分为2种:第一种:类型推断;第二种:类型注解。
什么是类型推断呢?
通过变量的使用上下文来推断出变量类型。
什么是类型注解呢?
事先注解好想要的类型,flow会基于这些注解来判断。
在Vuejs的主目录下有.flowconfig
文件,是flow
的配置文件,[libs]
部分是用来描述包含指定库定义的目录。
flow
文件夹目录:
-
compiler.js
编译相关 -
component.js
组件数据结构 -
global-api.js
global api结构 -
modules.js
第三方库定义 -
options.js
选项相关 -
ssr.js
服务端渲染相关 -
vnode.js
虚拟node相关
了解Vue.js源码目录src下:
-
compiler
编译相关 -
core
核心代码 -
platforms
不同平台的支持 -
server
服务端渲染 -
sfc
-.vue
文件解析 -
shared
共享代码
Vuejs源码是基于Rollup构建的。
Vue 初始化过程
推荐:Vue 初始化过程
init流程图
Vue的本质:其实就是一个用Function实现的Class,通过它的原型prototype以及它本身扩展的一系列的方法和属性。
对数据渲染的过程有了更深的一层理解,从new Vue()
开始,创建了一个vue是对象,会先进行init初始化——>$mount()——>compile(若已经是render则该过程不需要)——>render——>创建VNode——>patch过程——>生成真实的DOM
null
如果想要任意类型T
可以为null
或者是undefined
,只需写为?T
的格式。
var foo: string = null
// 可以是字符串,也可以是null
Vue项目中为什么要在列表组件中写key,其作用是什么
key是给每个vnode的唯一的id,可以依靠key,更准确,更快的拿到oldVnode中对应的vnode节点。
['1','2','3'].map(parseInt)
答案是[1,NaN,NaN]
,为什么不是[1,2,3]
呢?
map函数的第一个参数callback,这个callback一共可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。
arr.map(callback: (value:T, index: number, array: T[]) => U, thisArg?:any);
- parseInt是用来解析字符串的,使得字符串成为指定基数的整数。接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。
parseInt(string, radix);
parseINT('1', 0)
表示 radix 为0时,且string参数不以"0x"和"0"开头时,按照10为基数进行处理,返回为1。
parseInt('2',1)
,基数为1,(1进制),表示的数中,最大值小于2,所以无法解析,返回为NaN。
什么是防抖和节流
防抖,字面意思放置的手抖再次触发。
onReachBottom() {
this.timer && clearTimeout(this.timer)
this.timer = setTimeout(this.getMoreList, 300)
},
触发高频事件后n秒后函数只会执行一次,如果n秒内高频事件再次被触发,则需要重新计算时间。
// 掘金:魔王哪吒
// 实现input实时搜索
function debounce(fn) {
let timeout = null
// 创建一个标记用来存放定时器的返回值
return function() {
clearTimeout(timeout)
// 每当用户输入的时候把前一个setTimeout clear掉
timeout = setTimeout(() => {
// 创建一个新的setTimeout,这样就能保证输入字符串后的interval间隔内如果还有字符输入的话,就不会执行fn函数
fn.apply(this, arguments);
},500)
}
}
function sayHi() {
console.log(‘防抖成功’)
}
var inp = document.getElementById(‘inp’);
inp.addEventListener(‘input’,debounce(sayHi)); // 防抖
节流,字面节约流量,高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执 行频率。
// 掘金:魔王哪吒
function throttle(fn) {
let canRun = true; // 通过闭包保持一个标记
return function() {
if(!canRun) return
// 在函数开头判断标记是否为true,不为true则return
canRun = false // 立即设置为false
setTimeout(() => {
fn.apply(this,argument);
// 最后在setTimeout执行完毕后再把标记设置为true表示可以执行下一次循环了,当定时器没有执行的时候标记为false
canRun = true
},500)
}
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight)
}
window.addEventListener(‘resize’, throttle(sayHi));
Set, Map, WeakSet, WeakMap
set,对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用
weakset,成员都是对象,成员都是弱引用,可以被垃圾回收机制回收,可以用来保存DOM节点,不容易造成内存泄漏。
Map,本质上是键值对的集合,类似集合,可以遍历,方法很多,可以跟各种数据格式转换。
WeakMap,只接收对象为键名(null除外),不接收其他类型的值作为键名,键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的,不能遍历,方法有get,set,has,delete
深度优先遍历和广度优先遍历
深度优先遍历
指从某个顶点出发,首先访问这个顶点,然后找出刚访问 这个结点的第一个未被访问的邻结点,然后再以此邻结点为顶点,继续找它的 下一个顶点进行访问。重复此步骤,直至所有结点都被访问完为止。
广度优先遍历
是从某个顶点出发,首先访问这个顶点,然后找出刚访问这个结点所有未被访问的邻结点,访问完后再访问这些结点中第一个邻结点的所有结点,重复此方法,直到所有结点都被访问完为止。
//1.深度优先遍历的递归写法
function deepTraveral(node) {
let nodes = []
if(node != null) {
nodes.push[node]
let childrens = node.children
for(let i=0; i<childrens.length; i++) deepTraversal(childrens[i])
}
return nodes
}
//2.深度优先遍历的非递归写法
function deepTraversal(node) {
let nodes = []
if(node != null) {
let stack = []
// 用来存放将来要访问的节点
stack.push(node)
while(stack.length != 0) {
let item = stack.pop()
// 正在访问的节点
nodes.push(item)
let childrens = item.children
for(let i = childrens.length-1; i>=0; i–) stack.push(childrens[i])
// 将现在访问点的节点的子节点存入stack,供将来访问
}
}
return nodes
}
//3.广度优先遍历的递归写法
function wideTraversal(node) {
let nodes = [], i = 0
if(node != null) {
nodes.push(node)
wideTraversal(node.nextElementSibling)
node = nodes[i++]
wideTraversal(node.firstElementChild)
}
return nodes
}
//4.广度优先遍历的非递归写法
function wideTraversal(node) {
let nodes = [], i=0
while(node != null) {
nodes.push(node)
node = nodes[i++];
let childrens = node.children
for(let i=0; i<childrens.length; i++) {
nodes.push(childrens[i])
}
}
return nodes
}
实现一个拷贝函数?
Object.prototype.toString()
toString()
方法返回一个表示该对象的字符串。
function Dog(name) {
this.name = name;
}
const dog1 = new Dog(‘掘金魔王哪吒’);
Dog.prototype.toString = function dogToString() {
return ${this.name}
;
};
console.log(dog1.toString());
// expected output: “掘金魔王哪吒”
语法
obj.toString()
// 返回值
// 一个表示该对象的字符串。
每个对象都有一个 toString()
方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()
方法被每个 Object
对象继承。如果此方法在自定义对象中未被覆盖,toString()
返回 "[object type]"
,其中 type
是对象的类型。
var o = new Object();
o.toString(); // returns [object Object]
使用
toString()
检测对象类型
可以通过 toString()
来获取每个对象的类型。为了每个对象都能通过 Object.prototype.toString()
来检测,需要以 Function.prototype.call()
或者 Function.prototype.apply()
的形式来调用,传递要检查的对象作为第一个参数,称为 thisArg
。
示例:
var toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
//Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
Function.prototype.call()
call()
方法使用一个指定的 this
值和单独给出的一个或多个参数来调用一个函数。
call()
方法接受的是一个参数列表
示例:
// 掘金:魔王哪吒
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = ‘food’;
}
console.log(new Food(‘cheese’, 5).name);
// expected output: “cheese”
语法
function.call(thisArg, arg1, arg2, …)
thisArg
可选的。在 function
函数运行时使用的 this
值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined
时会自动替换为指向全局对象,原始值会被包装。
arg1, arg2, ...
指定的参数列表。
返回值
使用调用者提供的 this
值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined
。
描述
call()
允许为不同的对象分配和调用属于一个对象的函数/方法。
call()
提供新的 this
值给当前调用的函数/方法。你可以使用 call
来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法)。
使用 call 方法调用父构造函数
示例:
// 掘金:魔王哪吒
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = ‘food’;
}
function Toy(name, price) {
Product.call(this, name, price);
this.category = ‘toy’;
}
var cheese = new Food(‘feta’, 5);
var fun = new Toy(‘robot’, 40);
Function.prototype.apply()
apply()
方法调用一个具有给定this
值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
语法
// 掘金:魔王哪吒
func.apply(thisArg, [argsArray])
参数
thisArg
必选的。在 func 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined
时会自动替换为指向全局对象,原始值会被包装。
argsArray
可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 null 或 undefined
,则表示不需要传入任何参数。从ECMAScript 5
开始可以使用类数组对象。
返回值
调用有指定this
值和参数的函数的结果。
描述
在调用一个存在的函数时,你可以为其指定一个 this 对象。 this 指当前对象,也就是正在调用这个函数的对象。 使用 apply, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。
用 apply 将数组各项添加到另一个数组
// 掘金:魔王哪吒
var array = [‘a’, ‘b’];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // [“a”, “b”, 0, 1, 2]
Function.prototype.bind()
bind()
方法创建一个新的函数,在 bind()
被调用时,这个新函数的 this
被指定为 bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
// 掘金:魔王哪吒
const module = {
x: 42,
getX: function() {
return this.x;
}
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
语法
// 掘金:魔王哪吒
function.bind(thisArg[, arg1[, arg2[, …]]])
返回值
返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。
创建绑定函数
// 掘金:魔王哪吒
this.x = 9; // 在浏览器中,this 指向全局的 “window” 对象
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var retrieveX = module.getX;
retrieveX();
// 返回 9 - 因为函数是在全局作用域中调用的
// 创建一个新函数,把 ‘this’ 绑定到 module 对象
// 新手可能会将全局变量 x 与 module 的属性 x 混淆
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
在默认情况下,使用 window.setTimeout()
时,this
关键字会指向 window
(或 global
)对象。当类的方法中需要 this
指向类的实例时,你可能需要显式地把 this
绑定到回调函数,就不会丢失该实例的引用。
将一个类似于数组的对象转换成一个真正的数组
// 掘金:魔王哪吒
var slice = Array.prototype.slice;
// …
slice.apply(arguments);
Array.prototype.slice()
slice()
方法返回一个新的数组对象,这一对象是一个由 begin 和 end
决定的原数组的浅拷贝(包括 begin
,不包括end
)。原始数组不会被改变。
// 掘金:魔王哪吒
const animals = [‘ant’, ‘bison’, ‘camel’, ‘duck’, ‘elephant’];
console.log(animals.slice(2));
// expected output: Array [“camel”, “duck”, “elephant”]
console.log(animals.slice(2, 4));
// expected output: Array [“camel”, “duck”]
console.log(animals.slice(1, 5));
// expected output: Array [“bison”, “camel”, “duck”, “elephant”]
语法
// 掘金:魔王哪吒
arr.slice([begin[, end]])
返回值
一个含有被提取元素的新数组。
描述
slice 不会修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。原数组的元素会按照下述规则拷贝:
如果该元素是个对象引用 (不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。
如果向两个数组任一中添加了新元素,则另一个不会受到影响。
类数组(Array-like)对象
slice 方法可以用来将一个类数组(Array-like
)对象/集合转换成一个新数组。你只需将该方法绑定到这个对象上。 一个函数中的 arguments 就是一个类数组对象的例子。
// 掘金:魔王哪吒
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
除了使用 Array.prototype.slice.call(arguments)
,你也可以简单的使用 [].slice.call(arguments)
来代替。
可以使用 bind 来简化该过程
// 掘金:魔王哪吒
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
function list() {
return slice(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
环状数据
// 掘金:魔王哪吒
const obj = {
foo: {
name: ‘foo’,
bar: {
name: ‘bar’
baz: {
name: ‘baz’,
aChild: null //待会让它指向obj.foo
}
}
}
}
obj.foo.bar.baz.aChild = obj.foo // foo->bar->baz->aChild->foo 形成环
JSON.stringify(obj) // => TypeError: Converting circular structure to JSON
拷贝这样封闭的环状数据结构,会导致死循环
先说说什么是深拷贝与浅拷贝
浅拷贝:也就是拷贝A对象里面的数据,但是不拷贝A对象里面的子对象
深拷贝:会克隆出一个对象,数据相同,但是引用地址不同(就是拷贝A对象里面的数据,而且拷贝它里面的子对象)
浅拷贝和深拷贝的区别
推荐: 请分别用深度优先思想和广度优先思想实现一个拷贝函数? 每日一题系列(六)")
uniapp实现小程序微信登录
推荐:企业微信开放平台注册流程
推荐:uniapp实现小程序微信登录
补充:app
生成签名证书
testalias 和 test.keystore中的'test'
都是可以修改的,可以替换为自己项目中的名字。输入下面的keytool -genkey
命令就可以生成证书了
keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore
用签名生成工具生成签名
uniapp的mainfest.json
文件配置中,appid必须是'_UNI_'
开头,所以你的配置文件中得是'_UNI_'
开头的。
推荐:小程序静默登录方案设计
推荐:小程序用户登录架构设计
登录方案
-
Cookie + Session
登录 -
Token
登录 -
SSO
单点登录 -
OAuth
第三方登录
SSO
单点登录,适用于中大型企业,想要统一内部所有产品的登录方式的情况。
实现垂直居中
// 掘金:魔王哪吒
flex
margin: 0 auto
canvas如何实现按比例沾满全屏
-
document.documentElement.clientWidth
: 可见区域宽度; -
document.documentElement.clientHeight
: 可见区域高度。 -
canvas.width = document.documentElement.clientWidth
-
canvas.height = document.documentElement.clientHeight
-
screen.availWidth
:屏幕可用宽度; -
screen.availHeight
:屏幕可见高度。 -
canvas.width = screen.availWidth;
-
canvas.height = screen.availHeight;
-
screen.width:屏幕显示宽度
-
screen.height:屏幕显示高度
-
canvas.width = screen.width
-
canvas.height = screen.height
-
window.innerWidth:窗口的宽度
-
window.innerHeight:窗口的高度
-
canvas.width = window.innerWidth
-
canvas.height = window.innerHeight
Vue2.0
Vue源码根目录下文件夹:
-
build
打包相关的配置文件,根据不同的入口,打包为不同的文件 -
dist
打包之后文件所在位置 -
examples
部分示例 -
flow
,因Vue使用了Flow
来进行静态类型检查,这里是定义了声明一些静态类型 -
packages
,分别生成其他的npm
包 -
src
,主要源码所在位置 -
compiler
模板解析的相关文件 -
codegen
根据ast
生成render
函数 -
directives
通用生成render
函数之前需要处理的指令 -
parser
模板解析 -
core
核心代码 -
components
全局组件 -
global-api
全局方法 -
instance
实例相关内容,包括实例方法,生命周期,事件等 -
observer
双向数据绑定相关文件 -
util
工具方法 -
vdom
虚拟dom
相关 -
entries
入口文件,也就是build
文件夹下config.js
中配置的入口文件 -
platforms
平台相关的内容 -
web
,web
端独有文件 -
compiler
编译阶段需要处理的指令和模块 -
runtime
运行阶段需要处理的组件,指令和模块 -
server
服务端渲染相关 -
util
工具库 -
weex
,weex
端独有文件 -
shared
共享的工具方法 -
test
测试用例
从入口文件查看Vue源码
先看package.json
文件,有项目的依赖,有开发环境,生产环境等编译的启动脚本,有项目的许可信息等。来看看:npm run dev
:
// 掘金:魔王哪吒
“dev”: “rollup -w -c build/config.js --environment TARGET:web-full-dev”
rollup
是一个类似于webpack的打包工具,入口文件:/src/entries/web-runtime-with-compiler.js
// 掘金:魔王哪吒
/src/entries/web-runtime-with-compiler.js
–> /src/entries/web-runtime.js
–> /src/core/index.js
–> /src/core/instance/index.js
定义Vue对象它的构造函数及其简单:
// 掘金:魔王哪吒
function Vue (options) {
// 判断是不是生产环境
if (process.env.NODE_ENV !== ‘production’ &&
!(this instanceof Vue)) {
//如果不是通过new关键字来创建对象的话
warn(‘Vue is a constructor and should be called with the new
keyword’)
}
this._init(options)
}
Vue的静态方法和实例方法:
// src/core/index.js
Vue.version = ‘VERSION’
// src/entries/web-runtime-with-compiler.js
Vue.compile = compileToFunctions
// 把模板template转换为render函数
// src/core/global-api
// 在目录结构中,Vue的静态方法大多都是在该文件夹中定义的
// src/core/global-api/index.js
Vue.config
Vue.util
Vue.set
Vue.delete
Vue.nextTick
Vue.options = {
components: {KeepAlive: KeepAlive}
directives: {},
filters: {},
_base: Vue
}
// src/core/global-api/use.js
Vue.use
// src/core/global-api/mixin.js
Vue.mixin
// src/core/global-api/extend.js
Vue.extend
// src/core/global-api/assets.js
Vue.component
Vue.directive
Vue.filter
vm._uid // 自增的id
vm._isVue // 标示是vue对象,避免被observe
vm._renderProxy // Proxy代理对象
vm._self // 当前vm实例
vm.$parent // 用于自定义子组件中,指向父组件的实例
vm.$root // 指向根vm实例
vm.$children // 当前组件的子组件实例数组
vm.$refs
vm._watcher = null
vm._inactive = null
vm._directInactive = false
vm._isMounted = false // 标识是否已挂载
vm._isDestroyed = false // 标识是否已销毁
vm._isBeingDestroyed = false // 标识是否正在销毁
vm._events // 当前元素上绑定的自定义事件
vm._hasHookEvent // 标示是否有hook:开头的事件
vm. v n o d e / / 当前自定义组件在父组件中的 v n o d e ,等同于 v m . vnode // 当前自定义组件在父组件中的vnode,等同于vm. vnode//当前自定义组件在父组件中的vnode,等同于vm.options._parentVnode
vm._vnode // 当前组件的vnode
vm._staticTrees // 当前组件模板内分析出的静态内容的render函数数组
vm.$el // 当前组件对应的根元素
vm.$slots // 定义在父组件中的slots,是个对象键为name,值为响应的数组
vm.$scopedSlots = emptyObject
// 内部render函数使用的创建vnode的方法
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
// 用户自定义render方法时,传入的参数
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
vm._props // 被observe的存储props数据的对象
vm._data // 被observe的存储data数据的对象
vm._computedWatchers // 保存计算属性创建的watcher对象
钩子函数:
-
beforeCreate
,创建之前 -
created
,创建 -
beforeMount
,挂载前 -
mounted
,挂载 -
beforeUpdate
,更新前 -
updated
,更新 -
activated
,触发 -
deactivated
,停用 -
beforeDestroy
,销毁前 -
destroyed
,毁坏
// vm.$options
declare type ComponentOptions = {
// data
data: Object | Function | void; // 传入的data数据
props?: { [key: string]: PropOptions }; // props传入的数据
propsData?: ?Object; // 对于自定义组件,父级通过props
传过来的数据
computed?: { // 传入的计算属性
[key: string]: Function | {
get?: Function;
set?: Function;
cache?: boolean
}
};
methods?: { [key: string]: Function }; // 传入的方法
watch?: { [key: string]: Function | string }; // 传入的watch
// DOM
el?: string | Element; // 传入的el字符串
template?: string; // 传入的模板字符串
render: (h: () => VNode) => VNode; // 传入的render函数
renderError?: (h: () => VNode, err: Error) => VNode;
staticRenderFns?: Array<() => VNode>;
// 钩子函数
beforeCreate?: Function;
created?: Function;
beforeMount?: Function;
mounted?: Function;
beforeUpdate?: Function;
updated?: Function;
activated?: Function;
deactivated?: Function;
beforeDestroy?: Function;
destroyed?: Function;
// assets
directives?: { [key: string]: Object }; // 指令
components?: { [key: string]: Class }; // 子组件的定义
transitions?: { [key: string]: Object };
filters?: { [key: string]: Function }; // 过滤器
// context
provide?: { [key: string | Symbol]: any } | () => { [key: string | Symbol]: any };
inject?: { [key: string]: string | Symbol } | Array;
// component v-model customization
model?: {
prop?: string;
event?: string;
};
// misc
parent?: Component; // 父组件实例
mixins?: Array; // mixins传入的数据
name?: string; // 当前的组件名
extends?: Class | Object; // extends传入的数据
delimiters?: [string, string]; // 模板分隔符
// 私有属性,均为内部创建自定义组件的对象时使用
_isComponent?: true; // 是否是组件
_propKeys?: Array; // props传入对象的键数组
_parentVnode?: VNode; // 当前组件,在父组件中的VNode对象
_parentListeners?: ?Object; // 当前组件,在父组件上绑定的事件
_renderChildren?: ?Array; // 父组件中定义在当前元素内的子元素的VNode数组(slot)
_componentTag: ?string; // 自定义标签名
_scopeId: ?string;
_base: Class; // Vue
_parentElm: ?Node; // 当前自定义组件的父级dom结点
_refElm: ?Node; // 当前元素的nextSlibing元素,即当前dom要插入到_parentElm结点下的_refElm前
}
拿到一个函数的返回值类型,使用TS
const func = (): number => 1;
// 声明一个泛型类型别名,返回值与泛型类型相同,入参类型不限制。
type Reverse = (arg: any) => T;
// 声明一个泛型方法,入参arg继承泛型约束,返回空对象并断言其类型为T
function returnResultType(arg: Reverse): T {
return {} as T;
}
// 调用returnResultType,传入方法(arg: any) => 3,获得result返回值
const result = returnResultType((arg:any) => 3);
// 获取result类型并重名为ResultType
type ResultType = typeof result;
Array
构造函数:
new Array()
new Array(size)
new Array(element0, element1, …, elementn)
-
size
设定的数组元素个数。返回数组的length
属性等于size
。 -
参数列表,
element0,..,elementn
,当Array()
构造函数用这些参数调用时,新创建的数组实例会用指定的参数值来初始化,并将length
属性设置为参数个数。 -
当不带参数调用
Array()
时,返回的数组为空,length
属性为0。 -
concat()
,把元素衔接到数组中。 -
every()
,测试断言函数是否对每个数组元素都为真。 -
filter()
,返回满足断言函数的数组元素。 -
forEach()
,为数组的每一个元素调用指定函数。 -
indexOf()
,在数组中查找匹配元素。 -
join()
,将数组的所有元素转换为字符串,并衔接起来。 -
lastIndexOf()
,在数组中反向查找。 -
map()
,从数组的元素中,计算出新的数组元素。 -
pop()
,移除数组最后一个元素。 -
push()
,把元素添加到数组尾部。 -
reduce()
,从数组的元素中,计算出一个值。 -
reduceRight()
,从右到左缩减数组。 -
reverse()
,在原数组中颠倒元素的顺序。 -
shift()
,移除数组的第一个元素。 -
slice()
,返回数组的一部分。 -
some()
,测试是否至少有一个数组元素能让断言函数为真。 -
sort()
,在原数组中对数组元素进行排序。 -
splice()
,插入,删除,或替换数组元素。 -
toLocaleString()
,将数组转换为本地字符串。 -
toString()
,将数组转换为字符串。 -
unshift()
,在数组头部插入元素。
Array.concat()
array.concat(value, …)
返回值,一个新数组,包含array
的元素,以及衔接的新元素。
concat()
会将参数衔接到array
中得到一个新数组并返回,它不会修改array
,如果传给concat()
的某个参数本身是一个数组,则会将该数组的元素衔接到array
中,而不是数组本身。
var a = [1,2,3];
a.concat(4,5); // [1,2,3,4,5];
Array.every()
测试断言函数是否对每个元素为真
array.every(predicate)
array.every(predicate,o)
参数:
-
predicate
,用来测试数组元素的断言函数。 -
o
,调用predicate
时的可选this
值。
返回值:如果对array
的每一个元素调用predicate
时都返回真值,则返回true
,如果有任何一个元素调用predicate
时返回假值,则返回false
。
every()
方法用来测试数组的所有元素是否都满足某些条件。如果predicate
的每一次调用都返回true
,则every()
返回true
,否则,为false
。
当遍历的数组为空时,every()
返回true
[1,2,3].every(function(x) { return x<5 ;}) // true
[1,2,3].every(function(x) { return x<3 ;}) // false
[].every(function(x) {return false;}); // true []总是返回true
Array.filter()
返回通过断言的数组元素
-
array.map(predicate)
-
array.map(predicate, o)
-
predicate
,用来判断array
中的元素是否需要包含在返回数组中的调用函数 -
o
,调用predicate
时的可选this
值
返回值:
一个新数组,只包含那些让predicate
返回真值的数组元素
filter()
会创建一个新数组,包含那些让predicate
函数返回真值的array
的元素。filter()
方法不会修改arrry
本身,注意predicate
函数有可能会修改。
返回新创建的数组。
Array.forEach()
为每一个数组元素调用一个函数
array.forEach(f)
array.forEach(f,o)
参数
f 为array的每一个元素调用的函数
o 调用f时的可选this值
返回值:该方法无返回值,注意forEach()
没有返回值,特别注意,它不会返回array
。
forEach(), map(), filter(), every(), some()
接受函数作为第一个参数,并接受可选的第二个参数。在函数体内,this值等于o。
如果没有指定第二个参数,this值在非严格模式下是全局对象,在严格模式下则为null
。
var a = [1,2,3];
a.forEach(function(x,i,a){ a[i]++; }); // [2,3,4]
Array.indexOf()
查找数组
array.indexOf(value)
array.indexOf(value,start)
参数:
value 要在array中查找的值
start 开始查找的可选数组序号,可以省略,则为0
返回值,所在index,如果不存在匹配元素时,返回-1
判断是否相等使用的是"==="操作符
[‘a’, ‘b’, ‘c’].indexOf(‘b’); // 1
[‘a’, ‘b’, ‘c’].indexOf(‘d’, 1); // -1
Array.join()
,将数组元素衔接为字符串
array.join()
array.join(separator)
separator
,在返回的字符串中,用来分隔数组的某个元素与下一个元素的可选字符或字符串。如果省略,默认是英文逗号。
返回值,一个字符串。
a = new Array(1,2,3,“test”);
s = a.join(“+”); // 1+2+3+test
Array.lastIndexOf()
反向查找数组
array.lastIndexOf(value);
array.lastIndexOf(value,start);
-
value
,要在array
中查找的值 -
start
,开始查找的可选数组序号,如果省略,则从最后一个元素开始查找
Array.length
数组大小
length
属性表示数组中的元素个数
如果设置的
length
大于原值,数组会变大,新添加到末尾处的元素的值为undefined
。
Array.map()
从数组元素中计算新值
array.map(f);
array.map(f,o);
-
f
为array的每一个元素调用的函数,它的返回值会成为返回数组的元素。 -
o
-f
调用时的可选this
值。
返回值:一个新数组,由函数f
计算出的元素组成。
[1,2,3].map(function(x) { return x*x }); // [1,4,9]
Array.pop()
移除并返回数组的最后一个元素
array.pop()
返回值:array
的最后一个元素
pop()
会移除array
的最后一个元素,缩短数组的长度,并返回所移除元素的值。如果数组已经为空,pop()
不会修改该数组,返回值为undefined
。
pop()
和push()
,先进后出的栈功能:
var stack = []; // stack: []
stack.push(1,2); // stack: [1,2] 返回2
stack.pop(); // stack: [1] 返回2
stack.push([4,5]); // stack: [1, [4,5]] 返回2
stack.pop(); // stack: [1] 返回[4,5]
stack.pop(); // stack: [] 返回1
Array.push()
给数组追加元素
array.push(value,…);
返回值:把指定值追加到数组后数组的新长度。(它会直接修改array,而不会创建一个新的数组)
push()
和pop()
,先进后出的栈功能。
Array.reduce()
从数组元素中计算一个值
array.reduce(f);
array.reduce(f,initial);
-
f
一个函数,可以合并两个值,并返回一个“缩减”的新值。 -
initial
,用来缩减数组的可选初始值,如果指定该参数,reduce()
的行为会像把该参数插入array
的头部一样。
返回值:数组的化简值
示例:
[1,2,3,4].reduce(function(x,y) { return x*y; }) // 24
Array.reduceRight()
从右到左缩减数组
array.reduceRight(f)
array.reduceRight(f, initial)
-
f
一个函数,可以合并两个值,并返回一个“缩减”的新值。 -
initial
用来缩减数组的可选初始值,如果指定该参数,reduceRight()
的行为会像是把该参数插入aray
的尾部一样。
返回值:数组的缩减值,该值是最后一次调用f
时的返回值。
[2,10,60].reduceRight(function(x,y) { return x/y; }) // 3
Array.reverse()
颠倒数组中的元素顺序
array.reverse()
Array
对象的reverse()
方法可以颠倒数组元素的顺序。它会在原数组中进行操作,而不会创建一个新数组。
a = new Array(1,2,3);
a.reverse();
Array.shift()
移除数组的第一个元素
array.shift()
返回值:数组原来的第一个元素。
如果数组为空,
shift()
什么也不干,返回undefined
值,没有创建新数组。
var a = [1,[2,3],4];
a.shift(); // 1
Array.slice()
返回数组的一部分
array.slice(start, end)
返回值:一个新数组,包含array中从start一直到end之间的所有元素(包含start指定的元素,但不包含end指定的元素),如果没有指定end,返回的数组包含从start到array尾部的所有元素。
var a = [1,2,3,4,5];
a.slice(0,3); // 返回 [1,2,3]
a.slice(3); // 返回 [4,5]
Array.some()
测试是否有元素满足断言函数
array.some(predicate)
array.some(predicate,o)
-
predicate
用来测试数组元素的断言函数 -
o
调用predicate
时的可选this
值
返回值:如果array
中有至少一个元素调用predicate
时返回真值,则返回true,如果所有元素调用predicate
时都返回假值,则返回false。
[1,2,3].some(function(x) { return x>5; }); //false
[1,2,3].some(function(x) { return x>2; }); // true
[].some(function(x) { return false; }); // false
Array.sort()
对数组元素进行排序
array.sort()
array.sort(orderfunc)
orderfunc
用来指定如何排序的可选函数
返回值:该数组的引用。注意是在原数组中进行排序,没有新键数组。数组中的undefined元素会始终排列在数组末尾。
function numberorder(a,b) {return a-b;}
a = new Array(3,2,4);
a.sort(); // 字母排序
a.sort(numberorder); // 数值排序
Array.splice()
插入,删除或替换数组元素
array.splice(start,deleteCount,value,…)
-
start
开始插入和删除处的数组元素的序号。 -
deleteCount
要删除的元素个数,从start
开始,并包含start
处的元素,如果指定为0,表示插入元素,而不用删除任何元素。 -
value,...
要插入数组中的零个或多个值,从start
序号开始插入。
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
[4,5]] 返回2
stack.pop(); // stack: [1] 返回[4,5]
stack.pop(); // stack: [] 返回1
Array.push()
给数组追加元素
array.push(value,…);
返回值:把指定值追加到数组后数组的新长度。(它会直接修改array,而不会创建一个新的数组)
push()
和pop()
,先进后出的栈功能。
Array.reduce()
从数组元素中计算一个值
array.reduce(f);
array.reduce(f,initial);
-
f
一个函数,可以合并两个值,并返回一个“缩减”的新值。 -
initial
,用来缩减数组的可选初始值,如果指定该参数,reduce()
的行为会像把该参数插入array
的头部一样。
返回值:数组的化简值
示例:
[1,2,3,4].reduce(function(x,y) { return x*y; }) // 24
Array.reduceRight()
从右到左缩减数组
array.reduceRight(f)
array.reduceRight(f, initial)
-
f
一个函数,可以合并两个值,并返回一个“缩减”的新值。 -
initial
用来缩减数组的可选初始值,如果指定该参数,reduceRight()
的行为会像是把该参数插入aray
的尾部一样。
返回值:数组的缩减值,该值是最后一次调用f
时的返回值。
[2,10,60].reduceRight(function(x,y) { return x/y; }) // 3
Array.reverse()
颠倒数组中的元素顺序
array.reverse()
Array
对象的reverse()
方法可以颠倒数组元素的顺序。它会在原数组中进行操作,而不会创建一个新数组。
a = new Array(1,2,3);
a.reverse();
Array.shift()
移除数组的第一个元素
array.shift()
返回值:数组原来的第一个元素。
如果数组为空,
shift()
什么也不干,返回undefined
值,没有创建新数组。
var a = [1,[2,3],4];
a.shift(); // 1
Array.slice()
返回数组的一部分
array.slice(start, end)
返回值:一个新数组,包含array中从start一直到end之间的所有元素(包含start指定的元素,但不包含end指定的元素),如果没有指定end,返回的数组包含从start到array尾部的所有元素。
var a = [1,2,3,4,5];
a.slice(0,3); // 返回 [1,2,3]
a.slice(3); // 返回 [4,5]
Array.some()
测试是否有元素满足断言函数
array.some(predicate)
array.some(predicate,o)
-
predicate
用来测试数组元素的断言函数 -
o
调用predicate
时的可选this
值
返回值:如果array
中有至少一个元素调用predicate
时返回真值,则返回true,如果所有元素调用predicate
时都返回假值,则返回false。
[1,2,3].some(function(x) { return x>5; }); //false
[1,2,3].some(function(x) { return x>2; }); // true
[].some(function(x) { return false; }); // false
Array.sort()
对数组元素进行排序
array.sort()
array.sort(orderfunc)
orderfunc
用来指定如何排序的可选函数
返回值:该数组的引用。注意是在原数组中进行排序,没有新键数组。数组中的undefined元素会始终排列在数组末尾。
function numberorder(a,b) {return a-b;}
a = new Array(3,2,4);
a.sort(); // 字母排序
a.sort(numberorder); // 数值排序
Array.splice()
插入,删除或替换数组元素
array.splice(start,deleteCount,value,…)
-
start
开始插入和删除处的数组元素的序号。 -
deleteCount
要删除的元素个数,从start
开始,并包含start
处的元素,如果指定为0,表示插入元素,而不用删除任何元素。 -
value,...
要插入数组中的零个或多个值,从start
序号开始插入。
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-TcrqlWLg-1714860870887)]
[外链图片转存中…(img-G9Vq4mgb-1714860870887)]
[外链图片转存中…(img-q5edllqS-1714860870888)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!