/*
01 代码段
每一个:<script></script>标签都是一个代码断:
js执行是从上到下一个一个代码段执行
下面的script标签可以访问上面script标签的属性和方法
上面的script标签不能访问下面script标签的属性和方法
上面的代码段报错不会影响下面的代码段的执行,代码段是独立运行的
*/ -->
<!-- /*
02 代码运行
02-1 代码预解析:
var的全局变量提升到代码的最前面,只声明不赋值。
function声明的函数将会把整体函数提升到最前面,函数表达式不存在函数提升的问题
特别注意:
02-1-1:如果函数声明的变量名和function的函数名同名的情况下,无论是函数在var的前面还是函数在var的后面,结果都是函数整体会覆盖var声明的变量
02-1-2:函数体内部:同样也存在变量提升的问题
02-1-3:在判断体内 条件成立和不成立中被var声明的变量也都会存在变量提升的机制
02-1-4:在判断体内 条件成立和不成立 function声明的函数,只存在声明提升,不存在整体的函数体提升
02-1-5:在函数体内 没有用var声明的变量的值,属于全局window的属性。
02-2 数据存储:
栈内存:ECS(ECG+EC(fn)):基本数据类型 和 引入数据类型的十六进制的地址存储在栈区
堆内存: 引用数据类型存储在堆内存呢
代码块函数执行:会在栈内存进入入栈,等函数执行完如果不被外部的函数引用函数在执行完就会被释放,如果被外部的变量引用那么就不会被释放掉
02-3 立即执行函数:
立即执行函数中的this指向window
立即执行函数中打印函数名得到是的函数体本身
立即执行函数中需要使用var声明的和函数体同名的变量才能将函数本身进行覆盖,
立即执行函数如果不使用var声明的变量和函数体相同,不会覆盖函数体本身
02-4 全局代码和局部代码
当全局代码执行就会产生全局执行上下文,当函数调用,就会产生局部的执行上下文
执行上下文就要入栈,栈也是一种数据结构,先进后出
ESC:Excute Context Stack ===》 ESC 里面放EC
EC的作用:在代码的执行过程中,给代码提供数据。EC都有一个VO,在ECG中VO指GO,在普通EC中 VO值AO
GO:全局对象(Global object), VO:变量对象(Verible Object), AO:活动对象(Active Object)
GO:代表的是window; VO:代表的是产生执行上下文环境中的变量和函数声明;AO:代表的是函数被调用的时候产生的私有上下文中的变量和函数体内部的函数声明(形参+实参+局部变量+内部函数)
*/ -->
<!-- /*
03 作用域链:
03-1 基本数据与引用数据的原型链:
每一个基本数据类型或者引用数据类型:本身都有一个__proto__的属性,
该数据类型的__proto__属性指向实例属性的prototype
每一个基本数据类型的__proto__属性的constructor的属性指向了该属性实例的本身
const fn = ()=>{console.log('111')}
console.log(fn.__proto__) // f(){}
console.log(fn.__proto__===Function.prototype) // true
console.log(fn.__proto__.__proto__.constructor) //f object(){}
03-2 构造函数的原型链:
function Fn(name,age){
this.name = name
this.age = age
this.fn=function(){
console.log(this.name)
}
}
Fn.prototype.c = 20
Fn.prototype.obj = {
name:'zs',
fn:function(){
console.log(this.name,this.age)
}
}
const a = new Fn('zs',12)
console.log(Fn.prototype.__proto__==Object.prototype) //true
console.log(a.__proto__==Fn.prototype) // true
console.log(a.hasOwnProperty('c')) // false 检测是否是自己的私有属性
console.log(a.obj.fn()) // zs undefiend this指向的是函数前面的那个调用者
*/ -->
<!-- /*
04 this
在产生执行上下文的时候 会动态产生this, 谁调用函数this指向谁,默认调用指向window
*/ -->
<!-- /*
05 关于原型对象
面试题:
let a = {}, b = {a:1}, c={a:2};
a[b] = 'ok' a[c] = 'bad'
console.log(a[b]) // 得到的结果是bad
原因:因为对象中是如何直接以对象为键存储值的,如果以对象为键存储的都会转化为
let a = {[objct object]:'ok', [object object]:'bad'} // 因为键为对象会调用toshring的方法
console.log({name:'zs'}.toString())// [object object]
*/ -->
<!-- /*
06 原型继承的三种方式:
06-1 原型链继承: 缺点:如果继承的父类其中一个属性是引用数据类型的话,其中一个实例对象进行修改 其他的实例对象的值也会发生变化
function Fn1 (){
this.name = 'ls'
this.age = 12
}
function Fn2(sex){
this.sex = sex
}
Fn2.prototype = new Fn1()
console.dir(new Fn2('男'))
06-2 组合式继承:
function Fn1 (name,age){
this.name = name
this.age = age
}
function Fn2(sex){
Fn1.call(this,'zhao',12)
this.sex = sex
}
Fn2.prototype = new Fn1()
console.dir(new Fn2('男'))
06-3 使用object.create()继承对象的原型链:
function Fn1 (name,age){
this.name = name
this.age = age
}
function Fn2(sex){
Fn1.call(this,'zhao',12)
this.sex = sex
}
Fn2.prototype = object.create(Fn1)
/*-->
<!-- /*
07 class类的继承,使用extends继承;
07-1 类的构造函数使用extends继承:
class Person{
constructor(name,age){
this.name = name
this.age = age
}
asy(){
console.log(this.name)
}
}
class Express extends Person{
constructor(sex){
super('zs',12)
this.sex = sex
}
hi(){
console.log('123')
}
}
console.dir(new Express('男'))
07-2 手写new构造函数:
function Fn(callback,...args){
const obj = {}
obj.__proto__ = callback.prototype
callback.apply(obj,args)
return obj
}
*/ -->
<!-- /*
08 手写new的实现:
08-1 在构造器中 如果返回的是基本数据类型相当于什么都没有返回,如果返回的是引入数据类型那么new出来的实例对象就是返回的引用数据了
function Dog(){
return {name:'旺财'}
}
const dog = new Dog()
console.log(dog) // {name:'旺财'}
function Dog(){
return function (){
console.log('asas')
}
}
console.log(new Dog()) // function(){conole.log('asas')}
08-2 手写new的构造函数
function _new(callback,...args){
const obj = {}
obj.__proto__=callback.prototype
callback.apply(obj,args)
return obj
}
// 简化上面的写法
unction _new(callback,...args){
const obj = object.create(callback)
callback.apply(obj,args)
return obj
}
// 最后版本兼顾返回值有引入数据类型的情况
function _new(callback,...args){
if(!callback.hasOwnProperty('prototype')){
throw new TypeError('callback is not a constrouctor')
}
const obj = object.create(callback)
const result = callback.apply(obj,args)
if((typeof result !==null)&&(typeof result == 'object')){
return result
}
return obj
}
*/ -->
<!-- /*
09 手写call方法
;(function(){
function myCall(obj){
// 第一步 判断obj是否存在 如果存在 并且obj是字符串 那么就包括成对象的字符串 如果不存在就是window
const context = obj? Object(obj):window
// 第二步 获取所有传递进来的参数 然后将参数给到调用的mycall的方法
// 因为call第一个参数是this执行的对象 所以传递给函数的参数要从第二个截取
const args = Array.from(arguments).splice(1)
//谁调用call这个方法this指向谁 这是将this函数挂载在这个对象f的属性上面
context.f = this
// 调用这个this的方法 并把参数进行传递
let res = context.f(...args)
delete context.f
return res
}
Function.prototype.myCall = myCall
})()
*/ -->
<!-- /*
10 封装检测数据的方法
10-1
typeof 检测方法 可以检测 字符串 数字 undefiend symbol 大数 function
10-2
instanceof 检测某个对象是否是某个类的实例:
console.log(123 instanceof Number) false
console.log(new Number(123) instanceof number) true
console.log([] instanceof object) true
console.log({} instanceof object) true
10-3
constructor用来检测某个实例对象的constructor是否执行构造函数
console.log(new Number(123).constructor === Number) // true
console.log(123.constructor === Number) // 报错
console.log({}.constructor===Object) // true
console.log([].constructor===Array) // true
10-4
object.prototype.toString.call(xxx) // [object xxx]
*/ -->