BAT笔试题中几道关于堆栈内存和闭包作用域的问题
let a = {}, b = '0', c = 0;
a[b] = 'JavaScript';
a[c] = 'HTML+CSS';
console.log(a[b]); //HTML+CSS
//原因:对象中属性名不能重复,一般都为字符串属性,字符串属性名跟数字属性名是一样的
let a = {}, b = Symbol('1'), c = Symbol('1');
a[b] = 'JavaScript';
a[c] = 'HTML+CSS';
console.log(a[b]);//JavaScript
//Symbol的特点是:创建的唯一值。Symbol('1')与Symbol('1')是不相等的
let a = {},
b = {
n: '1'
},
c = {
m: '2'
}
a[b] = 'JavaScript';
a[c] = 'HTML+CSS';
console.log(a[b]);//HTML+CSS
//对象做属性名时会通过.toString方法被转换为字符串,而对象转换为字符串后都是"[object, Object]"
// 所以b和c转换为字符串后是一样的。
var test = (function(i){
return function(){
alert(i*=2);// alert输出结果都会转为字符串
}
})(2)
test(5); // '4'
//首先是创建一个自调用函数,在函数中又返回一个函数,这里有闭包产生。
//立即执行函数接收的实参是2,然后返回一个函数。
//这时test是一个无参函数,函数体就是alert(i*=2),由于闭包作用这里的i是立即执行函数的参数i,而立即执行函数执行时传入的参数是2
//当调用test函数时虽然传了个参数5,但由于test是一个无参函数,因此5没有任何作用
//所以最终结果是4,而又因alert会把内容转换为字符串,所以最终alert的是字符串4
var a = 0, b = 0;
function A(a){
A = function(b){
alert(a+b++);
}
alert(a++)
}
A(1); // "1"
A(2); // "4"
对象(数组)的深克隆和浅克隆(头条)
let obj = {
a: 100,
b: [10, 20, 30],
c: {
x: 10
},
d: /^\d+S/
};
let arr = [10, [100, 200], {
x: 10,
y: 20
}];
//=>浅克隆
//es6
let obj2 = {...obj};
//es5
let obj2 = {}
for(let key in obj){
if(obj.hasOwnProperty(key)){
obj2[key] = obj[key];
}
}
//=>深克隆
//let obj2 = JSON.parse(JSON.stringify(obj));//先转成json字符串再转成对象,但是如果对象内部有函数,正则或日期则转换时会有问题
function deepClone(obj){
if(obj === null) return null;
if(typeof obj !== "object") return obj;
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Date) return new Date(obj);
let cloneObj = new obj.constructor;
for(let key in obj){
if(obj.hasOwnProperty(key)){
cloneObj[key] = deepClone(obj[key]);
}
}
return cloneObj;
}
let obj2 = deepClone(obj);
一道关于面向对象面试题引发的血案(阿里)
function Foo(){
getName = function(){
console.log(1);
};
return this;
}
Foo.getName = function(){
console.log(2);
}
Foo.prototype.getName = function(){
console.log(3);
}
var getName = function(){
console.log(4);
};
function getName(){
console.log(5);
}
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3

一道面试题让你彻底掌握JS中的EventLoop(头条)
async function async1(){
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2(){
console.log('async2');
}
console.log('script start');
setTimeout(function(){
console.log('setTimeout');
},0);
async1();
new Promise(function(resolve){
console.log('promise1');
resolve();
}).then(function(){
console.log('promise2');
});
console.log('script end');

function A(){
alert(1);
}
function Func(){
A = function(){
alert(2);
}
return this;
}
Func.A = A;//相当于 Func.A = function(){alert(1)}
Func.prototype = {
A: () => {
alert(3);
}
}
A();//1
Func.A();//1
Func().A();//2 先调用Func函数,重写全局函数A并返回this(window),然后执行window.A(),此时A已经被重写,所以输出2
new Func.A();//1
new Func().A();//3 相当于实例.A(),所以去原型里找,输出3
new new Func().A();//报错,原因是原型中的A是箭头函数,不支持new
var x = 2;
var y = {
x: 3,
z: (function(x){
this.x *= x;
x += 2;
return function(n){
this.x *= n;
x += 3;
console.log(x);
}
})(x)
};
var m = y.z;
//y.z是自调用闭包函数,z函数自调用时传出的参数x值为全局x的值2,在函数内部执行x+=2后x变为4,然后返回一个函数。当调用m(4)时,实际上调用的是z返回的函数,此时n为4,x也为4,在执行x += 3后变为7所以输出7
m(4);//7
//当执行y.z(5)时,n的值为5,this.x *= n中this.x指的是y对象的x属性,值为3,执行*=n后变为15,
//而函数中的x来自上级作用域中的x值为7,在执行完 +=3后变为10所以紧跟着console.log输出10
y.z(5);//10
//在执行完m(4)时window.x变为16, 而y.x在执行y.z(5)后变为15
console.log(x, y.x);// 16, 15
var x = 0, y = 1;
function fn(){
x += 2;
fn = function(y){
console.log(y + (--x));
}
console.log(x, y);
}
fn(3);//2,1 1.执行代码在fn中对x进行+=2操作,x变为2,2. fn重新指向另一个函数,3.输出x和y的值2,1
fn(4);//5 fn已经指向另一个函数即console.log(y + (--x));y为传入的参数4,x则为上级作用域中的x值为2,自减后变为1 所以输出4+1=5
console.log(x, y);//1,1 执行完上两个步骤后x变为1,全程未对全局变量y操作,所以y依然是1
setTimeout(() => {
console.log(1);
}, 20);
console.log(2);
setTimeout(() => {
console.log(3);
}, 10);
console.log(4);
console.time("AA");
for(let i = 0; i < 90000000; i++){
//do somthing这里为了代码阻塞
}
console.timeEnd('AA');
console.log(5);
setTimeout(() => {
console.log(6);
}, 8);
console.log(7);
setTimeout(() => {
console.log(8);
}, 15);
console.log(9);
//结果输出:
// 2 4 时间长 5 7 9 3 1 6 8
//在代码从上到下执行时优先执行console.log/time/timeEnd,然后将setTimeout添加到宏任务列队中,在for循环阻塞前先加了两个setTimeout,阻塞后又加了2个。所以在主栈代码执行完成后开始执行列队中的任务,因为阻塞前的先添加进去的所以优先按顺序执行,然后再执行阻塞后的即后添加到列队中的。
// 当a为何值时,下面的条件能够成立
var a;
if(a == 1 && a == 2 && a == 3){
console.log('条件成立');
}
//在==进行比较时,对象会调用自身的toString方法转换为字符串后再转换为数字进行比较,所以可以利用这一点对toString进行重写以达到目的
//1. 每比较一次都会调用一次toString,i就会加1,从而使条件成立
var a = {
i: 0,
toString: function(){
return ++i;
}
}
//2. 利用数组的shift和对象的toString
var a = [1, 2, 3];
a.toString = a.shift;
//3. 利用Object.defineProperty()来监听window对象的a属性并重写get方法
//这里不用a是因为在get中进行自加时又会调用get方法导致死循环
var i = 0;
Object.defineProperty(window, 'a', {
get: function(){
return ++i;
}
});
还没有评论,来说两句吧...