1.浅拷贝
浅拷贝会创建一个新的对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝就是改引用类型的地址。
// 常见的浅拷贝
1.Object.assign({},obj) //对象浅拷贝
assign⽅法可以⽤于处理数组,不过会把数组视为对象,⽐如这⾥会把⽬标数组视为是属性为0、1、2的对象,所
以源数组的0、1属性的值覆盖了⽬标对象的值。
2.Array.concat({}) // 数组浅拷贝
3.Array.slice() // 数组浅拷贝
4.扩展运算符
2.深拷贝
深拷贝会创建一个新的对象,这个对象有着原始对象属性值的一份完整拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,就会将引用数据类型复制一份存到内存中,将其地址值赋值给新对象。
// 常见的深拷贝
1.JSON.parse(JSON.stringfy(obj)) // 对象深拷贝
2.递归拷贝
3.loadsh第三方库
Object.freeze()方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,并且返回当前对象。
这⾥是关于属性的四个基本类型
freeze作用:
1.函数声明
函数声明:function 函数名(){}
函数表达式:var 函数名 = function(){}
箭头函数: 函数名 = () => {}
2. 3种声明函数的区别
匿名函数
匿名函数:没有名字的函数,只能通过变量来调用。没有被显示进⾏赋值操作的函数。 使⽤场景——多作为⼀个参数传⼊另⼀个函数中
函数⾃执⾏,其实是匿名函数的⼀种应⽤
回调函数
回调函数:⼀个函数作为参数传⼊到另一个函数中,这个函数就是回调函数。使⽤场景——多作为⼀个参数传⼊另⼀个函数中
高阶函数
高阶函数:⼀个函数 接收另⼀个函数作为参数或返回另⼀个函数
特征
函数是第⼀等公⺠
所谓"第⼀等公⺠"(first class),是函数与其他数据类型⼀样,处于平等地位,可以赋值给其他变量,也可以作为
参数,传⼊另⼀个函数,或者作为别的函数的返回值
只⽤"表达式",不⽤"语句"
“表达式”(expression)是⼀个单纯的运算过程,总是有返回值;“语句”(statement)是执⾏某种操作,没有返
回值。函数式编程要求,只使⽤表达式,不使⽤语句。每⼀步都是单纯的运算,都有返回值
函数式编程期望⼀个函数有输⼊,也有输出
纯函数
即:只要是同样的参数传⼊,返回的结果⼀定是相等的
函数柯里化:
这里有一个函数(假设叫做addCurry),接收函数A作为参数,运⾏后返回⼀个新的函数。并且这个新的函数能够处理函数A的剩余参数
let addCurry = curry1((a, b) => a + b);
console.log(addCurry()(11)(1));
function curry1(fn) {
let judge = (...args) => {
if (args.length === fn.length) {
return fn.call(this, ...args);
}
//获取偏函数,返回包装器,重新组装参数并传⼊
return (...arg) => judge(...arg, ...args)
}
return judge;
}
length属性返回函数接收的参数个数,不包括rest参数。 这里不包括在参数定义位置赋了默认值的形参,同时也不包括剩余参数。
function fn1 () {}
function fn2 (name) {}
function fn3 (name, age) {}
console.log(fn1.length) // 0
console.log(fn2.length) // 1
console.log(fn3.length) // 2
可以看出,function有多少个形参,length就是多少。但是事实真是这样吗?继续往下看
2. 默认参数
如果有默认参数的话,函数的length会是多少呢?
function fn1 (name) {}
function fn2 (name = '林三⼼') {}
function fn3 (name, age = 22) {}
function fn4 (name, aaa, age = 22, gender) {}
function fn5(name = '林三⼼', age, gender, aaa) {}
console.log(fn1.length) // 1
console.log(fn2.length) // 0
console.log(fn3.length) // 1
console.log(fn4.length) // 2
console.log(fn5.length) // 0
上⾯可以看出,function的length,就是第⼀个具有默认值之前的参数个数
3. 剩余参数
在函数的形参中,还有剩余参数这个东⻄,那如果具有剩余参数,会是怎么算呢?
function fn1(name, ...args) {}
console.log(fn1.length) // 1
1.构造函数
在js中,通过一个new 关键字来创建对象的函数称为构造函数,也就是初始化一个实例对象,构造函数的命名一般都是首字母大写
构造函数创建对象的过程即本文上面提到的new关键字创建对象的过程
2.构造函数的返回值
构造函数中,一般不允许自己写返回值,当在函数中返回一个基本数据类型时,返回值无效,并不会返回给外面接收变量,但当返回一个引用数据类型时,这个引用数据类型将会覆盖本次创建的对象,从而会导致构造函数没有效果,因此不建议在构造函数中返回值
在js代码运行时,会产生三种执行上下文,分别是全局上下文,函数上下文和eval上下文,每种执行上下文都有三个重要属性:变量对象,作用域链,this
1.全局上下文
全局上下文在js代码执行之前就已经存在了,当js代码开始执行时,会首先进入全局上下文,全局上下文中包含有全局对象和this,在全局上下文中,作用域为全局作用于,this指向全局对象(在浏览器端指向window)
2.函数上下文
当函数被调用时,会创建函数上下文,函数上下文包含有变量对象,作用域链,this,函数上下文中的this指向调用函数的对象,如果没有对象调用函数,那么this指向全局对象(在浏览器端指向window)
3.eval上下文
eval函数执行时,会创建eval上下文,eval上下文包含有变量对象,作用域链,this,eval上下文中的this指向全局对象(在浏览器端指向window)
简单来说,闭包就是在一个函数中返回另一个函数,而返回的函数使用到了原函数中定义的变量,这样导致原函数执行完之后会残留一个变量被返回函数一直引用,无法被垃圾回收机制回收,同时在原函数外部根本除了返回函数外无法被其他方式访问到,因此就形成了闭包
闭包 = 函数 + 函数能够访问的⾃由变量。
本质上,闭包就是一个定义在上级作用域中的变量,在下级作用域中引用到了这个变量,本应在上级作用域结束时释放的变量因为间接引用没有被释放,因此就形成了闭包
作用
运用
function debounce(fn, delay = 300) {
let timer; //闭包引⽤外界变量
return function () {
consr args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
function OutPutNum(cnt) {
(function () {
for (let i = 0; i < cnt; i++) {
alert(i);
}
})();
alert(i);
}
this指向在函数被调⽤时确定,即执⾏上下⽂被创建时确定。函数执⾏过程中,⼀旦this指向被确定就不可更改。
在⼀个函数上下⽂中,this由调⽤者提供,由调⽤函数的⽅式来决定。如果调⽤者函数,被某⼀个对象所拥有,那
么该函数在调⽤时,内部的this指向该对象。如果函数独⽴调⽤,那么该函数内部的this,则指向undefined。但
是在⾮严格模式中,当this指向undefined时,它会被⾃动指向全局对象
1.严格模式
全局:
在严格模式中,全局上下⽂中的this值是undefined,⽽不是指向全局对象。
函数:在严格模式中,⾮箭头函数内部的this值是undefined,⽽不是指向全局对象或undefined。
对象方法:在严格模式中,对象⽅法中的this指向对象。
2.非严格模式
全局:在非严格模式中,全局上下⽂中的this值是全局对象。
函数:在非严格模式中,⾮箭头函数内部的this值是全局对象。
对象方法:在非严格模式中,对象⽅法中的this指向调用该方法的对象。
3.箭头函数
箭头函数中没有自己的this,沿用了上层作用域的this
作为⽅法的箭头函数 this 指向当前被定义变量的上下⽂环境。
箭头函数的this 为定义时所在的 this,不绑定this (因为箭头函数没有Constructor这个内部槽),会捕获其所在上下
⽂的 this 作为⾃⼰的 this。(箭头函数的this就是它在外⾯的第⼀个不是箭头函数的函数的this)**
4.修改this指向
bind():改变this指向,返回一个新函数原函数的副本,并绑定this指向bind的第一个参数,接受的第一个参数是需要绑定的this,其余参数是原函数的参数
call():改变this指向,立即执行原函数,并绑定this指向call的第一个参数,接受的第一个参数是需要绑定的this,其余参数是原函数的参数
apply():改变this指向,立即执行原函数,并绑定this指向apply的第一个参数,接受的第一个参数是需要绑定的this,接受的第二个参数是原函数的参数
手写以上三个函数
Function.prototype.myCall = function (obj,...args) {
obj.fn = this
const res = obj.fn(...args)
delete obj.fn
return res
}
Function.prototype.myApply = function (obj,args) {
obj.fn = this
const res = obj.fn(...args)
delete obj.fn
return res
}
Function.prototype.myBind = function (obj,...args) {
const fn = this
return function (...args1) {
const res = fn.apply(obj,args.concat(args1))
return res
}
}