前言
前面写过关于JavaScript的this指向的基础文章,链接:juejin.cn/post/751796…
今天我们继续来讲讲闭包的应用场景之一:实现私有属性和方法的封装
实例
关于私有变量和公有变量的区分
私有变量直接声明,只能由函数内部的其他函数访问,这得益于闭包的特性。
公有变量通过
this暴露出去,外部可以直接访问或调用。
| 写法 | 是否可被外部访问 |
|---|---|
function xxx(){} 定义在函数体内,未暴露 | 私有,外部不可访问 |
挂载到 this.xxx = xxx 或返回对象中 | 公有,外部可访问 |
function Book(title,author,year){
let _title = title; // _约定表示私有变量 内部可以使用 有利于可读性的编程风格
let _author = author;
let _year = year;
}
声明一个构造函数,这三个属性是共有属性,用_开头表示私有变量,有利于可读性的编程风格。
私有属性只有内部才可以访问
我们实例化一个对象book,试图访问私有变量 _title
let book = new Book('js高级程序设计','张三',2020)
console.log("1...."+book._title); // 私有属性 外部无法访问 undefined
结果输出undefined,证明私有变量只能在函数内部访问,在外部不可以访问
在函数中加一个公有属性方法:
function Book(title,author,year){
let _title = title;
let _author = author;
let _year = year;
this.getTitle = function(){ // 对外提供方法 可以访问私有变量 闭包
return _title;
}
}
这里的 this.getTitle是公有属性,赋了一个匿名函数给它,是一个公有方法。
在这里可以访问到私有属性_title
console.log("2...."+book.getTitle());// 可以访问
这里实现是靠闭包实现的,使得外部的
book对象能够访问到内部的私有属性。
我们继续添加一个私有方法 getFullTitle:
function Book(title,author,year){
let _title = title;
let _author = author;
let _year = year;
this.getTitle = function(){ // 对外提供方法 可以访问私有变量 闭包
return _title;
}
function getFullTitle(){
return `${_title} by ${_author}`// 私有方法 外部无法访问
}
}
console.log("4...."+book.getFullTitle);// 私有属性(方法) 外部无法访问 undefined
一样的道理,外部不可以访问私有变量。
假设我们这样访问它:
console.log("4...."+book.getFullTitle());
结果:
这里说
book.getFullTitle不是一个函数,这是为何??
getFullTitle是一个私有方法,只能在Book构造函数内部访问;- 它没有被绑定到
this上,也没有通过返回值暴露出去。
- 而尝试通过
book.getFullTitle()来访问它 —— 这其实是试图访问对象上的一个公共方法;- 所以这写法本身是“访问公有方法”的方式;
- 想访问的是一个“私有方法”,当然会失败。
我们继续添加公有方法:
function Book(title,author,year){
let _title = title;
let _author = author;
let _year = year;
this.getTitle = function(){
return _title;
}
this.getAuthor = function(){ // 闭包
return _author;
}
this.getYear = function(){ // 闭包
return _year;
}
function getFullTitle(){
return `${_title} by ${_author}`
}
this.getFullInfo = function(){
return `${getFullTitle()} published in ${_year}`
}
this.updateYear = function(newYear){
if(typeof newYear === 'number' && newYear > 0){
_year = newYear;
}else{
console.log('Invalid year');
}
}
}
console.log("5...."+book.updateYear(2021));
// 可以访问,但没有返回值
console.log("6...."+book.updateYear("123"));
// 传入的格式错误,而打印要返回某值,
//没有显式地返回任何值,因此它的默认返回值是 undefined。
这里的
book.updateYear(2021)是公有方法,可以访问,但是它并没有显式地返回任何值,故为undefined。
book.updateYear("123")因为传入的值不符合if语句,进入else语句,打印出Invalid year。而执行完毕后,要控制台打印,同上,没有显式返回任何值,故打印undefined。
如:
book.updateYear("123") // 输出Invalid year
而前面第五个打印语句:console.log("5...."+book.updateYear(2021));通过闭包修改了_year的值:
console.log("7...."+book.getYear());// 2021
结尾
总的来说,闭包不仅为JavaScript带来了灵活的作用域控制能力,更为面向对象编程中的封装思想提供了实践路径。通过合理利用闭包特性,我们能够更优雅地实现私有属性和方法的隐藏与暴露,提升代码质量和安全性。掌握闭包的应用,是深入理解JavaScript语言特性的关键一步,也是编写高质量、可维护代码的重要基础。希望本文能帮助你更好地理解和运用闭包这一实用特性!