用这个标题可能不太好,不是包含所有的函数进阶的知识,只是我最近学的部分做一个总结。
函数声明
- 函数声明方式 function 关键字 (命名函数)
- 函数表达式 (匿名函数)
- new Function() 用的比较少,效率较低。
函数中this指向
一般指向我们的调用者,
改变函数中this的三种方法
call,apply,bind。
fun.call(thisArg, arg1, arg2, ...)
fun.apply(thisArg, [argsArray])
fun.bind(thisArg, arg1, arg2, ...)
thisArg:在 fun 函数运行时指定的 this 值
call后面的参数是一个一个分开的,apply的参数是一个数组,
bind是改变了this指向,但是并不会立即执行函数。
function fn(a, b) {
console.log(this);
console.log(a + b);
};
var f = fn.bind(o, 1, 2);
f();
bind在开发中用的比较多,也适用于定时器函数中this的改变。
严格模式
<script>
'use strict';
// 下面的js 代码就会按照严格模式执行代码
</script>
<script>
(function() {
'use strict';
})();
</script>
<!-- 为某个函数开启严格模式 -->
<script>
// 此时只是给fn函数开启严格模式
function fn() {
'use strict';
// 下面的代码按照严格模式执行
}
function fun() {
// 里面的还是按照普通模式执行
}
</script>
严格模式带来的变化
都知道JS语言有很多不好的地方,严格模式就是用来解决这个的部分问题的
<script>
'use strict';
// 1. 我们的变量名必须先声明再使用
// num = 10;
// console.log(num);
var num = 10;
console.log(num);
// 2.我们不能随意删除已经声明好的变量
// delete num;
// 3. 严格模式下全局作用域中函数中的 this 是 undefined。
// function fn() {
// console.log(this); // undefined。
// }
// fn();
// 4. 严格模式下,如果 构造函数不加new调用, this
//指向的是undefined 如果给他赋值则 会报错.
// function Star() {
// this.sex = '男';
// }
// // Star();
// var ldh = new Star();
// console.log(ldh.sex);
// 5. 定时器 this 还是指向 window
// setTimeout(function() {
// console.log(this);
// }, 2000);
// a = 1;
// a = 2;
// 6. 严格模式下函数里面的参数不允许有重名
// function fn(a, a) {
// console.log(a + a);
// };
// fn(1, 2);
function fn() {}
</script>
变量
在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,变量都必须先用var 命令声明,然后再使用。
严禁删除已经声明变量。例如,delete x; 语法是错误的。
this
以前在全局作用域函数中的 this 指向 window 对象。
严格模式下全局作用域中函数中的 this 是 undefined。
以前构造函数时不加 new也可以 调用,当普通函数,this 指向全局对象
严格模式下,如果 构造函数不加new调用, this 指向的是undefined 如果给他赋值则 会报错
new 实例化的构造函数指向创建的对象实例。
定时器 this 还是指向 window 。
事件、对象还是指向调用者。
函数
函数不能有重名的参数。
函数必须声明在顶层.新版本的 JavaScript 会引入“块级作用域”( ES6 中已引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数。
高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
<script>
function fn(callback){
callback&&callback();
}
fn(function(){alert('hi')}
</script>
<script>
function fn(){
return function() {}
}
fn();
</script>
闭包
这里简单提一下,不是很完整。
闭包(closure)指有权访问另一个函数作用域中变量的函数。 ----- JavaScript 高级程序设计
简单理解就是 ,一个作用域可以访问另外一个函数内部的局部变量。
<script>
function fn() {
var num = 10;
return function {
console.log(num); // 10
}
}
var f = fn();
f()
</script>
这就是一个简单的闭包。
闭包的作用就是:延伸作用域的范围。
浅拷贝和深拷贝
浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.
深拷贝拷贝多层, 每一级别的数据都会拷贝.
Object.assign(target, …sources) es6 新增方法可以浅拷贝
<body>//浅拷贝
<script>
// 浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.
// 深拷贝拷贝多层, 每一级别的数据都会拷贝.
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
}
};
var o = {};
// for (var k in obj) {
// // k 是属性名 obj[k] 属性值
// o[k] = obj[k];
// }
// console.log(o);
// o.msg.age = 20;
// console.log(obj);
console.log('--------------');
Object.assign(o, obj);//es6的语法糖
console.log(o);
o.msg.age = 20;
console.log(obj);
</script>
</body>
深拷贝
<body>
<script>
// 深拷贝拷贝多层, 每一级别的数据都会拷贝.
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
},
color: ['pink', 'red']
};
var o = {};
// 封装函数
function deepCopy(newobj, oldobj) {
for (var k in oldobj) {
// 判断我们的属性值属于那种数据类型
// 1. 获取属性值 oldobj[k]
var item = oldobj[k];
// 2. 判断这个值是否是数组
if (item instanceof Array) {
newobj[k] = [];
deepCopy(newobj[k], item)
} else if (item instanceof Object) {
// 3. 判断这个值是否是对象
newobj[k] = {};
deepCopy(newobj[k], item)
} else {
// 4. 属于简单数据类型
newobj[k] = item;
}
}
}
deepCopy(o, obj);
console.log(o);
var arr = [];
console.log(arr instanceof Object);
o.msg.age = 20;
console.log(obj);
</script>
</body>
深拷贝就是比浅拷贝多了判断数据类型,再去拷贝,要注意的是,array是object,但是object不是array,所以array的判断要写在object前面。
深拷贝
深拷贝开辟了新的内存空间,而浅拷贝只是把地址拷贝过去了。
都占用同一块地址,所以不管是新的对象还是旧的对象修改值时,全部都一起跟着修改了。
深拷贝这里用到了递归,递归的时候一定要设置好条件,不然容易造成“栈溢出”