Licence
MIT
Version
1.0.1
Deps
0
Size
29 kB
Vulns
0
Weekly
0
基础
var i = 1
for (;i;) {
i++
console.log(i)
}
//死循环 两个分号中间哪一个是一个判断类型 i为的时候始终为true
var i = 100
for (;i --;) {
console.log(i) //打印所有100以内的数
}
- typeof
typeof(typeof(undefined)) //string
- undefined是NaN
函数调用
var test = function test1() {
console.log('函数执行')
}
test1() //报错
var test = function test1() {
console.log('函数执行')
test1() //在内部可以使用
}
test() //调用无限循环 相当于递归
console.log(test.name) //test1
- arguments
- arguments数组里面的值和是与实参存在映射关系的 然而他们并不是同一个变量
- 假如没有传入实参 又在函数内部修改形参的值 就无法一一对应 因为本质上他们只存在映射关系而不是同一个值
function test(a,b) {
console.log(arguments.length)//3打印的是实参个数
}
test(1,2,3)
console.log(test.length) //2打印的是形参个数
参数默认值
- 不管是形参默认值还是传入的实参 只要是参数有一个是undefined而一个不是undefined 那么默认就会取不是undefined的值
function test(a=1,b) {
console.log(a+b)
}
test(undefined,2) //3
function test(a=undefined,b) {
console.log(a+b)
}
test(1,2) //3
//传入null
function test(a=null,b) {
console.log(a)
}
test(undefined) //null
函数预编译的顺序
- 形参和变量声明
- 实参赋值给实参
- 寻找当前函数里的函数声明赋值
- 执行函数
函数作用域
- 当函数被定义时作用域暂未形成 但是作用域链已经形成 在当前作用域链的最顶端是全局作用域GO
- 当函数开始执行的前一刻 作用域形成 当前的作用域AO被放在了作用域链的最顶端而全局作用域被挤下了一位
function a() {
function b() {
var b = 2
}
var a = 1
b()
}
var c = 3
a()
如上函数执行
首先c变量声明 函数a声明 a作用域链形成 作用域尚未形成 a作用域链的顶端仍然是GO全局作用域
然后c变量赋值3 a函数执行
这时作用域形成 a变量声明 b函数声明 但是b函数还未执行作用域尚未形成 作用域链已经形成 b函数的顶端暂时还是a函数的AO AO表示a函数的执行上下文
a函数的作用域形成 顶端是就是自己的函数作用域 GO的全局作用域已经从顶端被挤下去
然后a赋值为1
b函数执行 声明b变量 作用域形成 b函数的AO被提到自己的最顶端 a函数的作用域被挤下来 1赋值给b
b函数执行结束 函数作用域和AO被销毁 作用域链尚未被销毁 作用域链的顶端是a函数的执行上下文
b函数结束之后a函数执行结束
a函数作用域和AO被销毁 同时b函数的作用域链被销毁 a的作用域链尚未被销毁 a函数作用域链顶端是GO全局作用域
闭包
function test1() {
var a = 100
return function add() {
a++
console.log(a)
}
}
var test2 = test1()
test2() //101
test2() //102
- 首先在全局作用上 变量声明test2 函数声明test1
- 当函数test2执行时 其内的作用域链上最顶端的是自己的AO(执行上下文) 然后是test1的AO 最后面是GO(全局作用域)
- 当函数执行时a++ 自身AO没有a于是去test1的AO中拿到 然后执行a++ 最后打印出来
- 而这个时候函数销毁 但是test2被返回出去的时候 在外界使用本来在test1执行完毕之后其内的AO应该被销毁
- 但是外界需要使用的情况下 test1销毁的只是与自身AO的引用
- test2需要test1AO中的数据所以AO在这个时候被保存到内存中不被销毁
- 当第二次使用test2的时候又再次使用这个test1的里面被保存保存的AO
- 但是是基于现在test1的AO中保存的数据也就是a=101中的基础上改变
立即执行函数
- 只有函数表达式可以立即执行函数
- 立即执行函数在执行接收之后就会立即销毁
- 立即执行函数会忽略函数名
var test = function() {
console.log(1)//1
}()
//上面的函数已经执行完毕 假如再次调用会报错因为函数已经销毁
test() //报错
//其他写法 加上运算符已经算作表达式其中包括 * + - / && || ()
//()
(function() {
console.log(1) //1
})()
//用数字来乘 或者字符串 其他加减除雷同
5 * function() {
console.log(1) //1
}()
//用或 前面需要是true才能走到后面 与也雷同
‘anyone’ || function() {
console.log(1) //1
}
来个题
var a = 10
if (function b() {}){
a += typeof(b)
}
console.log(a)
- 首先变量a声明 然后赋值为10
- 此时走到if语句中的判断 首先这里面是一个true 所以就进入
- 这个时候等到要typeof(b)的时候 其实由于function被加到if括号里面他已经看作表达式 现在已经销毁
- 此时此刻b是一个字符串类型的undefined 再与a相加
- 结果:10undefined
逗号运算
- 当在括号里使用逗号的时候默认会使用最后一个值
console.log((5,6)) //6
来个题
- 首先一个括号里面有两个函数 这两个函数都有返回值
- fn就相当于(function test1(){},function test2(){})
- 而取逗号的最后一位fn 就等于 function test2(){return 2}
- 外面有个立即执行的括号所以就相当于 function test2(){ return}()
- 立即执行test2函数后return一个返回值2
- 结果 : 2
var fn = (
function test1() {
return 1
},
function test2() {
return 2
}
)()
console.log(fn) //2
构造函数原理
- 实际上在new之前函数在执行了
- 而看到前面有一个new的关键字
- 此时在构造函数Car的内部会声明一个this的空对象(其实并不准确并不是一个完全的空对象)
- 然后通过this把那些属性给添加到this对象中
- 等构造函数执行到最后一步 会默认把this对象返回出去
- 所以实例化对象相当于对这个this复制了一个指针
- 而每构造出一个对象都是独立的存在
function Car(name,color) {
this.name = name,
this.color = color
}
var car1 = new Car('banz','red')
var car2 = new Car('mazid','black')
console.log(car1.name) //banz
console.log(car2.name) //mazid
- 以上代码其实大致相当于以下代码
function Car(name,color) {
var my = {}
my.name = name,
my.color = color
return my
}
var car1 = Car('banz','red')
var car2 = Car('mazid','black')
console.log(car1.name) //banz
console.log(car2.name) //mazid
- 但是要注意一点的是 在构造函数内部如果使用了this
- 而return的如果是基本类型
- 那么将默认还是返回this对象
function Car(name,color) {
var str = 'abc'
this.name = name,
this.color = color
return str
}
var car1 = new Car('banz','red')
console.log(car1.name) //banz
- 如果是其他的引用类型则不是如此
function Car(name,color) {
this.name = name,
this.color = color
return {}
}
var car1 = new Car('banz','red')
console.log(car1.name) //undefined
call apply bind 用法和区别
- 本质上call和bind是用来做函数调用的
- 在函数调用时候即便不使用call也会在后面隐式的添加上call
- call和apply的区别仅仅是传入调用函数的实参是一个个传递 还是用arguments传递
function fn(a,b) {
console.log(a,b,this);
}
fn.call() //window
var obj = {
m: 0
}
fn.call(obj,1,2) //打印obj对象 1 2
fn.apply(obj,[1,2])
- bind
- 用于返回一个要调用的函数 然而并未执行
- 主要用于绑定一个特定的函数
function fn(a,b) {
console.log(a,b,this);
}
var obj = {
m: 0
}
console.log(fn.bind(obj));//打印fn函数
fn.bind(obj)(1,2) //打印obj对象 1 2
call apply bind方法重写
- call 和apply以及bind方法是定义在Function的原型对象上的
- 在原型上对call进行重写
- 在Function的原型中this指向调用的函数
- 调用obj.tempFn方法 传入参数
- 删除obj.tempFn方法
- 返回返回值
- 优化 先做判断 当传入的对象是一个null或者undefined的时候默认调用者为window
Function.prototype.call = function(obj,...args) {
if(obj === null || obj === undefined) {
obj = window
}
obj.tempFn = this
var result = obj.tempFn(...args)
delete obj.tempFn
return result
}
function fn(a,b) {
console.log(a,b,this);
return a + b
}
var obj = {
m: 0
}
console.log(fn.call(obj,1,2));
- bind
- 当调用这个函数的时候返回一个函数
- 由于要用到this 所以就使用箭头函数
- 然后通过return 将函数计算结果返回值返回出去
Function.prototype.bind = function(obj,...args) {
return (...args2) => {
return this.call(obj,...args,...args2)
}
}
function fn(a,b) {
console.log(a,b,this);
return a + b
}
var obj = {
m: 0
}
fn.bind(obj)(1,2)
函数节流和防抖封装
- 节流
function throttle(callback, delay) {
var pre = 0 //闭包形成可以缓存这个数据
return function(event) {
var current = Date.now()
//当前时间减去起始时间得到时间间隔大于传入的时间间隔时候才调用时间处理
if(current - pre > delay) {
//这里的this是事件源
callback.call(this,event)
//将起始时间改为当前时间 保持时间间隔
pre = current
}
}
}
function handleClick(event) {
console.log('按钮点击成功',event);
}
document.getElementById('throttle').onclick = throttle(handleClick,2000);
- 防抖
function debounce(callback,delay) {
return function(event) {
//判断callback中是否存在这个属性 这里使用hasOwnProperty表示不再往原型链上查找 优化性能
if(callback.hasOwnProperty('timeoutId')) {
//当连续点击的时候 时间间隔并没有超过预期值 就会一直进入这个判断 反复的将定时器清除掉
clearTimeout(callback.timeoutId)
}
//直接将定时器返回的id挂载到callback上面
callback.timeoutId = setTimeout(() => {
callback.call(this,event)
//当时间间隔超过一定实现 清除这个属性就不会进入定时器的清除
delete callback.timeoutId
},delay)
}
}
function handleClick(event) {
console.log('按钮点击成功',event);
}
document.getElementById('debounce').onclick = debounce(handleClick,2000);
自定义库
- npm init -y初始化生成package.json文件
- 然后自定义配置
{
"name": "mornlibrary",
"version": "1.0.0",
"mian": "./src/mian.js",
"description": "",
"repository": "https://github.com/mornFloyd/mornlibrary.git",
"author": "mornfloyd",
//宽泛的版权授权
"license": "MIT",
"scripts": {
//自定义打包命令
"build": "webpack"
},
"dependencies": {},
"devDependencies": {
"clean-webpack-plugin": "^4.0.0-alpha.0",
"webpack": "^5.36.1",
"webpack-cli": "^4.6.0"
}
}
- 下载局部webpack
npm install webpack -D
npm install webpack-cli
入口配置
- 创建webpack.config.js配置文件
var path = require('path')
module.exports = {
//选择生成是否压缩的模式当前这个是开发模式未压缩
mode: 'development',
//mode: 'production',
//入口是一个叫mian的文件
entry: './src/mian.js',
output: {
path: path.resolve(__dirname, 'dist'),
//文件名
filename: 'mornlibrary.js',
//实际代码使用的对象名
library: 'mornlibrary',
//umd支持多种引入方式包括esm amd common.js
libraryTarget: 'umd'
}
}
打包上传到npm
- 要将淘宝镜像修改为npm的官网
npm config set registry https://registry.npmjs.org/
//这个是设置淘宝镜像
npm config set registry https://registry.npm.taobao.org/
- 在npm添加自己的npm账号
- 输入完命令行之后依次输入邮箱密码
npm addUser
- 在本地库推送上去
npm publish