类数组
case 1
function test (a, b) {arguments[2] = 3;console.log(arguments.length);console.log(arguments[2]);}test(1, 2);console.log(test.length);// 2 3 2
首先 arguments 是一个类数组,兼顾对象和数组的特性。 arguments[2] 相当于给对象赋值,并不会修改数组的 length属性。
访问 arguments[``2``] 就是获取对象属性,值为3。
case 2
const obj = {
'2': 3,
'3': 4,
push: Array.prototype.push
}
obj.push(1);
console.log(obj.length);
console.log(obj);
// 1 ['0': 1, '2': 3, length: 1, push: Function]
obj对象添加 push方法后,并有了数组的特性,这时可称为类数组(当前没有 length属性)。
调用 push方法添加元素后,发现当前没有 length属性,会为对象添加 length属性,值为 1。
这时,打印对象的 length属性就为 1。
case 3
const obj = {
'2': 3,
'3': 4,
length: 2,
push: Array.prototype.push
}
obj.push(1);
console.log(obj.length);
console.log(obj);
// 3 ['2': 1, '3': 4, length: 3, push: Function]
调用 push 方法时,会添加元素到数组里。
因为数组下标 从 0 开始,当前有两个元素,所以新元素下标 为 2,执行 obj[2] = 1; 。
同时length + 1 为 3。
toString
case 1
({} + {}).length;
// 30
两个对象相加取 length,要使代码有意义。这时 {} 会调用 toString 方法。
即 '[object Object]' + '[object Object]' ,结果为字符串 [object Object][object Object] 。
这时取字符串的 length 为 30。
case 2
([] + []).length;
// 0
数组相加取 length,同样调用自己的 toString方法,相加后为空串,所以 length为 0。
case 3
[1,2,3].toString();
// 1,2,3
case 4
(function () {}).length;
// 0
case 5
({} + (function () {console.log(123)})()).length;
// 123 24
立即执行函数先执行,打印 123。然后会返回 undefined。{} + undefined,会调用 toString方法,即 [object Object]undefined,取其 length为 24。
case 6
var a = {
num: 0,
toString: function () {
return ++this.num;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('you win');
}
要判断一个变量同时满足等于 1,2,3,那么必须针对 a 进行操作。
判断元素相等时,如果类型不同,会进行隐式类型转换,正好借助对象的 toString 方法。
只要保证 JS 在判断相等时,返回不同的值即可。
同理,使用 Array 也可以实现上述效果。
Array.prototype.toString = function () {
this[0]++;
return this[0];
}
var a = [0];
if (a == 1 && a == 2 && a == 3) {
console.log('you win');
}
还可以使用 Object.defineProperty 实现。
let num = 0;
Object.defineProperty(window, 'a', {
get () {
return ++num;
}
});
if (a == 1 && a == 2 && a == 3) {
console.log('you win');
}
use strict
case 1
function Test () {}
Test.prototype.a = function () {
console.log(this);
}
new Test().a.call(null);
new Test().a.call(undefined);
// window window
非严格模式下,调用 call 方法传入 null,undefined,值为 false(JS 引擎认为无意义)。所以 this指向 window。
case 2
'use strict'
function Test () {}
Test.prototype.a = function () {
console.log(this);
}
new Test().a.call(null);
new Test().a.call(undefined);
// null undefined
case 3
function Test () {}
"use strict";
Test.prototype.a = function () {
console.log(this);
}
new Test().a.call(null);
new Test().a.call(undefined);
// window window
use strict 必须写在文件最顶端,或者函数内部顶端。
case 4
function Test () {
"use strict";
Test.prototype.a = function () {
console.log(this);
}
}
new Test().a.call(null);
new Test().a.call(undefined);
// null undefined
case 5
class Test {
a () {
console.log(this);
}
}
new Test().a.call(null);
new Test().a.call(undefined);
// null undefined
class 关键字声明的对象,其内部默认使用严格模式。
JavaScript 不存在类机制,一切基于原型继承(构造函数)。**
prototype
case 1
Object.prototype = {
b: 2
};
var obj = {
a: 1
}
console.log(obj.b);
// undefined
内置原型是不允许修改(重写)的。比如 Array、Object 等。
箭头函数
case 1
const test = () => {
console.log(this);
}
test();
// window
case 2
const test = () => {
const t = () => {
console.log(this);
}
t();
}
test();
new test();
// window 报错
使用箭头函数创建实例时,会报 is not a constructor 。
这里和箭头函数产生的原因有关。箭头函数是为了解决 JS 中 this 指向不稳定而出现的。
箭头函数内部的 this 是稳定的,与父级作用域的 this 保持一致。使用 new 关键字会改变其 this,违背设计初衷。
class
case 1
改写为 class 关键字的形式。
;(function () {
var c = 1;
function Test () {
console.log(c);
}
Test.prototype.a = function () {
Test.b();
}
Test.b = function () {
console.log('I am a static function of Test constructor');
}
window.Test = Test;
})();
const Test = (() => {
let c = 1;
class Test {
constructor () {
console.log(c);
}
a () {
Test.b();
}
static b () {
console.log('I am a static function of Test constructor');
}
}
return Test;
})();
ES3 原型属性对应 class 关键字 内部函数。
ES3 静态属性对应 class 关键字 内部静态(static)属性。
promise
case 1
pormise 产生原因:
promise 是异步程序同步化的解决方案,可以避免异步程序同步化阻塞同步代码执行。
顺便解决了回调地狱问题。promise 多用于内部拆分处理程序,不影响外部代码执行。
