JavaScript中,函数被执行时, 相关的参数和信息, 会封装到一个类似数组(array-like)的对象中, 通过 arguments
可以引用到。
arguments
只能在函数之中使用, 属于约定好的符号, 不是关键字,而 this
则是关键字。
类数组(array-like)对象, 本质是一个普通对象, 但具有数组的某些特征; 比如: length
, 以及可以通过下标(index)来访问某些值;
类数组对象, 可能不具备数组的某些方法。所以会看到类似这样的代码: Array.prototype.slice.call(arguments, 0, 1)
言归正传, 请看示例:
function demo1(){
console.dir(arguments);
}
//
demo1("6", 66, 666);
在浏览器控制台执行, 结果类似这样:
Arguments(3)
0: "6"
1: 66
2: 666
> callee: ƒ demo1()
length: 3
> Symbol(Symbol.iterator): ƒ values()
> __proto__: Object
可以看到, 其中有一个属性叫做 callee
, 本质上是一个函数, 展开之后内容为:
callee: ƒ demo1()
arguments: null
caller: null
length: 0
name: "demo1"
> prototype: {constructor: ƒ}
> __proto__: ƒ ()
[[FunctionLocation]]: VM162:1
> [[Scopes]]: Scopes[1]
arguments.callee
就表示当前函数,
请看代码1:
function demoFuncion(){
return arguments.callee.name;
}
var func1 = function(){
return arguments.callee.name;
}
//
var func2 = demoFuncion;
var func3 = func1;
//
console.log("demoFuncion() return: " + demoFuncion());
console.log("func2() return: " + func2());
console.log("func3() return: " + func3());
执行结果为:
demoFuncion() return: demoFuncion
func2() return: demoFuncion
func3() return: func1
可以看到, 匿名函数第一次赋值给 func1, 所以 func3 引用的函数的名字实际上是 func1。
一般来说,创建 Error 对象时会自动收集堆栈信息。
// 获取JS中的调用栈
function checkCallStack(){
var stack = "";
try{
throw new Error("test-for-call-stack")
}catch(e){
stack = e.stack;
}
//
var stackArray = stack.split("\n");
//
// var curFuncName = arguments.callee.name;
// 去掉前2个
return stackArray.slice(2);
};
function testSS(){
return checkCallStack();
};
stack = testSS();
执行后,输出结果如下:
"Error: hahaha
at checkCallStack (<anonymous>:1:37)
at testSS (<anonymous>:2:26)
at <anonymous>:3:1"
一般来说有3种方式, 至于 eval和JSON反序列化之类的则不讨论。
在控制台执行以下代码:
// 创建空对象
c = {};
d = new Object();
e = Object.create(null);
//
console.log("c:", c);
console.log("d:", d);
console.log("e:", e);
展开之后
c:
{}
__proto__: Object
d:
{}
__proto__: Object
e:
{}
No properties
可以看到, e 没有任何属性, 连 __proto__
都没有。
j = [...new Set([1, 2, 3, 3])]; // ... 剩余参数
// 结果是 [1, 2, 3]
其中,使用了 剩余参数 和 Set 类。
person = { name: 'David Walsh', gender: 'Male' };
tools = { computer: 'Mac', editor: 'Atom' };
attributes = { handsomeness: 'Extreme', hair: 'Brown', eyes: 'Blue' };
summary = {...person, ...tools, ...attributes}; // ... 展开语法
结果是:
{
computer: "Mac"
editor: "Atom"
eyes: "Blue"
gender: "Male"
hair: "Brown"
handsomeness: "Extreme"
name: "David Walsh"
}
其中,我们使用了 展开语法;
在JS中, 三个点号(
...
) 被称为: 展开语法(spread syntax), 剩余参数(rest parameters), 剩余表达式(rest expression)等
// 假设查询参数是: "?name=tiemao&action=list"
//
var paramStr= window.location.search;
paramStr = "?name=tiemao&action=list"; // 临时赋值-演示
var urlParams = new URLSearchParams(paramStr);
console.log(urlParams.has('name')); // true
console.log(urlParams.get('action')); // "list"
console.log(urlParams.getAll('action')); // ["list"]
console.log(urlParams.toString()); // "name=tiemao&action=list"
// 追加参数;可同名
urlParams.append('active', '1')
console.log(urlParams.toString()); // "name=tiemao&action=list&active=1"
urlParams.append('active', '2')
console.log(urlParams.toString()); // "name=tiemao&action=list&active=1&active=2"
console.log(urlParams.getAll('active')); // ["1", "2"]
// set 是覆盖设置
urlParams.set("_ts", (new Date()).getTime());
再来看一个自动刷新的示例:
// 自动刷新示例; 将当前页面地址用内置iframe来自动刷新
function refreshNext(){
// 时间戳
var ts = ""+(new Date()).getTime();
// 增加参数
var newUrl = replaceParam(location.href, "_ts", ts);
// iframe
var iframe1 = getIframe("iframe1");
iframe1.src = newUrl;
// 设置下次自动刷新
window.setTimeout(refreshNext, 5000);
// 替换或新增参数
function replaceParam(href, paramName, paramValue){
var url = new URL(href); // window.location 也是一个 URL对象
var urlParams = url.searchParams;
// set 是覆盖设置
urlParams.set(paramName, paramValue);
//
var newUrl = url.origin + url.pathname + "?" + urlParams.toString();
return newUrl;
};
// 获取iframe
function getIframe(id){
var iframe1 = document.getElementById(id);
if(!iframe1){
iframe1 = document.createElement("iframe");
iframe1.setAttribute("id", id);
iframe1.setAttribute("width", "650px");
document.body.appendChild(iframe1);
}
return iframe1;
};
};
refreshNext();
可以看到, URLSearchParams 还是很方便的。
2019年4月24日