目录
动态改变函数体内部this的指向(call, apply) 对象继承
arguments对象+类数组转数组+apply() 的例子
高阶函数
高阶函数是对其他函数进行操作的函数,可以将它们作为参数或返回它们。简单来说,高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回。
例如,Array.prototype.map,Array.prototype.filter和Array.prototype.reduce是语言中内置的一些高阶函数。
var numbers = [1,2,3,4,5]
var doubled = numbers.map(function(n) {
return n * 2
})
console.log(doubled) //=> [2,4,6,8,10]
var numbers = [1,2,3,4,5]
var total = numbers.reduce (function (sum, n) {
return sum + n
});
console.log (total) //=> 15
【当这个类里面是2种类型时,例子为number和boolean】
forEach() 和 map() 的应用场景
forEach()
may be preferable when you’re not trying to change the data in your array, but instead want to just do something with it — like saving it to a database or logging it outAnd
map()
might be preferable when changing or altering data. Not only is it faster but it returns a new Array. This means we can do cool things like chaining on other methods (map()
,filter()
,reduce()
, etc.)
let arr = [1, 2, 3, 4, 5];
let arr2 = arr.map(num => num * 2).filter(num => num > 5);
// arr2 = [6, 8, 10]
- 能用
forEach()
做到的,map()
同样可以,反过来也是如此。 forEach()
允许callback
更改原始数组的元素。map()则
返回新的数组。
let arr = [1, 2, 3, 4, 5];
let doubled = arr.map(num => {
return num * 2;
}); // arr = [2, 4, 6, 8, 10]
arr.forEach((num, index) => {
return (arr[index] = num * 2);
}); // arr = [2, 4, 6, 8, 10]
Array.prototype.map()
map()
方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
可实现浅拷贝
> function rr(a, ...test) {console.log(a,"___",test)}
> rr(1,2,3,4,5)
// 1 "___" (4) [2, 3, 4, 5]
动态改变函数体内部this的指向(call, apply) 对象继承
语法:Function.call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。即 thisObj 继承了 Function 的属性和方法。
number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法:
var numbers = [5, 458 , 120 , -215 ];
var applyMaxInNumbers = Math.max.apply(Math, numbers); //458
var applyMaxInNumbers = Math.max.apply(null, numbers); //458 指定null会自动替换为指向全局对象
var applyMinInNumbers = Math.min.apply(Math,numbers); //-215
借用构造函数实现继承:
function Person(name,age) {
this.name=name;
this.age=age;
}
var Student=function(name,age,gender) {
Person.call(this,name,age);//this继承了person的属性和方法
this.gender=gender;
}
var student=new Student("陈安东", 20, "男");
alert("姓名:"+student.name+"\n"+"年龄:"+student.age+"\n"+"性别:"+student.gender);
// 姓名:陈安东 年龄:20 性别:男
声明式函数与赋值式函数(或叫:匿名函数)
JS的函数定义分为3种,声明式函数:function test() {}; 匿名函数:var test = function() {}。前面2种比较常用,最后一种是构造函数定义:var fun3 = new Function("a", "b", "return a * b");
JS的解析过程分为2个阶段,预编译期和执行期。预编译期就是:将函数声明和变量声明提升到当前作用域的顶端,需要注意的是此时处理的函数只是声明式函数,变量也只是进行了声明并未初始化和赋值。执行期就是从上到下编译代码块。
函数和变量相比,会被优先提升。这意味着函数会被提升到更靠前的位置。
JavaScript中的代码块是指由<script>标签分割的代码段。
Fn() // 打印:test2,因为同名函数后面会覆盖前面
function F() {
console.log("test1")
}
function F() {
console.log("test2")
}
Fn(); // 打印:"test 1",因为声明式的Fn()函数在预编译阶段就被处理了,所以即使Fn()调用在声明式函数之前也能执行。
function Fn() {
console.log("test 1");
}
var Fn = function() {
console.log("test 2");
} // 所以函数表达式中的Fn也不会是个函数,Fn在预编译期被放入了词法环境中,
// 被赋值为undefined,等到执行期才会变为一个function
只有声明var a这个操作会被提升,而= 233这个赋值操作并不会被提升。但是为什么a是undefined呢?因为在预编译期JS会找到var 声明的变量添加到词法环境中,并初始化一个值undefined。等后期执行的时候再把233赋值给a。
console.log(a); // 打印"undefined",因为变量在预编译期仅声明,并未初始化及赋值
var a = 233;
var x = 1; // 声明 + 初始化 x
console.log(x + " " + y); // '1 undefined'
var y = 2; // 声明 + 初始化 y
最佳实践:无论是函数还是变量,都先声明再使用。
function testOrder(arg) {
console.log(arg); // arg是形参,不会被重新定义
console.log(a); // 因为函数声明比变量声明优先级高,所以这里a是函数
var arg = 'hello'; // var arg;变量声明被忽略, arg = 'hello'被执行
var a = 10; // var a;被忽视; a = 10被执行,a变成number
function a() {
console.log('fun');
} // 被提升到作用域顶部
console.log(a); // 输出10
console.log(arg); // 输出hello
};
testOrder('hi');
/* 输出:
hi
function a() {
console.log('fun');
}
10
hello
*/
参考:https://blog.csdn.net/chen_zw/article/details/18502937
https://juejin.im/post/5d36b06af265da1ba84ad143
箭头函数
this指向
引入箭头函数有两个方面的作用:更简短的函数并且不绑定this
。
- 在箭头函数出现之前,每一个新函数根据它是被如何调用(运行期)的来定义这个函数的this值(在全局函数中,this指向windows对象;当函数被作为某个对象的方法调用时,this就等于那个对象)
- 箭头函数不会创建自己的
this,它只会从自己的作用域链的上一层继承this,在函数定义时就继承了定义函数的对象
。
基础语法
- (参数1, 参数2, …, 参数N) => { return 表达式; } // 相当于:(参数1, 参数2, …, 参数N) => { 函数声明 }
- 当只有一个参数时,圆括号是可选的。没有参数的函数应该写成一对圆括号。
- 当箭头函数的函数体只有一个 `return` 语句时,可以省略 `return` 关键字和方法体的花括号。
- 加括号的函数体返回对象字面表达式: 参数=> ({foo: bar})
- 在一个简写体中,只需要一个表达式,并附加一个隐式的返回值。在块体中,必须使用明确的
return
语句。
var func = x => x * x;
// 简写函数 省略return
var func = (x, y) => { return x + y; };
//常规编写 明确的返回值
undefined和null
undefined == null; // true
if (!undefined) {console.log(233)} // 打印:233
if (!null) {console.log(233)} // 打印:233
null的作用:给一个变量赋值,基本数据类型可以直接赋值,那么我要赋值一个对象,或者清空一个对象的赋值,该怎么办呢?
那就发一个空的对象吧,即:null
。当然变量被赋值为 null
后,还有另一层作用,那就是方便JS引擎对这个变量进行垃圾回收。
undefined
,用于变量声明时;-
null
,用于变量赋值时;
全局作用域、函数作用域、块级作用域
es6之前没有块级作用域。
如果一个变量在函数体内声明,则该变量的作用域为整个函数体。
由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行。
不在任何函数内定义的变量就具有全局作用域。
ES6标准引入了新的关键字const
来定义常量,const
与let
都具有块级作用域。
杂
arguments对象
arguments
对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments
对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。
arguments
对象不是一个 Array
。它类似于Array
,但除了length属性和索引元素之外没有任何Array
属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的Array
:
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
// ES2015
const args = Array.from(arguments);
const args = [...arguments];
arguments对象+类数组转数组+apply() 的例子
需求:定义一个 log 方法,让它可以代理 console.log 方法,并给每一个 log 消息添加一个"(doView)"的前辍
function log(){
var argsData = Array.prototype.slice.call(arguments);
argsData.unshift('(doView)');
console.log.apply(window, args);
};
其它
【加括号的函数体】
-------------
filter()
方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
reduce()
var initialValue = 0;
var sum = [{x: 1}, {x:2}, {x:3}].reduce(
(accumulator, currentValue) => accumulator + currentValue.x
,initialValue
);
console.log(sum) // logs 6
export const enum TemplateRegion {
Head = 'Head',
Neck = 'Neck',
Thorax = 'Thorax',
}
export interface RegionImageSource {
id: TemplateRegion;
text: string;
src: string
}
export const IMAGE_SOURCES: RegionImageSource[] = [
{id: TemplateRegion.Head, text: 'hi', src: 'hei'},
{id: TemplateRegion.Neck, text: 'hi', src: 'hei'},
{id: TemplateRegion.Thorax, text: 'hi', src: 'hei'}
]
interface Activate<T extends { id: any }> { // 不要直接extends RegionImageSource
data: T;
active: boolean;
}
export const regions: Activate<RegionImageSource>[] = IMAGE_SOURCES.map((s) => ({
data: s,
active: false,
}));
在控制台打印,结果如下:
console.log(regions)
[{data: {id: TemplateRegion.Head, text: 'hi', src: 'hei'},
active: false
},
{data: {id: TemplateRegion.Neck, text: 'hi', src: 'hei'},
active: false
},
{data: {id: TemplateRegion.Thorax, text: 'hi', src: 'hei'},
active: false
}]
改变 this 的指向:
- 使用 ES6 的箭头函数
- 在函数内部使用
_this = this
- 使用
apply
、call
、bind
- new 实例化一个对象