ES6(三) 函数 3
1.函数构造器 ( new Function(……) )
2.扩展运算符(…)
3.ES6 的名称属性(函数声明式,匿名函数式, 名称特殊情况)
4.明确函数的双重用途
函数构造器
Function 构造器允许你动态创建一个新函数
Function构造器(JS不常用)与 函数声明形式
普通Function构造器
var add = new Function("first", "second", "return first + second");
console.log(add(1, 1)); // 2
使用默认值的Function构造器
var add = new Function("first", "second = first", "return first + second");
console.log(add(1, 1)); // 2
console.log(add(1)); // 2
使用剩余变量的Function构造器
var pickFirst = new Function("...args", "return args[0]");
console.log(pickFirst(1, 2)); // 1
扩展运算符
与剩余参数关联最密切
剩余参数允许你把多个独立的参数合并到一个数组中(获取传入的实参,放到一个数组中);
扩展运算符则允许将一个数组分割,并将各个项作为分离的参数传给函数。
剩余参数:
function getValue(...value) {
console.log(value.length);
}
getValue('1', 'w', '3'); // 3
扩展运算符:
let values = [-25, -50, -75, -100]
console.log(Math.max(-60, ...values)); // -25
console.log(Math.max(...values, -60)); // -25
ES6 的名称属性
匿名函数表达式的 流行使得调试有点困难, 所以ES6 给所有函数 添加了name 属性。
function doSomething() { // 函数声明式
// ...
}
var doAnotherThing = function() { // 匿名函数表达式
// ...
};
console.log(doSomething.name); // "doSomething"
console.log(doAnotherThing.name); // "doAnotherThing"
function doSomething() {
console.log('this is doSomething.');
}
doSomething();
var doAnotherThing = function() {
console.log('this is doAnotherThing.');
};
doAnotherThing();
ES6 名称属性的特殊情况
var doSomething = function() {}
var doAnotherthing = function doAnotherthingElse() {}
var person = {
get firstName() {
return 'personName';
},
sayName: function() {
return 'say person name';
}
}
console.log( doSomething.name ); // doSomething
console.log( doAnotherthing.name ); // doAnotherthingElse
console.log( person.sayName.name ); // sayName
var descriptor = Object.getOwnPropertyDescriptor(person, "firstName");
console.log(descriptor.get.name); // get firstName
person.firstName 实际是个 getter 函数,因此它的名称是"getfirstName" ,以标明它的特征;
同样, setter 函数也会带有"set" 的前缀
( getter与 setter函数都必须用 Object.getOwnPropertyDescriptor() 来检 索)
函数名称还有另外两个特殊情况:
使用 bind() 创建的函数会在名称属性值之前带有"bound" 前缀;
而使用 Function 构造器创建的函数,其名称属性则会有 "anonymous" 前 缀。
var doSomething = function() {};
console.log(doSomething.bind().name); // bound doSomething
console.log((new Function()).name); // anonymous
明确函数的双重用途
function Person(name) {
this.name = name;
}
var person = new Person("Nicholas");
var notAPerson = Person("Nicholas");
console.log(person); // [Object object] // Person {name: "Nicholas"}
console.log(notAPerson); // undefined 未使用 new 来调用 Person() 输出了 undefined (并且在非严格模式下给全局对象添加了 name 属性)
console.log(window); // window.name: "Nicholas"
Person 首字母大写是指示其应当使用 new 来 调用的唯一标识,
ES6 中: JS 提供了两个不同的内部方法: [[Call]] 与 [[Construct]]
未使用 new 进行调用时: [[call]] 方法会被执行,运行的是代码中显示的函数体。会给全局对象添加属性 ( console.log(window); )
当使用 new 进行调用时: [[Construct]] 方法则会被执行,负责创建一个被称为新目标的新的对象,使用该新目标作为 this 去执行函数体。被称为构造器。
在 ES5 中判断函数如何被调用
function Person(name) {
if (this instanceof Person) {
this.name = name; // 使用new
console.log(this);
} else {
throw new Error("You must use new with Person.")
}
}
var person = new Person("Nicholas"); //[object, object] Person {name: "Nicholas"}
var notAPerson = Person("Nicholas"); // 抛出错误
function Person(name) {
if (this instanceof Person) {
this.name = name; // 使用new
} else {
throw new Error("You must use new with Person.")
}
}
var person = new Person("Nicholas");
var notAPerson = Person.call(person, "Michael"); // 奏效了!
调用 Person.call() 并将 person 变量作为第一个参数传入,这意味着将 Person 内部的
this 设置为了 person 。对于该函数来说,没有任何方法能将这种方式与使用 new 调用区 分开来。
为了解决此问题, ES6 引入了 new.target 元属性
警告:在函数之外使用 new.target 会有语法错误。