手写apply-call-bind
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// new Function()
// foo.__proto__ === Function.prototype
function foo(name, age) {
console.log(this, name, age)
}
// foo函数可以通过apply/call
// foo.apply("aaa", ["why", 18])
// foo.call("bbb", "kobe", 30)
// 1.给函数对象添加方法: hyapply
Function.prototype.hyapply = function(thisArg, otherArgs) {
// this -> 调用的函数对象
// thisArg -> 传入的第一个参数, 要绑定的this
// console.log(this) // -> 当前调用的函数对象
// this.apply(thisArg)
thisArg.fn = this
// 1.获取thisArg, 并且确保是一个对象类型
thisArg = (thisArg === null || thisArg === undefined)? window: Object(thisArg)
// thisArg.fn = this
Object.defineProperty(thisArg, "fn", {
enumerable: false,
configurable: true,
value: this
})
thisArg.fn(...otherArgs)
delete thisArg.fn
}
// foo.hyapply({ name: "why" }, ["james", 25])
// foo.hyapply(123, ["why", 18])
// foo.hyapply(null, ["kobe", 30])
// 2.给函数对象添加方法: hycall
Function.prototype.hycall = function(thisArg, ...otherArgs) {
// 1.获取thisArg, 并且确保是一个对象类型
thisArg = (thisArg === null || thisArg === undefined)? window: Object(thisArg)
// thisArg.fn = this
Object.defineProperty(thisArg, "fn", {
enumerable: false,
configurable: true,
value: this
})
thisArg.fn(...otherArgs)
delete thisArg.fn
}
foo.hycall({ name: "why", fn: "abc" }, "james", 25)
foo.hycall(123, "why", 18)
foo.hycall(null, "kobe", 30)
</script>
</body>
</html>
封装
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// new Function()
// foo.__proto__ === Function.prototype
function foo(name, age) {
console.log(this, name, age)
}
// foo函数可以通过apply/call
// foo.apply("aaa", ["why", 18])
// foo.call("bbb", "kobe", 30)
// 1.封装思想
// 1.1.封装到独立的函数中
function execFn(thisArg, otherArgs, fn) {
// 1.获取thisArg, 并且确保是一个对象类型
thisArg = (thisArg === null || thisArg === undefined)? window: Object(thisArg)
// thisArg.fn = this
Object.defineProperty(thisArg, "fn", {
enumerable: false,
configurable: true,
value: fn
})
// 执行代码
thisArg.fn(...otherArgs)
delete thisArg.fn
}
// 1.2. 封装原型中
Function.prototype.hyexec = function(thisArg, otherArgs) {
// 1.获取thisArg, 并且确保是一个对象类型
thisArg = (thisArg === null || thisArg === undefined)? window: Object(thisArg)
// thisArg.fn = this
Object.defineProperty(thisArg, "fn", {
enumerable: false,
configurable: true,
value: this
})
thisArg.fn(...otherArgs)
delete thisArg.fn
}
// 1.给函数对象添加方法: hyapply
Function.prototype.hyapply = function(thisArg, otherArgs) {
this.hyexec(thisArg, otherArgs)
}
// 2.给函数对象添加方法: hycall
Function.prototype.hycall = function(thisArg, ...otherArgs) {
this.hyexec(thisArg, otherArgs)
}
foo.hyapply({ name: "why" }, ["james", 25])
foo.hyapply(123, ["why", 18])
foo.hyapply(null, ["kobe", 30])
foo.hycall({ name: "why" }, "james", 25)
foo.hycall(123, "why", 18)
foo.hycall(null, "kobe", 30)
</script>
</body>
</html>
ES6~ES13新特性(一)
1 ECMA新描述概念
新的ECMA代码执行描述
词法环境(Lexical Environments)
LexicalEnvironment和VariableEnvironment
环境记录(Environment Record)
新ECMA描述内存图

2 let、const的使用
let/const基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// ES6之前
var message1 = "Hello World"
message1 = "Hello Coderwhy"
message1 = "aaaaa"
console.log(message1)
// ES6开始
// 1.let
let message2 = "你好, 世界"
message2 = "你好, why"
message2 = 123
console.log(message2)
// 2.const
// const message3 = "nihao, shijie"
// message3 = "nihao, why"
// 赋值引用类型
const info = {
name: "why",
age: 18
}
// info = {}
info.name = "kobe"
console.log(info)
</script>
</body>
</html>
let/const作用域提升
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 1.var声明的变量会进行作用域的提升
// console.log(message)
// var message = "Hello World"
// 2.let/const声明的变量: 没有作用域提升
// console.log(address)
console.log(address)
let address = "广州市"
const info = {}
</script>
</body>
</html>
暂时性死区 (TDZ)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 1.暂时性死区
// function foo() {
// console.log(bar, baz)
// console.log("Hello World")
// console.log("你好 世界")
// let bar = "bar"
// let baz = "baz"
// }
// foo()
// 2.暂时性死区和定义的位置没有关系, 和代码执行的顺序有关系
// function foo() {
// console.log(message)
// }
// let message = "Hello World"
// foo()
// console.log(message)
// 3.暂时性死区形成之后, 在该区域内这个标识符不能访问
let message = "Hello World"
function foo() {
console.log(message)
const message = "哈哈哈哈"
}
foo()
</script>
</body>
</html>
let/const有没有作用域提升呢?
Window对象添加属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 1.var定义的变量是会默认添加到window上的
// var message = "Hello World"
// var address = "广州市"
// console.log(window.message)
// console.log(window.address)
// 2.let/const定义的变量不会添加到window上的
// let message = "Hello World"
// let address = "广州市"
// console.log(window.message)
// console.log(window.address)
// 3.let/var分别声明变量
var message = "Hello World"
let adress = "广州市"
function foo() {
debugger
}
foo()
</script>
</body>
</html>
3 块级作用域的使用
var的块级作用域
let/const的块级作用域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 1.在ES5以及之前, 只有全局和函数会形成自己的作用域
// 代码块
// function foo() {
// console.log("Hello World")
// }
// {
// var message = "Hello World"
// }
// console.log(message)
// 2.从ES6开始, 使用let/const/function/class声明的变量是有块级作用域
// console.log(message)
// foo()
{
var message = "Hello World"
let age = 18
const height = 1.88
class Person {}
function foo() {
console.log("foo function")
}
}
// console.log(age)
// console.log(height)
// const p = new Person()
foo()
</script>
</body>
</html>
块级作用域的应用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>按钮0</button>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
// 1.形成的词法环境
// var message = "Hello World"
// var age = 18
// function foo() {}
// let address = "广州市"
// {
// var height = 1.88
// let title = "教师"
// let info = "了解真相~"
// }
// 2.监听按钮的点击
const btnEls = document.querySelectorAll("button")
// [btn1, btn2, btn3, btn4]
// for (var i = 0; i < btnEls.length; i++) {
// var btnEl = btnEls[i];
// // btnEl.index = i
// (function(m) {
// btnEl.onclick = function() {
// debugger
// console.log(`点击了${m}按钮`)
// }
// })(i)
// }
for (let i = 0; i < btnEls.length; i++) {
const btnEl = btnEls[i];
btnEl.onclick = function() {
console.log(`点击了${i}按钮`)
}
}
// console.log(i)
</script>
</body>
</html>
3 let、const和var区别
var、let、const的选择
5 模板字符串的详解
字符串模板基本使用
标签模板字符串使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const name = "why"
const age = 18
// 1.基本用法
// 1.1.ES6之前
// const info = "my name is" + name + ", age is " + age
// 1.2.ES6之后
const info = `my name is ${name}, age is ${age}`
console.log(info)
// 2.标签模板字符串的用法
function foo(...args) {
console.log("参数:", args)
}
// foo("why", 18, 1.88)
foo`my name is ${name}, age is ${age}, height is ${1.88}`
</script>
</body>
</html>