Function 构造函数

181 阅读2分钟

一:概念与写法

Function 构造函数创建一个新的 Function 对象。直接调用此构造函数可用动态创建函数,但会遇到和 eval 类似的的安全问题和(相对较小的)性能问题。

// 下面这四种写法都是可以的
const test = new Function('a', 'b', 'c', 'console.log(a + b + c)');
const test = new Function('a, b, c', 'console.log(a + b + c)');

// 以调用函数的方式调用 `Function` 的构造函数(而不是使用 `new` 关键字) 跟以构造函数来调用是一样的。
const test = Function('a', 'b', 'c', 'console.log(a + b + c)');
const test = Function('a, b, c', 'console.log(a + b + c)');
test(1,2,3); // 6

二:作用域问题

由 Function 构造器创建的函数不会创建当前环境的闭包,它们总是被创建于全局环境,因此在运行时它们只能访问全局变量和自己的局部变量,不能访问它们被 Function 构造器创建时所在的作用域的变量。这一点与使用 eval 执行创建函数的代码不同。

// Function构造的函数:不会创建闭包,访问全局变量;
var a = 1, b = 2;
function test(){
    var b = 3;
    return new Function('c', 'console.log(a + b + c)');
}
var t = test();
t(4); // 7 

// Function构造的函数:不会创建闭包,访问自己的局部变量;
var a = 1, b = 2;
function test(){
    var b = 3;
    return new Function('c', 'var b = 4; console.log(a + b + c)');
}
var t = test();
t(4); // 9

// eval:变成表达式让其立即执行,访问创建时所在的作用域
var a = 1, b = 2;
function test(){
    var b = 3;
    eval(!function(c){console.log(a + b + c)}(4));
}
test(); // 8

// 函数声明:创建闭包,访问创建时所在的作用域
var a = 1, b = 2;
function test(){
    var b = 3;
    return function(c){
        console.log(a + b + c);
    };
}
var t = test();
t(4); // 8

三:原型问题

函数也是对象。每个对象都有__proto__;但是只有函数才有prototype属性;

WechatIMG1007.png Object.__proto__ === Function.prototype

Function.__proto__ === Function.prototype

Object.__proto__ === Function.__proto__

Function.prototype.__proto__ === Object.prototype

Object.prototype.__proto__ === null

var t1 = new Function('console.log("t1")'); // Function()是一个function
console.log(t1.__proto__ === Function.prototype); // true
console.log(Function.__proto__ === Function.prototype); // true

const obj = new Object(); // Object()是一个function
console.log(obj.__proto__ === Object.prototype); // true
console.log(Object.__proto__ === Function.prototype); //true