原型继承和 Class 继承
原型如何实现继承?Class 如何实现继承?Class 本质是什么?
class
,其实在 JS中并不存在类
,class 只是语法糖
,本质还是函数
.
class Person { }
Person instanceof Function
组合继承(利用原型)
function Parent ( value ) {
this . val = value
}
Parent . prototype. getValue = function ( ) {
console. log ( this . val)
}
function Child ( value ) {
Parent . call ( this , value)
}
Child . prototype = new Parent ( )
const child = new Child ( 1 )
child. getValue ( )
child instanceof Parent
核心是子类的构造函数中 通过 Parent.call(this) 继承父类的属性 ,然后改变子类的原型为 new Parent() 来继承父类的函数。 优点:构造函数可以传参,不会与父类引用属性共享,可复用父类的函数, 缺点:在继承父类函数的时候调用了父类构造函数,导致子类原型上多了不需要的父类属性,存在内存上的浪费。
寄生组合继承(利用原型)
function Parent ( value ) {
this . val = value
}
function Child ( value ) {
Parent . call ( this , value)
}
Parent . prototype. getValue = function ( ) {
console. log ( this . val)
}
Child . prototype = Object. create ( Parent . prototype, {
constructor : {
value : Child,
enumerable : false ,
writable : true ,
configurable : true
}
} )
const child = new Child ( 1 )
child. getValue ( )
child instanceof Parent
寄生组合继承的核心将 父类的原型赋值给子类,将构造函数设置为子类,即解决了无用的父类属性问题,还能正确的找到子类的构造函数。
Class 继承
ES6中,class 实现继承,新的实现方式
class Parent {
constructor ( value ) {
this . val = value
}
getValue ( ) {
console. log ( this . val)
}
}
class Child extends Parent {
constructor ( value ) {
super ( value)
this . val = value
}
}
let child = new Child ( 1 )
child. getValue ( )
chiild instanceof Parent
原型、原型链、有什么特点
原型:每一个构造函数都有一个prototype属性指向一个对象,这个对象就是构造函数实例的原型。
原型链:每一个实例都有一个__proto__属性指向原型对象,来获取原型对象上的属性和方法,原型对象身上也有一个__proto__属性指向另外一个原型对象,依次类推,直到原型链的最终端 null为止,这个串成链的过程称之为原型链。
特点:实现继承一个对象可以拿到另一个对象上的属性和方法。
如何解释javascript中的作用域和变量声明提升
js中声明的变量不是一直都有作用的,它有起作用的区域
,这个区域称之为作用域,规定了如何查找变量,当前执行代码对变量的访问权限
。
变量提升
,可以理解为所有的 声明 都会被“移动”到各自作用域的最顶端。
谈谈this对象的理解,call和apply()的区别
call
和apply
的区别在于传入参数的不同;第一个参数都是,指定函数体内this的指向;
第二个参数开始不同,apply是传入带下标的集合
,数组或者类数组,apply把它传给函数作为参数,call从第二个开始传入的参数是不固定
的,都会传给函数作为参数。call传入参数的格式正是内部所需要的格式.
js的 typeof 返回有哪些数据类型?
string number Boolean undefined object function symbol
什么是闭包?为什么要用它?
一般来讲 如果一个内部函数可以访问到外部函数作用域的变量,就称之为闭包。
使用闭包,一是读取
函数中的变量,二可以将函数中的变量存储
在内存中,保护变量不被污染
。由于存储在内存中,会对内存有消耗
,故不能滥用闭包,造成内存泄漏
,要及时释放
内存,将内层函数对象的变量赋值为null
可释放
原理 函数执行有关
函数执行分成两个阶段(预编译阶段和执行阶段)。
在预编译
阶段,如果发现内部函数使用了外部
函数的变量
,则会在内存中创建一个“闭包”对象
并保存对应变量值,如果已存在“闭包”,则只需要增加对应属性值即可。 执行完
后,函数执行上下文
会被销毁,函数对“闭包”对象的引用也会被销毁,但其内部函数还持用该“闭包”的引用,所以内部函数可以继续使用“外部函数”中的变量利用了函数作用域链
的特性,一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕,其执行作用域链销毁,但因内部函数的作用域链仍然在引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被烧毁后才被销毁。
优点
可以从内部函数访问外部函数的作用域中的变量,且访问到的变量长期驻扎在内存中,可供之后使用。 避免变量污染全局。 把变量存到独立的作用域,作为私有成员存在。
缺点
因为存在内存中 内存消耗较大 易泄漏。 对处理速度具有负面影响,层级决定了引用的外部变量在查找时经过的作用域链长度。 可能获取到意外的值。
场景一
模块封装,在模块规范出现之前,都是用下面方式防止变量污染
var test = ( function ( ) {
var foo = 0 ;
function test ( ) { }
test. prototype. bar = function bar ( ) {
return foo;
} ;
return test;
} ( ) ) ;
场景二
在循环中创建闭包,防止取到意外的值
for ( var i = 0 ; i< 3 ; i++ ) {
document. getElementById ( 'id' + i) . onfocus = function ( ) {
alert ( i)
}
}
makeCallback ( ) {
return function ( ) {
alert ( num)
}
}
for ( var i = 0 ; i< 3 ; i++ ) {
document. getElementById ( 'id' + i) . onfocus = makeCallback ( i)
}