js常见的原理⾯试题总结(⼀)
1: ⼿动实现⼀个call 函数
前置知识:
(1):⾸先了解Function 与function 的区别
// 调⽤构造函数并在每次解析的时候都会重新读取并创建⼀个新的函数对象
var fname= new Function('test', `console.log(${test})`);
(2): 使⽤delete关键字可以删除对象的属性
var obj ={
name: 'xiaoc',
age: 12
}
console.log(obj);  // {name: 'xiaoc',age:12 }
delete obj.age;    // 注意使⽤delete关键字可以删除对象的属性
console.log(obj);  //  {name: "xiaoc"}
(3): 数组中的slice⽅法
var arr =[1,2,3,4,5,6,7];
// slice第⼀个参数是从数组的那个索引开始截取,第⼆个参数是结束截取,  不修改原数组,返回新数组
console.log(arr.slice(2));  // [3,4,5,6,7]
console.log(arr.slice(2,4));  // [3,4]
// 注意splice 会修改原数组,如有删除则返回删除的项
下⾯是正式代码:
all=function(context){
/
/(node  环境下是global, 浏览器环境下是window)如果第⼀个参数是 null ,会报错TypeError: Cannot set property 'fn' of null,    context= context||global;
var arr=[...arguments].slice(1);
context.fn =this;
var res=context.fn(...arr);  // 函数fn可能含有返回值
delete context.fn;
return res;
}
var obj ={
name: "xiaomi",
age: 12
}
function fn(a,b,c,d){
console.log(this);    // 打印出调⽤fn 函数的this
console.log(a,b,c,d);
return "测试返回结果";
}
var all(null, 12,3,4,6)  // Object[global]  12 3 4 6
console.log(res);    // 打印函数的返回值:测试返回结果
2: ⼿动写⼀个apply ⽅法
// 和call ⽅法的区别就是, 参数是⼀个数组
apply=function(context){
context= context||global;
var arr =arguments[1];
context.fn=this;
var res=context.fn(...arr);
delete context.fn;
return res;
}
var obj ={
name: "zhangsan",
age:13
}
function test(a,b,c,d){
console.log(a,b,c,d);
return "apply 打印";
}
var res= apply(obj,[3,4,5,6,100]);  //  3 4 5 6
console.log(res);  // apply 打印
3: ⼿写⼀个bind 函数
// 和call 的区别是 bind是不会⾃动调⽤的
bind=function(context){
context= context||global;
var arr= [...arguments].slice(1);
context.fn = this;
return function(){
var res=context.fn(...arr);
delete context.fn;
return res;
}
}
var obj={
name: "xiaowang",
age:21
}
function test(a,b,c,d){
console.log(this);
console.log(a,b,c,d);
return "bind 测试打印";
}
var bind(obj,4,2 ,5,6)();
console.log(res);
4: 实现typeof 原理
前置知识点:
(1): 七种基本数据类型的理解(number, string, boolean, object, function, undefined, symbol)
// 此处没有symbol基本数据类型,后⾯再单独说
var obj ={name: "aem"};
var arr=[1,2,3,45];
var fn=function(){}
var a=10;
var b="svd";
var c= true;
// 对于数组和对象的类型都是object
console.log(typeof obj);  //  object
console.log(typeof arr);  //  object
console.log(typeof null);  //  object
console.log(typeof fn);    //  function
console.log(typeof a);    //  number
console.log(typeof b);    //  string
console.log(typeof c);    //  boolean
(2): 常⽤的js内置对象
// 使⽤以下内置构造函数⽣成对应的对象
var d= new String("abcdefg");
var e= new Number(23892);
var f= new Boolean(false);
var g= new Function("a", `console.log(${a})`);  // 两个参数都是字符串类型
console.log(typeof undefined);  // undefined
console.log(typeof d);        //  object
console.log(typeof e);        //  object
console.log(typeof f);        //  object
console.log(typeof g);        //  function
(3): 常⽤的js内置构造函数的类型
// 由于在js中实现类的⽅式是以构造函数实现的,故这些构造函数的类型是 function console.log(typeof Array);                  // function
console.log(typeof Number);                // functuon
console.log(typeof String);                // function
console.log(typeof Boolean);                // function
console.log(typeof Function);              // function
(3): 基本数据类型: symbol
// ⽅法 for 可以是已经定义的symbol类型的值不再重复定义,即使其是唯⼀的
var h= Symbol.for("12345");
var i= Symbol.for("12345");
// ⽅法keyFor可以取出⼀个symbol类型的key
var j= Symbol.keyFor(h);  // 注意参数是⼀个Symbol 对象
var k= Symbol.keyFor(i);
//var l= new Symbol();  // TypeError: Symbol is not a constructor
console.log(h,i);  // Symbol(12345) Symbol(12345)
console.log(h==i); //  true
console.log(j,k);  // 12345 12345
console.log(j==k);  // true
console.log(typeof Symbol);  // function
console.log(typeof Symbol());  // symbol
/
/ Symbol 构造函数对象内部阻⽌你显⽰创建⼀个symbol包装对象,
// 所以你不能⽤new来创建⼀个symbol对象。只能通过Symbol("s")来创建⼀个基本数据类型——symbol类型。
// 假如说: var x= Symbol(); x是⼀个symbol 基本类型的值,问x 是哪个构造函数的实例化对象?
// 答案是:没有结果,因为Symbol 构造函数阻⽌显⽰的创建⼀个symbol包装对象,所以不能⽤new 来创建对象,
// 因此我们见到的 symbol 类型的值都是基本数据类型,不是对象,也就没有是哪个构造函数的实例化对象这⼀说;
console.log(Symbol instanceof Function);    // true
console.log(Symbol() instanceof Function);  // false
console.log(Symbol() instanceof Symbol);    // false
console.log(Symbol() instanceof Object);    // false
console.log(Symbol() instanceof Array);    // false
console.log(Symbol() instanceof Number);    // false
console.log(Symbol() instanceof String);    // false
以下就是我们实现 typeof 原理的描述:
注意:js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息
000:对象
010:浮点数
100:字符串
110:布尔
1:整数
null:所有机器码均为0
js arguments
undefined:⽤ −2^30 整数来表⽰
对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的。
所以,typeof 在判断 null 的时候就出现问题了,由于 null 的所有机器码均为0,因此直接被当做了对象来看待。
然⽽⽤ instanceof 来判断的话
null instanceof null // TypeError: Right-hand side of 'instanceof' is not an object
null 直接被判断为不是 object,这也是 JavaScript 的历史遗留bug,可以参考typeof。
因此在⽤ typeof 来判断变量类型的时候,我们需要注意,最好是⽤ typeof 来判断基本数据类型(包括symbol),避免对 null 的判断。
// null 的理解
console.log(typeof null);  // object,说明 null 是对象
console.log(null instanceof Object);  // false,  说明 null 不是对象
由于typeof 在判断⼀个 object的数据的时候只能告诉我们这个数据是 object, ⽽不能细致的具体到是哪⼀种 object,准确判断类型的⽅法,就是String
console.log(String.call(1));              // [object Number]
console.log(String.call("abcdefg"));      // [object String] console.log(String.call(true));            // [object Boolean]
console.log(String.call(function(){}));    // [object Function] console.log(String.call({name: "123"}));  // [object object] console.log(String.call([1,2,3,4]))        // [object Array]
console.log(String.call(undefined));      // [object Undefined] console.log(String.call(Symbol()));        // [object Symbol] console.log(String.call(null));            // [object Null]
console.log(String.call(new Number(1)));  // [object Number] console.log(String.call(new String("123")));// [object String] console.log(String.call(new Boolean(true)));// [object Boolean]
5 :代码实现 instanceof 原理
(1 ):instanceof 主要的作⽤就是判断⼀个实例是否属于某种类型
// instanceof 主要的作⽤就是判断⼀个实例是否属于某种类型
let Person=function(){
}
let student =new Person();
console.log(student instanceof Person);  // true
(2):instanceof 也可以判断⼀个实例是否是其⽗类型或者祖先类型的实例
let Person =function(){
}
let Man=function(){
}
Man.prototype=new Person();  // 构造函数Man 继承 Person
let me = new Man();
console.log(me instanceof Man);  //  true
console.log(me instanceof Person);  // true
(3): 理解构造函数下的prototype属性和实例化对象的__proto__属性的联系
// 注意构造函数是通过 Prototype来实现继承的
// 同时原型的属性和⽅法都会其实例化对象所共享
function Test(){
this.name="xiaowang"
}
Test.prototype.eat=function(){console.log("eat");}
console.log(Test.prototype);  // Test { eat: [Function] }
var test= new Test();
console.log(test.__proto__);  // Test { eat: [Function] }
// 构造函数下的prototype属性和其实例化对象的 __proto__属性是⼀致的
console.log(test.__proto__===Test.prototype);  // true
以下就是我们实现 instanceof 原理的源代码

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。