关于javascript:javascript高级程序设计学习笔记-1091011函数内部

20次阅读

共计 6271 个字符,预计需要花费 16 分钟才能阅读完成。

关注前端小讴,浏览更多原创技术文章

相干代码 →

10.9 函数外部

  • ES5 中函数外部有 2 个非凡对象 argumentsthis,1 个外部属性 caller
  • ES6 新增 new.target 属性

10.9.1 arguments

  • arguments是一个 类数组 对象,蕴含调用函数时传入的所有 参数
  • 只有以 funciton 关键字定义函数时才会有 arguments 对象(箭头函数没有
  • 对象有一个 callee 属性,指向 arguments 所在函数的指针(留神:是指针即函数名,而非函数)

    • 严格模式下,拜访 arguments.callee 会报错
// 递归函数:计算阶乘
function factorial(num) {if (num <= 1) return 1
  else return num * factorial(num - 1)
}
// 应用 arguments.callee 解耦函数逻辑与函数名
function factorial(num) {if (num <= 1) return 1
  else return num * arguments.callee(num - 1) // callee 指向 arguments 对象所在函数
}

let trueFactorial = factorial // 保留函数的指针

// 重写 factorial 函数,trueFactorial 指针不变
factorial = function () {return 0}
console.log(trueFactorial(5)) // 120,已用 arguments.callee 解除函数体内代码与函数名的耦合,仍能失常计算
console.log(factorial(5)) // 0,函数已被重写

10.9.2 this

  • 规范函数 中,this指向 调用函数的上下文对象 ,即 函数执行的环境对象(全局作用域指向window
window.color = 'red' // vscode 是 node 运行环境,无奈辨认全局对象 window,测试时将 window 改为 global
let o = {color: 'blue'}
function sayColor() {console.log(this.color)
}
sayColor() // 'red',this 指向全局对象
o.sayColor = sayColor
o.sayColor() // 'blue',this 指向对象 o 
  • 箭头函数 中,this指向 定义函数的上下文对象 ,即 该函数内部的环境对象
let sayColor2 = () => {console.log(this.color) // this 指向定义 sayColor2 的上下文,即全局对象
}
sayColor2() // 'red',this 指向全局对象
o.sayColor2 = sayColor2
o.sayColor2() // 'red',this 指向全局对象
  • 事件回调 定时回调 中调用某个函数时,this指向的 并非 想要的对象,将回调函数写成 箭头函数 可解决问题
function King() {
  this.royaltyName = 'Henry'
  setTimeout(() => {console.log(this.royaltyName) // 箭头函数,this 指向定义函数的上下文,即 King()的函数上下文}, 1000)
}
function Queen() {
  this.royaltyName = 'Elizabeth'
  setTimeout(function () {console.log(this.royaltyName) // 规范函数,this 指向调用函数的上下文,即 setTimeout()的函数上下文}, 1000)
}
new King() // 'Henry',1 秒后打印
new Queen() // undefined,1 秒后打印

10.9.3 caller

  • ES5 定义了 caller 属性,指向 调用以后函数的函数(全局作用域中为 null)
function callerTest() {console.log(callerTest.caller)
}
callerTest() // null,在全局作用域种调用

function outer() {inner()
}
function inner() {console.log(inner.caller)
}
outer() // [Function: outer],在 outer()调用

// 解除耦合
function inner() {console.log(arguments.callee.caller) // arguments.callee 指向 arguments 所在函数的指针,即 inner
}
outer() // [Function: outer],在 outer()调用
  • arguments.caller的值始终是 undefined,这是为了辨别arguments.caller 和函数的caller
  • 严格模式下,拜访 arguments.caller为函数的 caller 属性赋值 会报错
function inner2() {console.log(arguments.caller) // undefined
  console.log(arguments.callee) // [Function: inner2]
}
inner2()

10.9.4 new.target

  • ES6 在函数外部新增 new.target 属性,检测函数 是否应用 new 关键字调用

    • 未应用 new 调用,new.target的值是undefined
    • 应用 new 调用,new.target的值是 被调用的构造函数
function King2() {if (!new.target) {console.log(new.target, 'King2 must be instantiated using"new"')
  } else {console.log(new.target, 'King2 instantiated using"new"')
  }
}
new King2() // [Function: King2] 'King2 instantiated using"new"'King2() // undefined'King2 must be instantiated using "new"'

10.10 函数属性与办法

  • 函数蕴含 2 个属性:lengthprototype

    • length 保留函数心愿接管的 命名参数的个数
    function nameLength(name) {return name}
    function sumLength(sum1, sum2) {return sum1 + sum2}
    function helloLength() {return 'Hello'}
    console.log(nameLength.length, sumLength.length, helloLength.length) // 1 2 0
    • prototype 指向函数的原型对象,保留函数 所有实例办法 不可枚举 (应用for-in 无奈发现)
    console.log(Array.prototype) // 在浏览器中查看 Array 的原型对象,蕴含 sort()等办法
    console.log(Object.keys(Array)) // [],Array 构造函数本身所有可枚举的属性
    console.log(Object.getOwnPropertyNames(Array)) // ['length', 'name', 'prototype', 'isArray', 'from', 'of'],Array 构造函数本身的所有属性
  • 函数有 3 个办法:apply()call()bind()

    function sumPrototype(num1, num2) {return num1 + num2}
    • apply()call() 都会以指定的 this 值调用函数,即 设置 调用函数时函数体内 this指向
    • apply()接管 2 个参数:① 运行函数的作用域(指定 this);② 参数数组(实例或 arguments 对象均可)
    function applySum1(num1, num2) {return sum.apply(this, arguments) // 传入 arguments 对象
    }
    function applySum2(num1, num2) {return sum.apply(this, [num1, num2]) // 传入数组实例
    }
    console.log(applySum1(10, 10)) // 20
    console.log(applySum2(10, 10)) // 20
    • call()接管若干参数:① 运行函数的作用域(指定 this);残余参数一一传入
    function callSum(num1, num2) {return sum.call(this, num1, num2) // 一一传入每个参数
    }
    console.log(callSum(10, 10)) // 20
    • apply()call() 真正弱小的中央在于 可能裁减函数运行的作用域 ,即 管制函数体内 this
    window.color = 'red' // vscode 是 node 运行环境,无奈辨认全局对象 window,测试时将 window 改为 global
    let o2 = {color: 'blue'}
    function sayColor3() {console.log(this.color)
    }
    sayColor3() // 'red',this 指向全局对象
    sayColor3.call(this) // 'red',this 指向全局对象
    sayColor3.call(window) // 'red',this 指向全局对象,测试时将 window 改为 global
    sayColor3.call(o2) // 'blue',this 指向对象 o2
    • Function.prototype.apply.call(),将函数原型的 apply 办法利用 call() 进行绑定(可通过 Reflect.apply() 简化代码)
    let f1 = function () {console.log(arguments[0] + this.mark)
    }
    let o3 = {mark: 95,}
    f1([15]) // '15undefined',this 指向 f1 的函数上下文,this.mark 为 undefined
    f1.apply(o3, [15]) // 110,将 f1 的 this 绑定到 o3
    Function.prototype.apply.call(f1, o3, [15]) // 110,函数 f1 的原型对象的 apply 办法,利用 call 进行绑定
    Reflect.apply(f1, o3, [15]) // 110,通过指定的参数列表发动对指标函数的调用,三个参数(指标函数、绑定的 this 对象、实参列表)
    • bind()创立一个新的函数实例,其 this绑定 传给 bind() 的对象
    let o4 = {color: 'blue'}
    function sayColor4() {console.log(this.color)
    }
    let bindSayColor = sayColor4.bind(o4) // 创立实例 bindSayColor,其 this 被绑定给 o4
    sayColor4() // 'red',this 指向全局对象
    bindSayColor() // 'blue',this 被绑定给对象 o4

10.11 函数表达式

  • 函数申明 的要害特点是 函数申明晋升 ,即函数申明会在 代码执行之前 取得定义
sayHi() // 'Hi',先调用后申明
function sayHi() {console.log('Hi')
}
  • 函数表达式 必须 先赋值再应用 ,其创立一个 匿名函数(function后没有标识符)再把它赋值给一个变量

    • 匿名函数的 name 属性是空字符串
sayHi2() // ReferenceError: Cannot access 'sayHi2' before initialization,不能先调用后赋值
let sayHi2 = function sayHi() {console.log('Hi')
}
  • 函数申明与函数表达式的区别在于 晋升 ,在 条件块 防止应用函数申明 能够应用函数表达式
let condition = false
if (condition) {function sayHi3() {console.log('true')
  }
} else {function sayHi3() {console.log('false')
  }
}
sayHi3() // 不同浏览器的后果不同,防止在条件块中应用函数申明

let sayHi4
if (condition) {sayHi4 = function () {console.log('true')
  }
} else {sayHi4 = function () {console.log('false')
  }
}
sayHi4() // false,能够在条件块中应用函数表达式
  • 创立函数并赋值给变量 可用于 在一个函数中把另一个函数当作值 返回
/**
 * 依照对象数组的某个 object key,进行数组排序
 * @param {String} key 要排序的 key
 * @param {String} sort 正序 / 倒序:asc/desc,默认为 asc
 */
function arraySort(key, sort) {return function (a, b) {if (sort === 'asc' || sort === undefined || sort === '') {// 正序:a[key] > b[key]
      if (a[key] > b[key]) return 1
      else if (a[key] < b[key]) return -1
      else return 0
    } else if (sort === 'desc') {// 倒序:a[key] < b[key]
      if (a[key] < b[key]) return 1
      else if (a[key] > b[key]) return -1
      else return 0
    }
  }
}
var userList = [{ name: 'Tony', id: 3},
  {name: 'Tom', id: 2},
  {name: 'Jack', id: 5},
]
console.log(userList.sort(arraySort('id'))) // [{name: 'Tom', id: 2},{name: 'Tony', id: 3},{name: 'Jack', id: 5}],按 id 正序排列
console.log(userList.sort(arraySort('id', 'desc'))) // [{name: 'Jack', id: 5},{name: 'Tony', id: 3},{name: 'Tom', id: 2}],按 id 倒序排列
console.log(userList.sort(arraySort('name'))) // [{name: 'Jack', id: 5},{name: 'Tom', id: 2},{name: 'Tony', id: 3}],按 name 正序排列

总结 & 问点

  • arguments 是什么?arguments.callee 指向哪里?写一段代码,示意函数名与函数逻辑解耦的阶乘函数
  • this 在规范函数和箭头函数的指向有什么不同?在事件回调或定时回调中,为什么更适宜应用箭头函数?
  • 函数的 caller 属性指向哪里?arguments.caller 的值是什么?严格模式下 caller 有哪些限度?
  • new.target 的作用和值别离是什么?
  • 函数有哪些属性?其指向和用法别离是什么?
  • 请用代码证实 apply()、call()、bind()是如何裁减函数作用域的,并解释 Function.prototype.apply.call()的含意
  • 函数申明和函数表达式最大的区别是什么?如何了解申明晋升?
  • 写一段代码,依据对象数组的某个对象属性进行排序,可依据参数决定排序属性及升 / 降序

正文完
 0