这是我参与 8 月更文挑战的第 9 天,活动详情查看: 8月更文挑战
变量类型和计算
typeof能判断哪些类型
- 识别所有值类型
- 识别函数
- 判断是否是引用类型(不可再细分)
//判断所有的值类型
typeof undefined // undefined
typeof 'abc' // string
typeof 123 // number
typeof true // boolean
typeof Symbol('sdd') // symbol
//能判断函数
typeof console.log // function
typeof function(){} // function
//能识别引用类型(不能再细分)
typeof null // object
typeof [1,2] // object
typeof {a:123} // object
何时使用===,何时使用==
==抽象相等,比较时,会隐式进行类型转换,再进行值比较===严格相等,会比较两个值的类型和值
值类型和引用类型的区别
值类型:基本类型,Number,String,Boolean,undefined,Null(指向空指针,特殊的引用类型),Symbol,BigInt引用类型: Object,Array,Function,Date,Map,Set,WeakSet,WeakMap
| 区别 | 值类型 | 引用类型 |
|---|---|---|
| 存储位置 | 栈中 | 堆中(变量名在栈内存中,变量值在堆内存中) |
| 占用空间 | 固定 | 不固定 |
| 赋值方式 | 拷贝变量内容 | 拷贝引用地址 |
| 动态属性 | 不能添加属性 | 可动态添加属性 |
| 检测方法 | typeof | instanceof |
变量计算--强制类型转换
- 字符串拼接
- ==
//除了 ==null 之外,其它都一律使用 === ,如 let obj = {x:100} if(obj.a == null){} //相当于: if(obj.a == null || obj.a == undefined){} - if语句和逻辑运算
- 判断true/false
//以下是falsely变量,除此之外都是truly变量 !!0 === false !!NaN === false !!'' === false !!null === false !!undefined === false !!false === false
// 字符串拼接
var a = 100 + 10 //100
var b = 100 + '10' //10010
var c = true + '10' // true10
// == 运算符
100 == '100' //true
0 == '' //true
0 == false // true
false == '' // true
null == undefined //true
[10] == 10 // true
[] == 0 // true
[] == false // true
![] == false // true
null == false // false
// 语句
var a = true
if(a){}
var b = 100
if(b){} // 把数字转换为true
var c = ''
if(c){} // 把空字符串转换为false
// 逻辑运算
console.log(10&&0); // 0 把10转换成true
console.log('' || 'abc'); // 'abc' 把空字符串转换为false
console.log(!window.abc); // window.abc是undefined 把非undefined转换成true
//判断一个变量会被当做true还是false
var a = 100
console.log(!!a); // true
手写深拷贝
原型和原型链
class和继承
class
- constructor
- 属性
- 方法
// 类
class Student{
constructor(name,age){
this.name = name
this.age = age
}
sayHi(){
console.log(`姓名: ${this.name}, 年龄: ${this.age}`)
}
}
// 通过类new 对象/实例
const pp = new Student('小鱼',18)
console.log(pp.name,pp.age) // 小鱼 18
pp.sayHi() // 姓名: 小鱼, 年龄: 18
const cc = new Student('小C',16)
console.log(cc.name,cc.age)
cc.sayHi()
- 每个class都有显示原型 prototype
- 每个实例都有隐式原型 proto
- 实例的 proto 指向对应的class的prototype
执行规则
- 获取属性pp.name 或 执行方法 pp.sayHi()时
- 先在自身属性和方法寻找
- 如果找不到则 自动去 __proto__中查找
// class 实际上是函数,是语法糖
typeof People // function
typeof Student // function
// 隐式原型和显示原型
pp.__proto__ //隐式原型
Student.prototype // 显示原型
pp.__proto__ === Student.prototype // true
Student.prototype.__proto__
People.prototype
People.prototype === Student.prototype.__proto__ // true
继承
- extends
- super (父类)
- 扩展和重写
// 父类
class People{
constructor(name){
this.name =name
}
eat(){
console.log(`${this.name} eat something`)
}
}
// 子类
class Student extends People{
constructor(name,age){
super(name)
this.age = age
}
sayHi(){
console.log(`姓名: ${this.name}, 年龄: ${this.age}`)
}
}
// 子类
class Teacher extends People{
constructor(name,major){
super(name)
this.major = major
}
teach(){
console.log(`${this.name} 教授 ${this.major}`)
}
}
const pp = new Student('小鱼',18)
console.log(pp.name,pp.age) // 小鱼 18
pp.sayHi() //姓名: 小鱼, 年龄: 18
pp.eat() // 小鱼 eat something
//实例
const lu = new Teacher('陆老师','语文')
console.log(lu.name,lu.major) // 陆老师 语文
lu.teach() // 陆老师 教授 语文
pp.eat() // 陆老师 eat something
instanceof
// 参照上面继承
pp instanceof Student // true
pp instanceof People // true
pp instanceof Object //true
[] instanceof Array // true
[] instanceof Object // true
{} instanceof Object // true
题目
如何判断数组
Object.prototype.toString.call()Array.isArrray()instanceof: 判断一个变量是否某个对象的实例Array.prototype.isPrototypeOf: 利用isPrototypeOf()方法,判定Array是不是在obj的原型链中constructor: 返回对创建此对象的数组函数的引用,就是返回对象相对应的构造函数
function isArray(obj){
// return Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
return Object.prototype.toString.call(obj) === '[object Array]';
}
function isArray(obj){
return Array.isArrray(obj);
}
function isArray(obj){
return obj instanceof Array
}
function isArray(obj){
return obj.constructor === Array
}
function isArray(obj){
return Array.prototype.isPrototypeOf(obj)
}
手写jquery
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
}
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)
})
}
//扩展很多DOM API
}
// 插件
jQuery.prototype.dialog = function(info){
alert(info)
}
//造轮子
class myJQuery extends jQuery{
constructor(selector){
super(selector)
}
//扩展自己的方法
addClass(className){
}
}
//调用demo
const $p = new jQuery('p')
$p.get(1)
$p.each(elem=>console.log(elem.nodeName))
$p.on('click',()=>alert('clicked'))
$p.dialog('test')
作用域和闭包
作用域
- 全局作用域
- 函数作用域
- 块级作用域
自由变量
- 一个变量在当前作用域没有定义,但被使用了
- 向上级作用域,一层一层依次寻找,直到找到为止
- 如果到全局作用域都没有找到,则报错 XX is not defined
闭包 作用域应用的特殊情况,有2种表现:
- 函数作为参数被传递
- 函数作为返回值被返回
自由变量的查找: 是在
函数定义的地方,向上级作用域查找; 不是在执行的地方!!!
//函数作为返回值
function create(){
let a = 100
return function(){
console.log(a)
}
}
const fn = create()
let a = 200
fn() // 100
//函数作为参数
function print(fn){
let a = 200
fn()
}
let a = 100
function fn(){
console.log(a)
}
print(fn) //100
this在不同场景,如何取值
this取值,是在
函数执行的时候确认,不是在函数定义时确认
- 作为普通函数
- 使用 call apply bind
- 作为对象方法调用
- 在class方法中调用
- 箭头函数
function fn1(){
console.log(this)
}
fn1() // window
fn1.call({x:100}) // {x:100}
let fn2 = fn1.bind(x:200)
fn2() // {x:200}
const pp = {
name:'pp',
sayHi(){
//this 即当前对象
console.log(this)
},
wait(){
setTimeout(function(){
// this === window
console.log(this)
})
},
wait2(){
setTimeout(() => {
// this 即当前对象
console.log(this)
})
}
}
class People{
constructor(name){
this.name = name
}
sayHi(){
console.log(this)
}
}
const pp = new People('小玉儿')
pp.sayHi() // 指向 pp对象
手写bind函数
function fn1(a,b,c){
console.log('this',this) // this { x:100}
console.log(a,b,c) // 10 20 30
return 'this is fn1'
}
const fn2 = fn1.bind({x:100},10,20,30)
const res = fn2()
console.log(res) // this is fn1
//模拟bind
Function.prototype.bind1 = function(){
//将参数拆解为数组
const args = Array.prototype.slice.call(arguments)
//获取 this(数组第一项)
const t = args.shift()
//fn1.bind(...)中的fn1
const self = this
//返回一个函数
return function(){
return self.apply(t,args)
}
}
实际开发中闭包应用场景
- 隐藏数据
// 闭包隐藏数据,只提供API
function createCache(){
const data = {} // 闭包中的数据,被隐藏,不被外界访问
return {
set: function(key,value){
data[key] = value
},
get: function(key){
return data[key]
}
}
}
const a = createCache()
a.set('a1',100)
console.log(a.get(a1))