感觉有些题目还是蛮刁钻 经典的。。。
1、JS赋值问题,js赋值是值传递还是引用?
JS有5种基本类型Undefined、Null、Boolean、Number和String,和1种复杂类型Object。
基本类型是值传递,复杂类型引用传递。
// 猜猜看都会输出什么?
1、
var strA ='AAA';
var strB= strA;
strB="BBB";
console.log (strA)
2、var array1 = [1, 2, 3];
var array2 = array1;
array1[0] = 100;
alert(array2);
3、var obj1 = {
"a":1};
var obj2 = obj1;
obj1["a"] = 2;
alert(obj2);
// 思考一下这个噢
4、var a = [1,2,3];
var b = a;
a = [4,5,6];
alert(b);
1、AAA
2、[100, 2, 3]
3、{
"a":2}, 值跟着obj1改变
4、 [1,2,3]
// 关于 4可以看这个文章https://blog.csdn.net/yu121380/article/details/106992674
// a不是修改内部值,而是直接被赋值了,相当于把另一个地址的值赋给了a,所以修改a之后,b还指向原地址,不会变。
2、变量提升、函数变量提升
变量提升一般就提升声明,var声明变量提升到作用域最顶端为undefined,let/const无变量提升。
函数变量提升会整个提升,所以上方的函数可以直接调用下方声明的函数。
// 猜猜会输出什么
1、
var employeeId = "abc123";
function foo() {
employeeId();
return;
function employeeId() {
console.log(typeof employeeId);
}
}
foo();
2、// 变量提升和函数提升一起
function foo() {
employeeId();
var product = "Car";
return;
function employeeId() {
console.log(product);
}
}
foo();
1、function
2、undefined
// Object.keys(仅遍历自身属性,不含继承的),自身属性中也只遍历可枚举的
(function () {
"use strict";
var person = {
names: "John",
};
person.salary = "10000$";
person["country"] = "USA";
person.__proto__.email = 'XXX';
Object.defineProperty(person, "phoneNo", {
vatue: "888888888",
enumerable: false,
});
console.log(Object.keys(person));
})();
// "use strict";唬人的。
// [ 'names', 'salary', 'country' ]
// 注释enumerable: false:结果同上
// 注释enumerable: true:[ 'names', 'salary', 'country', 'phoneNo' ]
关于可枚举属性看ES6这一段
摘要笔记引用如下:
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。描述对象的enumerable属性,称为“可枚举性”,如果该属性为false,就表示某些操作会忽略当前属性。
let obj = {
foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
目前,有四个操作会忽略enumerable为false的属性。
for…in循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。这四个操作之中,前三个是 ES5 就有的,最后一个Object.assign()是 ES6 新增的。其中,只有for…in会返回继承的属性,其他三个方法都会忽略继承的属性,只处理对象自身的属性。
实际上,引入“可枚举”(enumerable)这个概念的最初目的,就是让某些属性可以规避掉for…in操作,不然所有内部属性和方法都会被遍历到。比如,对象原型的toString方法,以及数组的length属性,就通过“可枚举性”,从而避免被for…in遍历到。
4、关于Object.create()和 new Object
Object.create(a)新生成了一个对象,a在这个对象的原型链中,但是这个对象本身为空。
new Object(a)新生成了一个对象,a的属性就是对象的属性,直接继承来了,对象原型链为{}。
具体可以看这里
// new Object() 方式创建
var a = {
rep : 'apple' }
var b = new Object(a)
console.log(b) // {rep: "apple"}
console.log(b.__proto__) // {}
console.log(b.rep) // {rep: "apple"}
// Object.create() 方式创建
var a = {
rep: 'apple' }
var b = Object.create(a)
console.log(b) // {}
console.log(b.__proto__) // {rep: "apple"}
console.log(b.rep) // {rep: "apple"}
// 猜猜会输出什么?
(function () {
var objA = Object.create({
foo: "foo",
});
var objB = objA;
objB.foo = "bar";
delete objA.foo;
console.log(objA.foo);
console.log(objB.foo);
})();
// foo foo
5、== 和 ===
== 代表相同,===代表严格相同,对于基本简单类型,双等于会转换类型比较,三等于不会转换类型比较。复杂类型(对象),只有地址相同才是相同,否则
比较过程:
双等号== :
(1)如果两个值类型相同,再进行三个等号(=== )的比较
(2)如果两个值类型不同,也有可能相等,需根据以下规则进行类型转换在比较:
1)如果一个是null,一个是undefined,那么相等
2)如果一个是字符串,一个是数值,把字符串转换成数值之后再进行比较
3)false和0,true和1可以转换
三等号=== :
(1)如果类型不同,就一定不相等
(2)如果两个都是数值,并且是同一个值,那么相等;如果其中至少一个是NaN,那么不相等。(判断一个值是否是NaN,只能使用isNaN( ) 来判断)
(3)如果两个都是字符串,每个位置的字符都一样,那么相等,否则不相等。
(4)如果两个值都是true,或是false,那么相等
(5)如果两个值都引用同一个对象或是函数,那么相等,否则不相等
(6)如果两个值都是null,或是undefined,那么相等
// 猜猜会输出什么?
1、
(function () {
var objA = Object.create({
foo: "foo",
});
var objB = Object.create(objA);
console.log(objA == objB);
console.log(objA === objB);
})();
2、
(function() {
var objA = Object.create({
foo: 'foo '
});
var objB = objA;
console.log(objA == objB);
console.log(objA === objB);
console.log(objA.toString() == objB.toString());
console.log(objA.toString() === objB.toString());
}());
1、false false
2、true true true true
6、new Array 、 Array.from 、 Array.of
ES6新出的from / of方法,使用方法可以看ES6手册
Array.from可以把数据转换成对象类型,传进任何一个有length属性的对象,转换成数组,可以转换类数组对象,比如arguments/ DOM数组。扩展运算符只能转换可迭代类型。
Array.of主要是解决newArray方法传进不同参数会有不同转换的行为,把不论传多少参数行为都统一成一种输出。
Array.from(Obj);内数据必须是一个包含length属性的对象,比如Array.from(1,2,3)会报错的。
Array.from({
length: 3 });
// [ undefined, undefined, undefined ]
// Array.of 把任何输进去的一个参数作为数组的一个成员。
Array.of() // []
Array.of(undefined) // [undefined]
Array.of([3]) // [[3]]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]
// new Array 参数为单个数字时会输出n个成员的数组,其他和of相同。
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
// 猜猜会输出什么?
1、
(function () {
var array1 = [];
var array2 = new Array(10);
var array3 = Array.of(3);
var array4 = new Array(["1", "2", "3", "4"]);
var array5 = Array.from([1, 2, 3]);
console.log(array1, array2, array3, array4, array5);
console.log(array4.length, array5.length);
})();
2、
(function () {
var array = new Array("a", "b", "c", "d", "e");
array[10] = "f";
delete array[10];
console.log(array,array.length);
})();
// 1、
// [],[<10 empty items>],[3],[['1', '2', '3', '4']],[1, 2, 3]
// 1 3
// 2、['a','b','c','d','e',<6 empty items>],11(新建到11个数,再删掉第10个,已经创建的内存空间还是存在的。
7、Array.filter
1、
(function () {
var containers = [2, 0, false,"", "12", true];
console.log(containers.filter(Boolean));
console.log(containers.filter(Number));
console.log(containers.filter(String));
console.log(containers.filter(Object));
})();
// 答案
[ 2, '12', true ]
[ 2, '12', true ]
[ 2, 0, false, '12', true ]
[ 2, 0, false, '', '12', true ]
// 解析:
// 直接输类型,filter会强转成员为X类型,然后判断这个类型是true/false。
// filter(d=>Number(d)),Number(0)=0,但是filter会认为返回的0(Number)是false。
// filter(d=>String(d)),返回后的'2','0'都认为是字符串。但是''会认为为空,转为false。
// 以下条件会认为flase强转if (false)
if (null)
if (undefined)
if (0)
if (NaN)
if ('')
if ("")
if (``)
2、
(function () {
var greet = "Hello World";
var toGreet = [].filter.call(greet, function (element, index) {
return index > 5;
});
console.log(toGreet);
})();
// ['W','o','r','l','d']
// 字符串的filter遍历,会把每一个字符都认为是一个数据
还有一些不知道怎么定义考点的题目。。
8、this指针 和变量提升和函数提升
this指针
函数提升和变量提升:函数是一等公民,提升在变量之前,但是提升的都只是声明,使用是按原本次序。以及如果函数与变量同名的情况:函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖。
// 猜猜会输出啥
1、
var obj = {
message: "Hello",
innerMessage: !(function () {
console.log(this.message);
})(),
};
console.log(obj.innerMessage);
1、undefined true(如果没有感叹号,输出undefined undefined
// 解析:初始化obj时就会执行innerMessage,函数一等公民,变量提升在变量之前。所以此时的顺序应该是:
// function(){console.log(this.message)}
// var message;
// (function(){})()=>输出undefined
2、
function myFunc() {
console.log(this.message);
}
myFunc.message = "Hi John";
console.log(myFunc());
// undefined undefined
// 解析:因为直接调用对象, 对象默认是window,所以this.message是undefined,无返回值,输出undefined
3、
var employeeId = "aq123";
function Employee() {
this.employeeId = "bq1uy";
}
const emplyee = new Employee();
console.log(Employee.employeeId,emplyee.employeeId);
// undefined bq1uy
// 要看this指向,new的时候,就是由实例对象调用this。但是没有new,直接函数.变量调用,this指向window。var employeeId声明变量是用来迷惑你的,实际上这个变量和window没关系,所以输出的window.employeeId=Employee.employeeId=undefined .
4、函数与变量同名的情况,提升怎么办!?
console.log(foo);
function foo(){
console.log("函数声明");
}
var foo = "变量";
----------------------
function foo(){
console.log("函数声明");
}
var foo = "变量";
console.log(foo);
// 第一个:[function foo] 第二个:变量。
// 函数声明不会被变量声明覆盖,但是会被变量赋值覆盖。
// 第一个相当于变成了这样,第二个类似不写了。
function foo(){
console.log("函数声明");
}
var foo;
console.log(foo);
foo = "变量";
9、函数的长度
function myFunc(...argus) {
console.log(argus.length);
}
function myFunc(parm1,parm2) {
console.log(myFunc.length);
}
console.log(myFunc());
console.log(myFunc("a", "b"));
console.log(myFunc("a", "b", "c", "d"));
// argus.length:0,2,4
// myFunc.length 2,2,2
// 参数的长度就是函数的长度。如果已经定死了有1,2俩参数,那这个函数的长度就是2不会变了。
10、闭包、bind指向问题
1、
function passwordMngr() {
var password = "12345678";
this.userName = "John";
return {
pwd: password,
username:username
};
}
var userInfo = passwordMngr();
console.log(userInfo.pwd,userInfo.userName,userInfo.password);
// 1、12345678 undefined undefined
// 有点像闭包但不是闭包。userInfo就只是一个对象,里面有{pwd: password}
2、
(function () {
var fooAccount = {
name: " John",
amount: 4000,
totalMount: function (amount) {
this.amount -= amount;
return "Total amount left in account:"+ this. amount;
},
};
var barAccount = {
name: "John",
amount: 6000,
};
var withdrawAmountBy = function (total) {
return fooAccount.totalMount.bind(barAccount, total);
};
console.log(withdrawAmountBy(400)());
console.log(withdrawAmountBy(300)());
})();
// 5600 5300
// bind直接改变了this指向,现在this指向了barAccount,this.amount=6000,bind的第二个参数是函数的参数,所以,6000-400-300
11、原型链问题
// 如果原型链和内部变量重名,会输出什么?
1、
function Employee() {
this.employeeId = "1111";
}
Employee.prototype.JobId = "2222";
Employee.prototype.employeeId = "3333";
console.log(new Employee().employeeId, new Employee().JobId);
// 1、1111 2222
// 扩展,如果Employee构造函数内的值不重名,是this.employeeId111 = "1111";此时new Employee().employeeId会输出什么?
12、Array.sort()
可以看看这个sort方法解析
如果直接sort(),或者sort((a,b)=>(a-b))有什么不同呢?
直接sort()根据unicode字符串顺序排列,a-b也就是a
(function () {
var numberArray1 = [2, 8, 15, 16, 23, 42];
var numberArray2 = [2, 8, 15, 16, 23, 42];
var numberArray3 = [2, 8, 15, 16, 23, 42];
numberArray1.sort(function (a, b) {
return a - b;
});
numberArray2.sort(function (a, b) {
if ((a = b)) {
return 0;
} else {
return a < b ? -1 : 1;
}
});
numberArray3.sort();
console.log(numberArray1, numberArray2, numberArray3);
})();
// 输出:
// [2,8,15,16,23,42] [2,8,15,16,23,42] [15,16,2,23,42,8]
13、不知道归类为哪一类的题目
function getNumber() {
return 2, 4, 5;
}
var numb = getNumber();
console.log(numb);
// 5