函数进阶
基础知识
声明定义
对象字面量属性函数简写
let user = {
name: null,
getName: function (name) {
return this.name;
},
//简写形式
setName(value) {
this.name = value;
}
}
user.setName('love');
console.log(user.getName()); // love
使用let/const
时不会压入 window
let hd = function() {
console.log("love");
};
window.hd(); //window.hd is not a function
标准声明的函数优先级更高,解析器会优先提取函数并放在代码树顶端,所以标准声明函数位置不限制,所以下面的代码可以正常执行。
console.log(hd(3));
function hd(num) {
return ++num;
};
标准声明优先级高于赋值声明
console.log(hd(3)); //4
function hd(num) {
return ++num;
}
var hd = function() {
return "5";
};
使用 let/const
有块作用域特性,所以使用以下方式也可以产生私有作用域
{
let web = 'love';
}
console.log(web);//Uncaught ReferenceError: web is not defined
arguments
arguments 是函数获得到所有参数集合,下面是使用 arguments
求和的例子
function sum() {
return [...arguments].reduce((total, num) => {
return (total += num);
}, 0);
}
console.log(sum(2, 3, 4, 2, 6)); //17
更建议使用展示语法
function sum(...args) {
return args.reduce((a, b) => a + b);
}
console.log(sum(2, 3, 4, 2, 6)); //17
箭头函数
箭头函数是函数声明的简写形式,在使用递归调用、构造函数、事件处理器时不建议使用箭头函数。
标签函数
使用函数来解析标签字符串,第一个参数是字符串值的数组,其余的参数为标签变量。
function hd(str, ...values) {
console.log(str); //["站点", "-", "", raw: Array(3)]
console.log(values); //["love", "you"]
}
let name = 'love',url = 'you';
hd `站点${name}-${url}`;
this
his
调用函数时 this
会隐式传递给函数指函数调用时的关联对象,也称之为函数的上下文。
函数调用
全局环境下this
就是 window 对象的引用
<script>
console.log(this == window); //true
</script>
使用严格模式时在全局函数内this
为undefined
对象字面量
- 下例中的 hd 函数不属于对象方法所以指向
window
- show 属于对象方法执向
obj
对象
let obj = {
site: "love",
show() {
console.log(this.site) //love
console.log(`this in show method: ${ this }`) //this in show method: [object Object]
function hd() {
console.log(typeof this.site) //undefined
console.log(`this in hd function: ${ this }`) //this in hd function: [object Window]
}
hd()
}
}
obj.show();
在方法中使用函数时有些函数可以改变 this 如forEach
,当然也可以使用后面介绍的apply/call/bind
let Lesson = {
site: "love",
lists: ["js", "css", "mysql"],
show() {
return this.lists.map(function(title) {
return `${this.site}-${title}`;
}, this);
}
};
console.log(Lesson.show());
也可以在父作用域中定义引用this
的变量
let Lesson = {
site: "love",
lists: ["js", "css", "mysql"],
show() {
const self = this;
return this.lists.map(function(title) {
return `${self.site}-${title}`;
});
}
};
console.log(Lesson.show());
箭头函数
箭头函数没有this
, 也可以理解为箭头函数中的this
会继承定义函数时的上下文,可以理解为和外层函数指向同一个 this。
- 如果想使用函数定义时的上下文中的 this,那就使用箭头函数
下例中的匿名函数的执行环境为全局所以 this
指向 window
。
let name = 'loveagri'
let obj = {
name: 'js',
getName: function () {
console.log(this.name) //js
return function () {
return this.name
}
}
}
console.log(obj.getName()()) //loveagri
使用箭头函数时 this 指向上下文对象,匿名函数的一般使用event.target
寻找上下文对象。
<body>
<button desc="hdcms">button</button>
</body>
<script>
let Dom = {
site: "loveagri",
bind() {
const button = document.querySelector("button");
button.addEventListener("click", event => {
alert(this.site + event.target.innerHTML);
});
}
};
Dom.bind();
</script>
使用handleEvent
绑定事件处理器时,this
指向当前对象而不是 DOM 元素。
<body>
<button desc="hdcms">button</button>
</body>
<script>
let Dom = {
site: "loveagri",
handleEvent: function(event) {
console.log(this);
},
bind() {
const button = document.querySelector("button");
button.addEventListener("click", this);
}
};
Dom.bind();
</script>
apply/call/bind
改变 this 指针,也可以理解为对象借用方法
原理分析
构造函数中的this
默认是一个空对象,然后构造函数处理后把这个空对象变得有值。
function User(name) {
this.name = name;
}
let love = new User("love");
可以改变构造函数中的空对象,即让构造函数 this 指向到另一个对象。
function User(name) {
this.name = name;
}
let love = {};
User.call(love, "love");
console.log(love.name); //love
apply/call
call 与 apply 用于显示的设置函数的上下文,两个方法作用一样都是将对象绑定到 this,只是在传递参数上有所不同。
- apply 用数组传参
- call 需要分别传参
- 与 bind 不同 call/apply 会立即执行函数
bind
bind()是将函数绑定到某个对象,比如 a.bind(hd) 可以理解为将 a 函数绑定到 hd 对象上即 hd.a()。
- 与 call/apply 不同 bind 不会立即执行
- bind 是复制函数形为会返回新函数