函数
- 在传递函数参数时,ES5中想要创建带有参数默认值的函数往往会这样写,这样写能满足大部分的需要,但是当参数,比如age为0时,不会返回0而会返回20,因为0是一个假值:
function makeRequest(name, age, sex){
// 当||左侧的值为假时,会返回右侧的值
name = name || "emoji";
age = age || 20;
callback = callback || function(){};
}
为了更好兼容上面所述的异常情况,我们会使用typeof来检测参数的类型,这样写更安全了,但是代码就显的啰嗦繁杂了:
function makeRequest(name, age, sex){
// 当||左侧的值为假时,会返回右侧的值
name = (typeof name !== "undefined") || "emoji";
age = (typeof age!== "undefined") || 20;
callback = (typeof callback!== "undefined") || function(){};
}
ES6中支持给参数直接设置默认值,具体也可以看【解构】那篇文章:
// es6里会认为参数是必须的,设置了默认值可以规避不传值的报错,null会被认为是一个有效值
function makeRequest(name, age = 20, sex = "male"){
// 当||左侧的值为假时,会返回右侧的值
name = (typeof name !== "undefined") || "emoji";
age = (typeof age!== "undefined") || 20;
callback = (typeof callback!== "undefined") || function(){};
}
对arguments参数的影响:
在ES5的非严格模式下,arguments会跟着参数的重复赋值而更改,而在严格模式下,arguments会记录原始调用的值,不会随着具名参数的改变值而改变,这个和ES6是一样的:
// es5非严格模式下
function mixArgs(first, second){
console.log(first, second); // k i
console.log(first === arguments[0]); // true
console.log(second === arguments[1]); // true
first = "e";
second = "m";
console.log(first, second); // e m
console.log(first === arguments[0]); // true
console.log(second === arguments[1]); // true
}
mixArgs("k","i");
// es6无论是否严格模式下
function mixArgs(first, second = "b"){
console.log(first, second); //k i
console.log(first === arguments[0]); //true
console.log(second === arguments[1]); //true
first = "e";
second = "m";
console.log(first, second); // e m
console.log(first === arguments[0]); // false arguments[0] = k
console.log(second === arguments[1]); // false arguments[0] = i
}
mixArgs("k","i");
扩展运算符:
// 会将该数组分割为独立参数,并把他们传递进去
let values = [1,2,3,4,5];
console.log(Math.max(...values)); // 5
箭头函数:
需要从函数体内返回一个对象字面量,需要将该字面量包裹在圆括号内,表示括号内是一个字面量不是一个函数体
var getTempItem = id => ({ id: id, name: "Temp" });
//等于
var getTempItem = function(id){
return {
id: id,
name: "Temp"
};
}
// 箭头函数中没有自己的this,this都是最外层环境中的this,使用apply、call、bind都没有用
function foo() {
return () => {
return () => {
return () => {
return () =>{
console.log("id:", this.id);
}
}
}
}
}
let f = foo.call({id:1})
let t1 = f.call({id:2})()(); // id:1
let t2 = f().call({id:3})(); // id:1
let t3 = f()().call({id:4}); // id:1
- 不适用箭头函数的场景
(1)const cat = {
live:9,
jumps:()=>{
this.live++ // this在外层环境指向window
}
}
(2)button.addEventListener("click", () => {
this.classList... // this指向window
})
部署管道机制:前一个函数的输出是后一个函数的输入
const emoji = (...func) => val => func.reduce((a,b) => b(a), val);
emoji = function(...func) {
return function(val) {
return func.reduce(function(a,b){
return b(a)
}, val)
}
}
const plus = a => a+1;
const mult = a => a*1;
mult(plus(5));
立即执行函数
我们知道这两种写法可以说是一样的:
// 写法1
(function(){/*函数体*/})()
// 写法2
(function(/*函数体*/){}())
在使用es6时,立即执行函数的参数调用不能包含在箭头函数定义括号内,即只能用写法1
尾调用:
尾调用指调用函数的语句是另一个函数的最后语句
function doSomething() {
// 尾调用
return doSomethingElse();
}
尾调用优化
function f(x) {
return g(x);
}
// 三种情况都不属于尾调用
// 情况一
fuction f(x) {
let y = g(x);
return y;
}
// 情况二
function f(x) {
return g(x)+1;
}
// 情况三
function f(x) {
g(x)+1;
}
函数调用时会在内存中形成一个调用记录,称为“调用帧”,保存调用位置和内部变量信息。比如A函数中调用了B函数,那在A的调用帧上方会形成一个B的调用帧。等B运行结束,将结果返回A,B的调用帧才会消失。
尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置和内部变量信息不会再用到了。只要直接用内层函数的调用帧取代外层函数的调用帧。
function f() {
let m = 1;
let n = 2;
return g(m+n);
}
f();
自动优化为:
function f () {
return g(3);
}
最终为
g(3)
如果改为中间调用
function f() {
let m = 1;
let n = 2;
let fn = g(m+n);
return fn;
}
调用g(m+n)时就会保存m、n变量等信息
function addOne(a) {
let one = 1;
function inner(b) {
return b + one;
}
return inner(a);
}
上面的函数不会进行尾调用优化,因为内层函数inner用到了外层函数addOne内部变量one;
字符串与正则:
字符查找:
var msg = "hello world!";
console.log(msg.startsWith("Hello")); // true
console.log(msg.endsWith("!")); // true
console.log(msg.includes("o")); // true
console.log(msg.startsWith("o")); // false
console.log(msg.startsWith("world!")); // true
console.log(msg.startsWith("x")); // false
// startsWith 和 includes 会从索引位置开始找
// endsWith 字符串长度-参数得到的值 开始查找 12 - 8 = 4
console.log(msg.startsWith("o", 4)); // true
console.log(msg.endsWith("o", 8)); // true
console.log(msg.includes("o", 8)); // false
重复指定次数的新字符串(可以用来缩进和补全):
console.log("x".repeat(3)); // "xxx"