JavaScript_函数

本文深入探讨了ES6箭头函数的特性,如匿名、不可作为构造器等,并剖析了JavaScript原型和原型链的概念,展示了如何通过原型链继承和作用域规则。同时讲解了命名提升、闭包以及各种作用域的区别,适合理解JavaScript进阶特性的开发者阅读。
摘要由CSDN通过智能技术生成

函数

函数声明
//ES5
function getName(){
  console.log('name')
}
getName() // name
//匿名函数
!function (){
  console.log('none')
}(); // none
var getName5 = function() {
  console.log('var')
}
getname() // var
//ES6
// 箭头函数
(() => console.log('=>'))() // =>

let getName6 = () => {
  console.log('let =>')
}
getname() // let =>
箭头函数与普通函数区别
  1. 不能绑定 arguments 对象,在函数内无法访问 arguments 对象,会报错
  2. 不能用作构造器,不能通过 new 来创建实例
  3. 默认不会创建 prototype 原型属性
  4. 不能作为 Generator() 函数,不能使用 yeild 关键字
函数转换

隐式转换函数 toString()valueOf()

toString() 函数会在打印函数的时候调用,如console.log()

valueOf 会在获取函数原始值时调用,如运算

原型

原型是 JavaScript 重要的特性之一

可以让对象从其他对象继承功能的特性

JavaScript 也被称之为 基于原型的语言

严格的说原型应该是对象的特性,但函数其实也是一种特殊的对象

function fn() {}
console.log(fn instanceof Object) // true
原型、原型链

原型就是对象属性

包括,隐式原型__proto__ 属性和显式原型 prototype 属性

隐式原型__proto__ 一般为对象自带的,最上级为 Object ,而 Object 的隐式原型 指向 null

let obj = {
  name: 'obj'
}
console.log(obj.__proto__) // [Object: null prototype] {}
console.log(obj.__proto__.__proto__) // null

function fn () {}
console.log(fn.__proto__.__proto__) // [Object: null prototype] {}
console.log(fn.prototype) // {}
console.log(obj.prototype) // undefined

let p = {code:'p',name:'pn'}

let c = {
  __proto__:p,name:'cn'
}

console.log(c.name) // cn
console.log(c.code) // p 通过原型链查找
// 可以使用 hasOwnProperty() 方法判断属性是否为本对象拥有
console.log(c.hasOwnProperty('name')) // true
console.log(c.hasOwnProperty('code')) // false

class P {}
let c = new P()

console.log(c.__proto__ === P.prototype) // true
new 操作符实现了什么?
function F(args){}
let f = new F(args)
  1. 创建一个临时空对象,让对象的隐式原型指向函数 F 的显式原型
  2. 执行函数 F(),将 this 指向临时对象,并传入参数 args 得到结果
  3. 判断结果如果结果为非空对象,返回 result,否则返回临时对象
function F(init) {
  let a = { name: 'a' }
  let b = function() {
    console.log(init)
  }
}

let args = ['test']

let fn = Object.create(F.prototype)

let obj = F.apply(fn,args)

let f1 = obj && typeof obj === 'object'? obj: fn

let f2 = new F('test')

console.log(f1.__proto__ === f2.__proto__) // true
console.log(f1.a === f2.a) // true
console.log(f1.b === f2.b) // true
原型链继承
function A() {}

A.prototype.a = function () {
  console.log('a')
}

function B() {}

B.prototype = new A()

B.prototype.b = function() {
  console.log('b')
}

let c = new B()

c.a() // a
c.b() // b
function fn() {}

console.log(fn.__proto__ === Function.prototype) // true
// 可以通过 instanceof 判断原型是否在原型链上
console.log(fn instanceof Function) // true
作用域
  1. 作用域是指赋值、取值的范围,即上下文,可以有效的防止变量/函数重复定义以及控制它们的访问属性

  2. 浏览器和 Node.js 作用域处理不同,比如全局作用域,浏览器会自动将未主动声明的变量提升到全局作用域,

    Node.js 则是需要显示挂载到 global 对象上。比如在 ES6 之前,浏览器不提供模块级别的作用域,而 Node.js 的 CommonJS 模块提供模块级别作用域。

  3. 在类型上可以分为全局作用域(window/global)、块级作用域(let、const、try/catch)、模块级作用域(ES6 Module、CommonJS)、以及函数作用域

命名提升

对于使用 var 声明的变量,以及创建命名函数的时候, JavaScript 在解析执行的时候会将声明的内容提前提升到作用域顶部,这种机制称为命名提升

var a = test()
function test() {
  return 'a'
}
console.log(a) // a

console.log(b) // undefined 只是声明还未赋值
var b = 'b'
console.log(b) // b

console.log(c) // 报错 Cannot access 'c' before initialization let 不会进行变量提升
let c = 'c'

f() // 报错 f is not a function 只是声明还未赋值
var f = function() {}
闭包

在函数内部访问外部函数作用域时就会产生闭包,闭包允许将函数与其操作的某些数据(环境)关联起来,这种关联不只是跨作用域引用,也可以实现数据与函数的隔离

// 通过闭包实现单例模式
let SingleStudent = (function(){
  function Student() {}
  let _student;
  return function () {
    if(_student) return _student;
    _student = new Student()
    return _student
  }
})()

let s1 = new SingleStudent()
let s2 = new SingleStudent()

console.log(s1 === s2)

注意,闭包不一定会引起内存泄漏,可参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值