函数的length属性
函数有length属性
function test(){
}
// test(1);
console.log(test.length);//0
function test(a, b) {
}
test(1);
console.log(test.length);//2
function test(a,b,c=1){
}
test(1);
console.log(test.length);//2
function test(c=1,a,b){
}
test(1);
console.log(test.length);//0
还是2,因为c=1赋予参数默认值的时候,它自己这位不算在length里面,并且后面无论赋不赋参数,都不算到length参数里面
function test(a,b,c=1,d){
}
test(1);
console.log(test.length);//2
形参默认值与argument
argument与形参是映射关系
function test(a, b, d, e, f) {
console.log(arguments);//[Arguments] { '0': 1 }
}
test(1);
console.log(test.length);//5
function test(a, b, d, e, f) {
arguments[1]=7;
console.log(arguments);//[Arguments] { '0': 1, '1': 7, '2': 3, '3': 4, '4': 5, '5': 6 }
console.log(b);//7
}
test(1,2,3,4,5,6);
console.log(test.length);//5
arguments可以更改实参,但对形参没有任何影响
function test(a, b, d=1, e, f) {
arguments[1]=7;
console.log(arguments);//[Arguments] { '0': 1, '1': 7, '2': 3, '3': 4, '4': 5, '5': 6 }
console.log(b);//2
}
test(1,2,3,4,5,6);//1,2,3,4,5,6是实参
console.log(test.length);//2
/*a,b,d,e,f是形参,把实参赋值给形参,实参就没有什么用处了,AO中一直存在的是形参,不是实参,只不过形参的值是实参的值,
* argument也不是实参,只不过与实参、形参有映射关系,但这个关系会被默认值影响,如果任何参数有默认值,即使是最后一位,
*有默认值,所有形参都不再与argument有映射关系*/
function test(a, b, d=1, e, f) {
arguments[1]=7;
console.log(arguments);//[Arguments] { '0': 1, '1': 7, '2': 3, '3': 4, '4': 5, '5': 6 }
console.log(b);//2
}
test(1,2,3,4,5,6);
/*1,2,3,4,5,6是实参,函数运行存入的值是实参*/
console.log(test.length);//2
function foo({x,y=5}){
console.log(x,y);
}
foo({});//undefined 5
foo({x:1});//1 5
foo({x:1,y:2});//1 2
foo({});//undefined 5
foo()//TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.
/*这样如果什么都不传的情况下,就会报错,代码终止运行,体验不好*/
/*这样写,即使foo()什么都不传也不会报错了,做了兼容性处理*/
function foo({x, y = 5} = {}) {
console.log(x, y);
}
foo({});//undefined 5
foo({x: 1});//1 5
foo({x: 1, y: 2});//1 2
foo({});//undefined 5
foo()//undefined 5
这里面用到了兼容性
// var x=x;
/*先不走let x;先走x=x*/
let x=x;
console.log(x);
/*ReferenceError: Cannot access 'x' before initialization*/
解析
不是如下这样运行的,结果都不一样
let x;
x=x;
console.log(x);//undefined
是这样运行的,结果一样
x=x;//ReferenceError: Cannot access 'x' before initialization
let x;
console.log(x);//undefined
function foo(x=x){
//ReferenceError: Cannot access 'x' before initialization
}
foo()
调试
var x = 1;
/*调用栈,函数调用栈,赋默认值*/
/*
这个块级作用域里面x的值从里面取 x=>1=>2
function foo({(let)x=1,(let)y = function () {
x = 2;
console.log(x);}})
参数赋予默认值,是一个运算,需要运行,产生作用域,产生运行作用域,
如上图,之后把得出来的值传给函数AO,函数需要AO中的形参来运行,之后那个块级作用域销毁
即使没有赋予默认值,只要传参了,也可以理解成{x=实参(包括undefined),y=实参},
之后把得出来的x,y传给函数的AO,之后{x,y}的块级作用域销毁
也可以理解成,不销毁继续调用,函数调用y()行成了闭包,不销毁了
*/
function foo(x = 1, y = function () {
var x = 2;
console.log(x);//2
}
) {
x = 3;
y();
console.log(x);
}
foo();//2 3
console.log(x);//1
火狐浏览器
调试器,在foo上打断点
刷新浏览器
点击步进
范围就是scope
var x = 1;
/*调用栈,函数调用栈,赋默认值*/
/*
这个块级作用域里面x的值从里面取 x=>1=>2
function foo({(let)x=1,(let)y = function () {
x = 2;
console.log(x);}})
参数赋予默认值,是一个运算,需要运行,产生作用域,产生运行作用域,
如上图,之后把得出来的值传给函数AO,函数需要AO中的形参来运行,之后那个块级作用域销毁
即使没有赋予默认值,只要传参了,也可以理解成{x=实参(包括undefined),y=实参},
之后把得出来的x,y传给函数的AO,之后{x,y}的块级作用域销毁
也可以理解成,不销毁继续调用,函数调用y()行成了闭包,不销毁了
*/
function foo(x = 1, y = function () {
x = 2;
console.log(x);//2
}
) {
x = 3;
y();
/* y = function () {
x = 2;
console.log(x);//2
}
其实就是在这里运行了这段代码,改变了x的值,x从哪里找,从这里找,从AO中找
*/
console.log(x);//2
}
foo();//2 2
console.log(x);//1
类似于
{
let x=2;
{
x=3;
console.log(x);
}
console.log(x);
}
this指向
见之前笔记
function foo() {
console.log(this.a);
// console.log(this);
}
var obj = {
a: 2,
foo: foo
}
obj.foo();//2
window.obj.foo();//2
/*因为bar接收obj.foo对象,赋予地址,没有运行,bar在window下,其实就是window调用*/
var bar = obj.foo;
bar();//undefined
window.bar();//undefined
let bar1 = obj.foo;
bar1();//undefined
/*bar1的this也是window*/
箭头函数
参数是一个时可以省略,可以简写,如果函数里面只有一个return语句时,也可以简写
返回值只能有一个,因为走完第一个return函数就停止运行了,但可以返回对象,或者数组,里面有多个变量、多个函数,也可以返回函数
只有一个参数的情况
// ()=>{}
var f = a => a;
var f = (a) => a;
var f = (a) => {
return a;
};
var f = function (a) {
return a;
}
2.参数不是一个的情况
0个参数必须写()括号
var f = () => 5;
function f(){
return 5;
}
/*Uncaught SyntaxError: Identifier 'f' has already been declared*/
// let f=(a,b)=>a+b;
var f=(a,b)=>a+b;
function f(a,b){
return a+b;
}
说箭头函数的时候,一般说的是箭头函数表达式
/*箭头函数*/
()=>{
}
/*想给其赋值,这样写不合法*/
test()=>{
}
这样写也没用
var test = (() => {
})
只有给箭头函数赋值才能够保存箭头函数,之后才可以调用箭头函数
var test = () => {
}
多重语句必须写{}大括号,没有返回值,默认返回值是undefined
let f = (a,b) => {
var a=3;
var b=4;
console.log(a+b);//7
}
console.log(f())//undefined
/*当语句只有一条,返回但是语句的执行结果,当只有一条return语句时,就可以省略{}大括号与return*/
var f = (a,b) => a+b;
/* var f = (a,b) => {
return a+b;
};*/
console.log(f())//undefined
//通过解构赋值来结合
const full = ({first, last} = {}) => first + '' + last;/* +‘’转成字符串*/
console.log(full({first: 3, last: 5}));//35
/*从小到大排序,通过箭头函数可以简化代码,箭头函数具体应用,有些方法需要传入一个带有返回值的方法,
* 这个时候写function a(){return。。。}就太繁琐了,直接箭头函数简写*/
var arr = [12312, 31, 23, 1, 4, 124, 32, 5, 3465, 3];
var arr1=arr.sort((a,b)=>a-b);
console.log(arr1);
箭头函数问题
箭头函数本质上不是用function关键字定义出来的,不是new Function出来的,而是叫一个胖箭头的操作符来定义的,本质上与函数是两个东西,经常叫它箭头函数,其实它不是函数
有很多区别
var sum = (a, b) => {
console.log(arguments);
return a + b;
}
sum(1, 2);//Uncaught ReferenceError: arguments is not defined报错
/*箭头函数没有arguments*/
…运算符
展开
… spread/rest 运算符;(用来展开或是收集的)
var sum = (...args) => {
console.log(args);/*Array [ 1, 2 ]返回真正的数组,不是类数组*/
console.log(args[0]+args[1]);//3
}
sum(1, 2);
收集
function foo(x,y,z){
console.log(x,y,z);
}
foo(...[1,2,3]);//1,2,3
foo(...[1,2,3,4,5]);//1,2,3
本质上,或者说用es5的方式去模拟它,怎么模拟?可以用apply实现
function foo(x, y, z) {
console.log(this);
console.log(x, y, z);
}
// foo(...[1, 2, 3]);//1,2,3
// foo(...[1, 2, 3, 4, 5]);//1,2,3
foo.apply(undefined, [1, 2, 3, 4, 5]);//1,2,3
foo.apply(null, [1, 2, 3, 4, 5]);//1,2,3
打印window说明执行失败了,没有改变this的指向,只提取数组中的值
let a=[2,3,4];
let b=[1,...a,5];
console.log(b);//[1, 2, 3, 4, 5]
es5写法
let a=[2,3,4];
// let b=[1,...a,5];
console.log([1].concat(a,[5]));//[1, 2, 3, 4, 5]
收集,收集的是剩余的所有参数 ,只能放在最后一位
let fn=(a,b,...c)=>{
console.log(a,b,c);
}
fn(1,2,3,4,5,6,7);//1 2 [ 3, 4, 5, 6, 7 ]
放在前面会报错
rest收集,必须是最后一个参数
// SyntaxError: Rest parameter must be last formal parameter
let fn=(...c,a,b)=>{
console.log(a,b,c);
}
fn(1,2,3,4,5,6,7);
function sortNum(){
return Array.prototype.slice.call(arguments).sort(function(a,b){
return a-b;
})
}
console.log(sortNum(12,431,21,12,1,4,135,2,35,25));
const sortNum=(...args)=>args.sort((a,b)=>a-b);
console.log(sortNum(12,431,21,12,1,4,135,2,35,25));
es6,箭头函数写法,因为箭头函数没有argument,所以只能用…收集运算符号
console.log((function (a){}).length);//1
console.log((function (...a){}).length);//0 不能找到里面的length
console.log((function (b,c,d=0,...a){}).length);//2
内容不少了,消化一下