问题

获取页面元素的位置方式

通过累加offset的方式来获取坐标

//取得元素x坐标  
function pageX(elem) {  
    return elem.offsetParent?(elem.offsetLeft+pageX(elem.offsetParent)):elem.offsetLeft;  
}  
复制代码
  1. 通过最新的函数getBoundingClientRect()直接获取left,top,bottom,right位置

函数原型与原型链

function Person() {
    
}
let person = new Person
复制代码

实例person对象通过__proto__ 获取实例原型或者通过Object.getProtoTypeOf() 最终找寻到null,形成一条完整的原型链

person.__proto__ = Person.protoType
Person.protoType.__proto__ = Object.protoType
Object.protoType.__proto__ = null
复制代码

函数通过prototype获取到原型 原型通过contructor获取到构造函数

Person.protoType.contructor = Person
复制代码

使用原型的方式挂载函数,并不会增加实例负担,生成的实例上并没有对应的函数,仅仅使用的时候会关联到原型上,不用而外为每个实例开辟对应的函数存储空间。

闭包与执行上下文的关系

function bar() {
    var a = 10
    function foo() {
        console.log(a)
    }
    return foo
}
bar()()
复制代码

执行上下文操作:

全局上下文压栈

stack= [globalContext]

bar 压栈

stack = [ globalContext, barContext ]

bar 退栈

stack= [ globlcontext ]

foo 压栈

stack = [

globalContext,

foo

]

foo 退栈 输出a

stack= [ globalContext ]

全局上下文退栈 stack=[],执行结束

执行期间,虽然bar中变量a被foo持有,从而延长到foo退栈才销毁,但是bar上下文的生存时间并没有延长,在执行完成后便直接退栈

连等赋值问题

var a = {n: 1};
var b = a;
a.x = a = {n: 2};

a.x     // 这时 a.x 的值是多少
b.x     // 这时 b.x 的值是多少
复制代码

正确的答案是a.x结果为undefined,b.x结果是{n:2}

首先:

var a, b
a = b = {n:1}
a // {n:1}
b // {n:1}
复制代码

证明连等操作执行从右至左

原因:在执行连等操作的时候,会开启一份副本来执行赋值操作

//a.x=a={n:2}  从运算符优先级判断 先执行a.x ,再从右到左执行=
a.x // a.x 中的a地址被单独记录,即可以看做{n:1}.x
a = {n:2} // 将a指向{n:2},a.x中的a仍然是{n:1}
a.x = a// 修改a后,a.x内存地址已经被记录副本中,因此a.x中的a地址仍旧是{n:1}对象地址,不受影响,可以看成{n:1}.x={n:2}
a // {n:2}
b // {n:1,x:{n:2}},b仍然指向{n:1}

复制代码

垃圾回收

现在浏览器一般不再使用引用计数的方式判断对象是否应该回收,避免了循环引用造成的内存泄露。使用标记清除的方式来判断,从根部出发定时扫描对象,那些无法达到的对象标记为不再使用,清除。

从ES5规范判定this指向

在规范中有一种只存在于规范的类型Reference,只存在于规范中的抽象类型,不存在于实际的js中。 Reference由三部分组成:

-base value

-reference name

-strict reference

base value 指的是属性所在对象或者环境记录,值可以是undefined,object,Boolean,string,number,environmentRecord, reference name指属性名称。

var foo = 1
// 对应的Reference是:
var fooReference = {
    base: EnvironmentRecord,
    name: 'foo',
    strict: false
};
var bar = {
    fn: funtion() {
        return this
    }
}
// fn对应的Reference是:
var BarReference = {
    base: bar,
    propertyName: 'fn',
    strict: false
};
复制代码

规范中有两种获取reference组成的方法,GetBase和IsPropertyReference,GetBase可以获得base value内容,IsPropertyReference可以用来判断reference中的base value是否为一个对象。 GetValue则是一个通过reference类型获取其真实内容的函数,返回值是一个具体的值,不再是reference类型

var foo = 1
// 对应的Reference是:
var fooReference = {
    base: EnvironmentRecord,
    name: 'foo',
    strict: false
};
GetValue(fooReference) // 1
复制代码

通过规范确定this可以通过这几步:

1.计算MemberExpression的结果给ref,memberExpression的表现形式

-PrimaryExpression // 原始表达式

-FunctionExpression // 函数表达式

-MemberExpression[Expression] // 属性访问

-MemberExpression.IdentifierName // 属性访问点语法

-new MemberExpression Arguments // 对象创建表达式

也可以简单说是()左边的部分,例如foo()中的foo或者foo.bar()中的foo.bar

2.判断ref是否是一个Reference类型

3.1 如果IsPropertyReference(ref)是true,那么this的值为GetBase(ref),也就是ref的base value

3.2 如果base value是一个environment Record,那么this的值为 ImplicitTHisvalue(ref),ImpliciThisValue值恒为undefined

3.3 如果不是Reference,那么this的值为undefined

案例分析:

var value = 1;

var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}
//示例1
console.log(foo.bar());
//示例2
console.log((foo.bar)());
//示例3
console.log((foo.bar = foo.bar)());
//示例4
console.log((false || foo.bar)());
//示例5
console.log((foo.bar, foo.bar)());
复制代码

示例1:

memberExpression是foo.bar,属性访问表达式,bar的Reference:

var Reference = {
  base: foo,
  name: 'bar',
  strict: false
};
复制代码

IsPropertyReference(ref)是true,this是foo,所以输出2

示例2:

(foo.bar)跟foo.bar一样

(foo.bar = foo.bar)()
看示例3,有赋值操作符,查看规范 11.13.1 Simple Assignment ( = ):

计算的第三步:

3.Let rval be GetValue(rref).

因为使用了 GetValue,所以返回的值不是 Reference 类型,

按照之前讲的判断逻辑:

2.3 如果 ref 不是Reference,那么 this 的值为 undefined

this 为 undefined,非严格模式下,this 的值为 undefined 的时候,其值会被隐式转换为全局对象。

(false || foo.bar)()
看示例4,逻辑与算法,查看规范 11.11 Binary Logical Operators:

计算第二步:

2.Let lval be GetValue(lref).

因为使用了 GetValue,所以返回的不是 Reference 类型,this 为 undefined

(foo.bar, foo.bar)()
看示例5,逗号操作符,查看规范11.14 Comma Operator ( , )

计算第二步:

2.Call GetValue(lref).

因为使用了 GetValue,所以返回的不是 Reference 类型,this 为 undefined
复制代码

示例:

foo(),memberExpression是foo,reference为:

var Reference = {
    baseValue:environmentRecord
    name:foo
    strict:false
}
复制代码

根据3.2,如果返回environmentRecord,使用impliciThisValue返回undefined,非严格指window

CONST

const保证的并不是变量值不能改动,而是变量所指的内存地址保存的数据不得改动。

对应基本类型,值就保存在变量指向的地址中,因此此时变量内容等同常量,不可修改。但是对于对象,变量保存地址仅仅是指向数据的指针,const仅仅保证了指针不可变动,内容数据改变不能控制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值