记一次js笔试题

感觉有些题目还是蛮刁钻 经典的。。。

1、JS赋值问题,js赋值是值传递还是引用?
JS有5种基本类型Undefined、Null、Boolean、Number和String,和1种复杂类型Object。
基本类型是值传递,复杂类型引用传递。

// 猜猜看都会输出什么?

1var strA ='AAA';
var strB= strA;
strB="BBB";
console.log (strA)

2var array1 = [1, 2, 3];
var array2 = array1;
array1[0] = 100;
alert(array2);	
 
3var obj1 = {"a":1};
var obj2 = obj1;
obj1["a"] = 2;
alert(obj2);	

// 思考一下这个噢
4var a = [1,2,3];
var b = a;
a = [4,5,6];
alert(b); 

1AAA
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无变量提升。
函数变量提升会整个提升,所以上方的函数可以直接调用下方声明的函数。

// 猜猜会输出什么

1var 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();

1function
2undefined

3、ES6 Object.keys / for…in
在这里插入图片描述

// 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());
  }());

1false false 
2true 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(123)会报错的。
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指针
函数提升和变量提升:函数是一等公民,提升在变量之前,但是提升的都只是声明,使用是按原本次序。以及如果函数与变量同名的情况:函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖。

// 猜猜会输出啥
1var obj = {
  message: "Hello",
  innerMessage: !(function () {
    console.log(this.message);
  })(),
};
console.log(obj.innerMessage);

1undefined  true(如果没有感叹号,输出undefined  undefined
// 解析:初始化obj时就会执行innerMessage,函数一等公民,变量提升在变量之前。所以此时的顺序应该是:
// function(){console.log(this.message)} 
// var message;
// (function(){})()=>输出undefined

2function myFunc() {
  console.log(this.message);
}
myFunc.message = "Hi John";
console.log(myFunc());

// undefined  undefined  
// 解析:因为直接调用对象, 对象默认是window,所以this.message是undefined,无返回值,输出undefined

3var 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指向问题

1function 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、原型链问题


// 如果原型链和内部变量重名,会输出什么?
1function 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<b时返回false不用换位置,a前b后排列。

(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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值