函数/闭包/类
1.函数默认值
//js原生函数没有默认值
function delay(timeout, callback) {
timeout = typeof timeout !== undefined ? timeout : 3000;
callback = typeof callback !== undefined ? callback : function () {};
setTimeout(callback, timeout);
}
delay();
//es6,可以给函数传递默认参数
function delay(timeout = 3000, callback = function () {}) {
setTimeout(callback, timeout);
}
delay();
2.传统函数表达式/回调的缺点与解决方案
let user = {
//属性
name: "peter",
//方法
getName: function () {
//将当前this放到一个临时变量中保存起来
let that = this;
console.log(that);
setTimeout(function () {
//回调函数默认作用域是全局
console.log(this);
console.log(that);
console.log("My name is ", that.name);
}, 1000);
},
};
user.getName();
3.箭头函数的小案例
//解决了函数表达式作用域的指向问题
let user = {
//属性
name: "peter",
//方法
getName: function () {
setTimeout(() => {
//回调函数默认作用域是全局
console.log(this);
console.log("My name is ", this.name);
}, 1000);
},
};
user.getName();
//箭头函数主要是替代之前的函数表达式
//箭头函数没有自己的this,支持词法作用域/块级作用域
四、箭头函数基本语法
//1.无参数
let f1 = function () {
console.log("无参数F1()");
};
f1();
//箭头函数
f1 = () => {
console.log("箭头函数——>F1()");
};
f1();
//只有一行代码{}可以省略
f1 = () => console.log("箭头函数——>F2()");
f1();
//懒得调用的话可以写成立即执行函数
(f1 = () => console.log("箭头函数——>F3()"))();
console.log("------------------------");
//2.单个参数
let f2 = function (item) {
console.log(`f1(${item})`);
};
f2("item");
//箭头函数
f2 = (item) => console.log(`箭头函数f2(${item})`);
f2("item");
(f2 = (item) => console.log(`箭头函数f2(${item})`))("item2");
//简化item可以省略()
//3.多个参数
let f3 = function (...items) {
console.log("f3()", items);
};
f3(1, 2, 3, 4);
//箭头函数
//有多条语句的话{}不能省略
f3 = (...items) => {
console.log(this);
console.log("箭头函数->f3()", items);
};
f3(5, 6, 7, 8);
五、…rest/spread
//...rest(剩余参数),将多个参数归并到一个数组中,用在函数的参数列表中
let sum = (a, b) => a + b;
console.log(sum(5, 6));
//累加
sum = (...arr) => arr.reduce((prev, next) => prev + next, 0);
console.log(sum(4, 8, 3, 6));
//遍历
let f = (...items) => items.map((item) => console.log(item));
f("apple", "pear", "orange");
//2. ...spread(扩展参数),从一个集合中解析出一个个独立的元素,用在函数的调用的实际参数列表中
f = (a, b, c) => console.log(a + b + c);
f(3, 4, 5);
f(...[3, 4, 5]);
//混合在一起
f = (a, ...items) => console.log(a, items);
f(4, 5, 6, 7);
f(...[4, 5, 6], 7);
六、对象字面量的扩展
//1.传统:对象字面量的声明
let createUser = (id, name, email) => ({
id: id,
name: name,
email: email,
});
let user = createUser(1, "admin", "admin@qq.com");
console.log(user);
//当对象中的属性与属性值同名时可省去变量值
createUser = (id, name, email) => ({ id, name, email });
user = createUser(2, "wang", "wang@qq.com");
console.dir(user);
//2.方法简化
let site = {
siteName: "php中文网",
getSite: function () {
return this.siteName;
},
};
console.log(site);
//es6方法简化
let prop = "siteName";
site = {
prop: "php中文网",
//:function去掉
getSite() {
return this.siteName;
},
};
console.log(site);
let prefix = "user-";
user = {
[prefix + "name"]: "Trump",
[`${prefix}email`]: "trump@qq.com",
};
console.log(user);
七、闭包原理
//mdn:闭包是可以访问自由变量的函数
function foo(a) {
//函数中有二类变量是自己的
//1.函数参数
//2.私有变量
//只要不是a,b之外的,都是自由变量
let b = 10;
console.log(a, b);
console.log(c);
}
console.log(foo());
//从技术角度看,任何一个函数都是闭包
//实际开发中,闭包需要满足两个条件
//1.即使出啊关键它的上下文已经销毁,它仍然存在(例如,内部函数从父函数中返回)
//2.在代码中引用了自由变量
//简化一下
//1.函数中必须要有一个子函数,且返回这个函数
//2.在这个子函数中,引用了父函数中的变量
八、闭包的应用场景
//1.访问函数中的私有变量
let foo = () => {
//私有变量
let username = "peter";
//子函数(闭包),当前的username相对于闭包(子函数get)来说是自由变量
let get = () => username;
return get;
};
let get = foo();
console.log(get);
console.log(get());
//2.快速创建多个全局可用的API
//要求这个脚本返回四个接口api
let set, inc, dec, print;
let manager = () => {
let num = 10;
//设置器
set = (val) => (num = val);
//递增器
inc = () => num++;
//递减器
dec = () => num--;
//打印
print = () => console.log(num);
};
//初始化
manager(10);
print();
inc();
print();
set(20);
print();
dec();
print();
九、es6中的类
//原生js没有类,通过"构造函数"模拟类
function Person(name) {
this.name = name;
}
//公共方法放在函数的原型对象上
Person.prototype.sayName = function () {
return this.name;
};
let person = new Person("孙悟空");
let person1 = new Person("齐天大圣");
console.log(person);
console.log(person1);
//es6
class PersonClass {
//构造方法
constructor(name) {
this.name = name;
}
//原型方法
sayName() {
return this.name;
}
}
person = new PersonClass("灭绝师太");
console.log(person.sayName());
//函数
function fn(a, b) {}
console.dir(fn);
//prototype:原型属性:当函数当成非构造函数调用时,没有用
//__proto__:原型链属性,因为函数也是对象
//任何对象都有一个__proto__
console.log({});
console.log({}.toString());
//__proto__:原型链属性
//构造函数的原型属性 prototype,上面是当前构造函数的所有实例所共享的属性和方法
function A() {
//以下是伪代码,用于辅助理解
//1.生成新对象
/* this = New A; */
//A.prototype上的内容,是每个实例/对象上都应该有的公共成员
//2.从A.prototype上复制所有属性和方法到这个新对象上this
//this.toString = A.prototype.toString;
//this.valueof = A.prototype.valueof;
//.....
//3.
//return this
}
console.dir(A);
let a = new A();
console.log(a);
//函数有两个重要的属性
//原型属性:prototype,做为构造函数的时候才会用到,当该属性的指针指向新对象的__proto__
//原型链属性: __proto__,因为任何一个对象都有这个属性,指向自己的公共方法函数也是对象,当然也有这个属性
十、学习总结
1.函数默认值
js原生函数没有默认值
es6,可以给函数传递默认参数
2.传统函数表达式/回调的缺点与解决方案
回调函数默认作用域是全局
当this指向全局时,可以把this放到一个临时变量中保存起来
3.箭头函数的小案例
箭头函数解决了函数表达式作用域的指向问题
箭头函数主要是替代之前的函数表达式
箭头函数没有自己的this,支持词法作用域/块级作用域
4.箭头函数基本语法
f1 = () => {
console.log("箭头函数——>F1()");
};
f1();
只有一行代码{}可以省略
单个参数的箭头函数
f2 = (item) => console.log(`箭头函数f2(${item})`);
f2("item");
- 多个参数的箭头函数
let f3 = function (...items) {
console.log("f3()", items);
};
f3(1, 2, 3, 4);
- 有多个参数的箭头函数{}不能省略
五、…rest/spread
…rest(剩余参数),将多个参数归并到一个数组中,用在函数的参数列表中
…spread(扩展参数),从一个集合中解析出一个个独立的元素,用在函数的调用的实际参数列表中
六、对象字面量的扩展
当对象中的属性与属性值同名时可省去变量值
es6方法简化,可以去掉
:function
改为()
let prop = "siteName";
site = {
prop: "php中文网",
//:function去掉
getSite() {
return this.siteName;
},
};
console.log(site);
七、闭包原理
闭包是可以访问自由变量的函数
函数中有二类变量是自己的:1.函数参数2.私有变量;只要不是a,b之外的,都是自由变量
函数中必须要有一个子函数,且返回这个函数
在这个子函数中,引用了父函数中的变量
八、闭包的应用场景
- 访问函数中的私有变量
let foo = () => {
//私有变量
let username = "peter";
//子函数(闭包),当前的username相对于闭包(子函数get)来说是自由变量
let get = () => username;
return get;
};
let get = foo();
console.log(get);
console.log(get());
- 快速创建多个全局可用的API
let set, inc, dec, print;
let manager = () => {
let num = 10;
//设置器
set = (val) => (num = val);
//递增器
inc = () => num++;
//递减器
dec = () => num--;
//打印
print = () => console.log(num);
};
//初始化
manager(10);
print();
inc();
print();
九、es6中的类
原生js没有类,通过”构造函数”模拟类
公共方法放在函数的原型对象
函数对象都有一个子对象 prototype对象
prototype表示该函数的原型,也表示一个类的成员的集合
es6
class PersonClass {
//构造方法
constructor(name) {
this.name = name;
}
//原型方法
sayName() {
return this.name;
}
}
person = new PersonClass("灭绝师太");
console.log(person.sayName());
js在创建对象的时候,都有一个叫做
__proto__
的内置属性,用于指向创建它的函数对象的原型对象prototype
原型链的基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法
每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针( constructor),而实例则包含一个指向原型对象的内部指针(
__proto__
)函数有两个重要的属性:
原型属性:prototype,做为构造函数的时候才会用到,当该属性的指针指向新对象的__proto__
原型链属性: __proto__,因为任何一个对象都有这个属性,指向自己的公共方法函数也是对象,当然也有这个属性