Javascript-进阶
Javascript-进阶
事件委托
-
事件冒泡
当子元素事件被触发的时侯,
子元素所有的父级元素 同名事件会被依次触发子元素 -> 父元素 ->
body -
事件委托
L 给父元素注册事件, 委托给子元素处理 - 事件委托原理: 事件冒泡
- 事件委托注意点: 不能使用
this,this指向父元素
this 指向
-
指向问题
1
2
3
4
5
6// 普通的函数被独立调用
function foo() {
// foo Window
console.log("foo", this);
}
foo();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var obj = {
name: "lisi",
foo: function () {
// foo index.html:15 foo {name: 'lisi', foo: ƒ}
console.log("foo", this);
},
};
// obj 调用
obj.foo();
// 独立调用
var baz = obj.foo;
// foo window
baz();1
2
3
4
5
6
7;
// 严格模式下,独立调用的函数中的 this 指向的是 undefined
// 独立调用
var baz = obj.foo;
// foo undefined
baz(); -
隐式绑定
1
2
3
4
5
6
7
8function bar(params) {
// bar obj
console.log("bar", this);
}
var obj = {
foo: bar,
};
obj.foo(); -
new绑定 1
2
3
4
5function foo() {
this.name = "lisi";
console.log("foo", this);
}
new foo();- 创建新的空对象
- 将
this指向这个空对象 - 执行函数整体中的代码
- 没有显示返回非空对象时,
默认返回这个对象
-
显示绑定
1
2
3
4
5
6
7
8
9// 需求: 执行函数 并且函数中的 this 指向 obj 对象
var obj = {
name: "lisi",
};
function foo() {
this.name = "lisi";
console.log("foo", this);
}
foo.call(obj); | foo.apply(obj);call和 apply方法 - 第一个参数是相同的,
要求传入一个对象 - 这个对象就是给
this准备的 - 在调用函数时,
会将 this绑定到这个传入的对象上
- 这个对象就是给
- 后面的参数
apply为数组, call为参数列表
- 第一个参数是相同的,
箭头函数
-
箭头函数
1
2
3
4var foo = (params) => {
console.log(params);
};
foo("lisi");- 箭头函数不会绑定
this,arguments属性 - 箭头函数
不能作为构造函数来使用(不能和 new 一起来使用, 会抛出错误)
- 箭头函数不会绑定
-
练习
1
2
3
4var names = ["a", "b", "c"];
names.forEach((item) => {
console.log(item);
}); -
箭头函数中
this使用 1
2
3
4
5// 查找规则的 this
var bar = () => {
console.log(this);
};
bar();全局 this
-
验证
this1
2
3
4
5
6
7
8
9
10
11var obj = {
name: "obj",
foo: function () {
var bar = () => {
console.log("bar: ", this);
};
return bar;
},
};
var fn = obj.foo();
fn.apply("bbb");this查找规则 
-
浏览器运行原理 (da31)
闭包
-
闭包的定义
-
维基百科
闭包: 又称调法闭包或函数闭包是在支持
头等函数的编程语言中,实现词法绑定的一种技术 闭包在
实现上是一个结构体,他存储了 一个函数和一个关联的环境(相当于一个符号查找表)闭包跟函数的最大区别在于,
当捕捉闭包的时候, 它的 自由变量会在捕捉时被确定,这样即使脱离了捕捉时的上下文, 它也能正常运行 1
2
3
4
5
6
7
8
9
10<script>
// 自由变量
var name = "coder";
var age = 18;
// 函数
function foo() {
console.log(name, age);
}
foo();
</script>闭包 
-
MDN对 Javascript的解释 - 一个函数和对其周围状态的引用捆绑在一起
( 或者说函数被引用包围),这样的组合就是闭包 - 闭包可以让你在一个内层函数中访问到其外层函数的作用域
- 在
Javascript中, 每当创建一个函数, 闭包就会在函数创建的同时被创建
- 一个函数和对其周围状态的引用捆绑在一起
-
个人理解
- 一个普通的函数
function,如果它可以访问外层作用域的自由变量,那么这个函数和周围环境就是一个闭包 - 从广义的角度来说,
Javascript中的函数就是闭包 - 从下一角度说:
Javascript中一个函数, 如果访问了外层作用的变量, 那么它是一个闭包
- 一个普通的函数
-
对象增强和函数增强
-
函数对象的属性
-
name获取函数名称 1
2
3
4
5
6function foo() {}
function bar() {}
var fnArr = [foo, bar];
for (var fn of fnArr) {
console.log(fn.name);
} -
length参数个数 1
2
3
4function foo() {}
foo(12, 34);
// 0
console.log(foo.length);
-
-
arguments-
arguments是一个对应于 传递给函数的参数的类数组(array-like) 对象 1
2
3
4
5function foo(x, y) {
// Arguments(2) [12, 34, callee: ƒ, Symbol(Symbol.iterator): ƒ]
console.log(arguments);
}
foo(12, 34); -
array-like意味着它不是一个数组类型, 而是一个对象类型 - 但是它却拥有数组的一些特性,
比如 length比如可以通过索引 index来访问 - 但是它却没有数组的一些方法,
比如 filter,map
- 但是它却拥有数组的一些特性,
-
arguments转换为数组 1
2
3
4
5
6
7
8
9// 方式一
function foo() {
var newArguments = [];
for (var arg of arguments) {
newArguments.push(arg);
}
console.log(newArguments);
}
foo(1, 2, 3, 4);1
2
3
4
5
6// 方式二: slice
function foo() {
var newArguments = [].slice.apply(arguments);
console.log(newArguments);
}
foo(1, 2, 3, 24, 6);1
2
3
4
5
6
7
8// 方式三
function foo() {
var newArguments = Array.from(arguments);
console.log(newArguments);
}
foo(1, 2, 3, 4, 6);
var newArguments = [...arguments]; -
箭头函数不绑定
arguments1
2
3
4var foo = () => {
console.log(arguments);
};
foo(1, 2, 3, 24, 6);箭头函数 
-
-
函数的剩余参数
( rest)1
2
3
4
5// 剩余参数必须在其他参数最后
function foo(...args) {
console.log(args);
}
foo(12, 56, 67, 90); -
剩余参数和
arguments的区别 - 剩余参数只包含那些没有对应形参的实参,
而 arguments对象包含了传给函数的所有实参 arguments对象不是一个真正的数组, 而 rest参数是一个真正的数组,可以进行数组的所有操作 arguments是早期 ECMAScript中为了方便去获取所有的参数提供的一个数据结构, 而 rest参数是 es6中提供并且希望依此来替代 arguments的
- 剩余参数只包含那些没有对应形参的实参,
-
纯函数
-
维基百科
(满足如下条件) - 此函数
在相同的输入值时,需要产生相同的输出 - 函数的
输出和输入值以外的其他隐藏信息或状态无关,也和 由I/O 设备产生的外部输出无关 - 该函数
不能有语义上可观察的函数副作用诸如触发事件使输出设备输出时,或更改输出值以外的物件的内容等
- 此函数
-
小总结
-
确定的输入,
一定会产生确定的输出, -
函数在执行过程中,
不能产生副作用 -
副作用
在计算机科学中,
表示在执行一个函数时, 除了 返回函数值外,还对调用函数产生了附加影响,比如 修改了全局变量,修改参数或者改变外部的存储 -
案例
slice(纯函数 没有改变原数组)splice(非纯函数 改变了原数组)
-
-
-
函数的柯里化
-
维基百科
- 在计算机科学中,
柯里化又翻译为卡瑞化或加里化 - 是把接受
多个参数的函数,编程一个 接受一个单一参数(最初函数的第一个参数) 的函数, 并且返回接受余下的参数, 而且返回结果的新函数技术 - 柯里化生成
如果你固定某些参数,你将得到接受余下参数的一个函数
- 在计算机科学中,
-
柯里化总结
-
只
传递给函数一部分参数来调用它,让它返回一个函数去处理余下的一个函数 -
这个过程称之为
柯里化1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function foo(x, y, z) {}
foo(1, 2, 3);
// 转换为柯里化: foo(1)(2)(3)
function bar(x) {
console.log(x);
return function foo1(y) {
console.log(y);
return function foo2(z) {
console.log(z);
};
};
}
// 接受一个参数
bar(3)(4)(5);
-
-
自动柯里化函数封装
-
-
组合函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18var num = 100;
// 需求一: num * 2
function doubleNum(num) {
return num * 2;
}
// 需求二: num ** 2
function powNum(num) {
return num ** 2;
}
console.log(powNum(doubleNum(100)));
console.log(powNum(doubleNum(200)));
// 组合函数
function composeFn(num) {
return powNum(doubleNum(num));
}
console.log(composeFn(100));
console.log(composeFn(200)); -
eval函数 eval是一个特殊函数, 它可以将 传入的字符串当作Javascript 代码来运行 eval会将最后一句执行的语句的结果作为返回值
-
严格模式
(待补充 day33)
Es5 中继承
- 对象的原型
- 普通对象的原型