文章目录
JS
1.1作用域和闭包、this
(1)作用域和自由变量
作用域就是变量的一个合法使用范围
变量可以在自己对应的红框的任何位置使用
(2)作用域分为以下几类:
1.全局作用域
2.函数作用域
3.块级作用域(ES6新增)
if (true) {
let x = 100
}
console.log(x) // 报错
(3)自由变量
- 一个变量在当前作用域没有定义,但被使用了
- 向上级作用域,一层一层一次寻找,直到找到为止
- 如果到全局作用域都没找到,则报错xx is not definded
(4) 闭包
-
作用域应用的特殊情况,有两种表现:
- 函数作为参数被传递
- 函数作为返回值被返回
所有的自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方。
// 闭包 // 函数作为返回值 function create() { let a = 100 return function () { console.log(a) } } const fn = create() const a = 200 fn() //a = 100 //函数作为参数 function print(fn){ const a = 200 fn() } const a = 100 function fn(){ console.log(a) } print(fn) //100
(5)闭包的应用
- 隐藏数据
- 如做一个简单的cache工具
// 闭包隐藏数据 ,只提供 API
function createCache() {
const data = {} // 闭包中的数据,被隐藏,不被外界访问
return {
set: function (key, val) {
data[key] = val
},
get: function (key) {
return data[key]
}
}
}
const c = createCache()
c.set('a', 100)
console.log(c.get('a'))
// 用户能用到set get 的api,但是不能够直接操作data数据
重点区别:
// 创建10 个a标签,点击的时候弹出对应的序号
let a
for (let i = 0; i < 10; i++) {
a = document.createElement('a')
// 这里不能用innerText给a赋标签内容,需要使用innerHTML,浏览器才能识别
a.innerHTML = i+'<br>'
a.addEventListener('click',function(e){
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}
// !!!上面这段代码,点击连接弹出0-9,并不是10.因为let i 是 for 作用域中的内容,每次点击就会在作用域查找上一次的值
let i, a
for (i = 0; i < 10; i++) {
a = document.createElement('a')
// 这里不能用innerText给a赋标签内容,需要使用innerHTML,浏览器才能识别
a.innerHTML = i+'<br>'
a.addEventListener('click',function(e){
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}
// !!!上面这段代码,点击链接时只会弹出10,因为此时全局变量,再点击之前i就已经被累加到了10
(6)this
-
作为普通函数
-
使用
call
、apply
、bind
-
作为对象方法被调用
-
在
class
方法中调用 -
箭头函数
this取什么样的值,是在执行的时候确认,不是在函数定义的时候确认的。
// this
function fn1() {
console.log(this)
}
fn1() //window
fn1.call({x: 100}) // {x:100}
const fn2 = fn1.bind({x: 200}) // {x:200}
fn2()
const zhangsan1 = {
name: '张三',
sayHi() {
// this 即当前对象
console.log(this)
},
wait() {
setTimeout(function() {
// this === window
console.log(this)
})
}
}
const zhangsan2 = {
name: '张三',
sayHi() {
// this 即当前对象
console.log(this)
},
waitAgain() {
setTimeout(() => {
// this 即当前对象,箭头函数的this取值是取他上级作用域的取值
console.log(this)
})
}
}
class People {
constructor(name) {
this.name = name
this.age = 20
}
sayHi() {
console.log(this)
}
}
const zhangsan = new People('张三')
zhangsan.sayHi() // zhangsan 对象
(7)手写bind函数
Function.prototype.bind1 = function () {
// 将参数解析为数组
const args = Array.prototype.slice.call(arguments)
// 获取 this (取出数组第一项,数组剩余的就是传递的参数)
const t = args.shift()
const self = this //当前函数
//返回一个函数
return function () {
// 执行原函数,并返回结果
return self.apply(t,args)
}
}
1.2 值类型和引用类型的区别
常见的值类型 :
undefined 、 字符串 、 数值 、布尔 、Symbol(‘s’)(es6)
常见的引用类型:
对象 、 数组 、null(特殊引用类型,指针指向为空地址)、函数(特殊引用类型,它不用于存储数据,所以没有“拷贝、复制函数”一说)
用const定义常量必须赋值
1.3 typeof 运算符
- 识别所有值类型
- 识别函数
- 判断是否是引用类型(不可再细分)
// 判断所有值类型
let a;
const str = "abc";
const n = 100;
const b = true;
const s = Symbol('s');
typeof a // 'undefined'
typeof str // 'string'
typeof n // 'number'
typeof b // 'boolean'
typeof s // 'symbol'
// 能判断函数
typeof console.log // 'function'
typeof funtion () {} // 'function'
// 能识别引用类型(不能具体属于应用类型中的哪一类)
typeof null // 'object'
typeof ['a','b'] // 'object'
typeof { x: 100} // 'object'
1.4 深拷贝和浅拷贝
浅拷贝
在js默认情况下,对象赋值是一个浅拷贝。
obj1 = {
name: "国福",
age: 56,
address: {
city: 'beijing'
},
arr: ['a','b','c']
}
const obj2 = obj1
obj2.address.city = 'shanghai'
console.log(obj1.address.city) // shanghai
深拷贝(手写深拷贝)
- 注意判断值类型和引用类型
- 注意判断是数组还是对象
- 递归
// Obj1实例
let obj1 = {
name: "双越",
age: 15,
address:{
city:"北京"
},
hobby:['写书','写诗','跑步']
}
console.log(obj1)//15
let obj2 = deepClone(obj1)
obj2.age=17
console.log(obj1)//15
let obj3 = obj1
obj3.age = 34
console.log(obj1)//34
/**
* 深拷贝
* @param {Object} obj
*/
function deepClone (obj) {
if (typeof(obj) !== 'object'|| obj == null) {
// obj 是 null,或者不是对象和数组,直接返回
return obj
}
// 初始化返回结果
let result
// instanceof 判断obj具体为什么引用类型
if (obj instanceof Array) {
result = []
} else {
result = {}
}
for (let key in obj) {
// hasOwnProperty 判断属性是否属于对象
if (obj.hasOwnProperty(key)) {
// 保证 key 不是原型的属性,而是自身属性
result[key] = deepClone(obj[key])
}
}
return result
}
1.5 变量计算-类型转换
-
字符串拼接
-
== 运算符
100 == '100' //true 0 == '' //true 0 == false //true flase == '' //true null == undefinded //true // 除了 == mull 之外,其他都一律用 ===,例如 const obj = { x: 100} if (obj.a == null) { } // 相当于,if (obj.a === null || obj.a === undefinded) {}
-
逻辑判断
-
console.log(10 && 0) //0 console.log('' || 'abc') // 'abc' console.log(!window.abc) // true
-
1.6 类型判断 -instanceof
instanceof
的实现原理为:判断一个实例属于不属于一个类型,当根据实例的隐式原型逐层寻找时,隐式原型形成的原型链所涉及到的类,实例都是属于的。
[] instanceof Array //true
[] instanceof Object //true
{} instanceof Object //true
1.7 原型
__proto__
:隐式原型
prototype
:显示原型
当一个类继承另一个类时,父类的显式原型与子类的隐式原型是相同的。
- 每个
class
都有显示原型prototype
- 每个实例都有隐式原型
__proto__
- 实例的
__proto__
指向对应class
的prototype
class Person{
constructor(namee,age,language){
this.namee = namee
this.age = age
this.language = language
}
speak() {
console.log(`我${this.namee}能说${this.language}`)
}
}
class Student extends Person {
constructor(namee,age,language,subject){
// 父类的构造函数参数
super(namee,age,language)
this.subject = subject
}
listen() {
console.log(`${this.namee}喜欢听${this.subject}`)
}
}
let xialuo = new Student('夏洛',25,'中文','语文课')
xialuo.listen()
console.log(xialuo instanceof Person)//true
console.log(Student.prototype.__proto__ === Person.prototype) //true
console.log(xialuo.hasOwnProperty('speak')) // 键名需要用单引号引 false,hasOwnProperty 判断的属性是否属于当前对戏
基于原型的执行规则:
- 获取属性或执行方法时。
- 现在自身属性和方法寻找
- 如果找不到自动去
__proto__
中查找
注:
class
是ES6
语法规范,由ECMA委员会发布
ECMA
只规定语法规则,即我们代码的书写规范,不规定如何实现
1.8 手动封装一个 JQuery
本质上就是一个jQuery对象+js中的DOM-API。
class jQuery {
constructor(selector) {
const result = document.querySelectorAll(selector)
const length = result.length
for (let i = 0; i < length; i++) {
this[i] = result[i]
}
this.length = length
this.selector = selector
//类似数组的形式,实际是对象,jQuery的对象
}
get(index) {
return this[index]
}
each(fn) {
for (let i = 0; i < this.length; i++) {
const elem = this[i]
fn(elem)
}
}
on(type, fn) {
return this.each(elem => {
elem.addEventListener(type, fn, false)
})
}
}
// 插件,扩展性的一种方式,向jQuery对象的显示原型中直接添加属性或方法
jQuery.prototype.dialog = function (info) {
alert(info)
}
// 复写机制(造轮子)
// 基于jQuery写
class myjQuery extends jQuery {
constructor(selector) {
super(selector)
}
}