* 每个javascript函数实际上都是一个Function对象。运行
* (function(){}).constructor === Function // true 便可以得到这个结论.
// 构造函数
const Rectangle = new Function('a', 'b', 'return a+b')
// console.log(Rectangle, Rectangle(1, 2)) // anonymous 3
// 实例属性
// console.log(Rectangle.prototype.arguments) // undefined已弃用, 推荐使用函数内部的arguments
// console.log(Rectangle.prototype.caller) // undefined已弃用,
// console.log(Rectangle.prototype.displayName) // 函数的显示名称(描述)
// console.log(Rectangle.prototype.length) // 函数形参
// console.log(Rectangle.prototype.name, '---') // 函数的名称
/**
* 实例方法
*/
{
/**
* apply
* 语法:
* apply(thisArg)
* apply(thisArg, argsArray)
* 参数:
* thisArg,在func函数运行时使用this值。请注意,this可能不是该方法看到的实际值:
* 如果这个函数处于非严格模式下,若指定为null或undefined时会自动替换为全局对象,原始值会被包装。
* argsArray(可选),一个数组或类数组对象,其中的数组元素将作为单独的参数传给func函数。如果该参数的值为
* null或undefined,则表示不需要传入任何参数。
* 返回值:
* 调用有指定this值和参数的函数的结果
* 描述:
* apply与call用法几乎相同,唯一区别就是apply接受一个单独数组或者类数组(尽量转为数组),call接受一个参数列表
*/
// 示例
// 1.用apply将数组各项添加到另一个数组
{
let arr = [1, 2, 3]
let elements = [4, 5, 6]
arr.push.apply(arr, elements)
// console.log(arr)
}
{
// 原始做法
let arr = [1, 2, 3]
let elements = [4, 5, 6]
arr.push(...elements)
// console.log(arr)
}
/*示例
2.使用apply和内置函数
*/
{
let arr = [3, 4, 1, 2, 0.2]
// console.log(Math.max(...arr), Math.max.apply(null, arr)) // 4 4
// console.log(Math.min(...arr), Math.min.apply(null, arr)) // 0.2 0.2
}
{
// 简单循环算法
let arr = [3, 4, 12, 1, 2, 0.2],
max = -Infinity,
min = +Infinity
for (let i = 0; i < arr.length; i ++) {
if (arr[i] > max) {
max = arr[i]
}
if (arr[i] < min) {
min = arr[i]
}
}
// console.log(max, min)
}
/* 使用apply来链接构造器 */
Function.prototype.construct = function (aArgs) {
let oNew = Object.create(this.prototype)
this.apply(oNew, aArgs)
return oNew
}
function myConstruct() {
for (let i = 0; i < arguments.length; i++) {
this['property' + i] = arguments[i]
}
}
let arr = ['hello', 'world', '!']
let myInstance = myConstruct.construct(arr)
console.log(myInstance)
}
{
/**
* call
*/
// 示例1:使用call方法调用父构造函数
{
function Product(name, price) {
this.name = name
this.price = price
}
function Food(name, price) {
Product.call(this, name, price)
this.category = 'food'
}
let f = new Food('tea', 19)
console.log(f.name, f.price)
}
// 示例2:使用call方法调用匿名函数
{
let arr = [
{name: '张三', age: 18},
{name: '李四', age: 19}
]
for (let i = 0; i < arr.length; i++) {
(function(i) {
this.print = function() {
console.log(`我是第${i}个,name:${this.name}age:${this.age}`)
}
}).call(arr[i], i)
}
arr[0].print()
arr[1].print()
}
// 示例3:使用call方法调用函数并且指定上下文的this
{
function say() {
console.log('我的名字叫' + this.name)
}
let person = {
name: '张三'
}
say.call(person)
}
// 示例4:使用call方法调用函数并且不指定第一个参数(arguments)
{
var name = '张三'
function say() {
console.log('我的名字叫' + this.name)
}
say.call()
}
}
{
/**
* bind
* 语法:
* function.bind(thisArg, [arg1,...])
* 参数:
* thisArg,调用绑定函数时作为this参数传递给目标函数的值。如果使用new运算符构造绑定函数,则忽略该值。
* 当使用bind在setTimeout中创建一个函数作为回调提供时,作为thisArg传递的任何原始值都将转换为Object。
* 如果bind函数的参数列表为空,或者thisArg是null或undefined,执行作用域的this将被视为新函数的thisArg。
* arg1, arg2,当目标函数被调用时,被预置入绑定函数的参数列表中的参数。
* 返回值
* 返回一个原函数的拷贝,并拥有指定的this值和初始参数。
* 描述
* 创建一个新函数,该函数包装了原函数对象,
*/
/* 示例:创建绑定函数 */
{
window.x = 90
const module = {
x: 81,
getX: function() {
console.log(this.x)
}
}
// module.getX()
const retrieveX = module.getX
// retrieveX()
}
{
window.x = 90
const module = {
x: 81,
getX: function() {
console.log(this.x)
}
}
module.getX()
const retrieveX = module.getX
const a = retrieveX.bind(module)
a()
}
/* 拥有预设参数 */
{
function list() {
return Array.prototype.slice.call(arguments)
}
let arr = list(1, 2, 3)
let arr1 = list.bind(null, 90) // 预设参数
console.log(arr1(1, 2, 3))
console.log(arr)
}
/* 配合setTimeout */
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1
}
LateBloomer.prototype.bloom = function () {
window.setTimeout(this.declare.bind(this), 1000)
}
LateBloomer.prototype.declare = function() {
console.log(`i am a beautiful flower with ${this.petalCount} petals!`)
}
/* 快捷调用 */
{
function f() {
let slice = Array.prototype.slice.apply(arguments)
let slice1 = [].slice.apply(arguments)
console.log(slice, slice1)
}
f(1, 2, 3)
}
}