前端总结(二)

以下主要是JavaScript相关面试题

1.call和.apply的区别是什么?

call方法:

语法:call(thisObj,Object)
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明:call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。 如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

/*call()方法*/
function.call(thisObj[, arg1[, arg2[, [,...argN]]]]);
apply方法:

语法:apply(thisObj,[argArray])
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明:如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。

/*apply()方法*/
function.apply(thisObj[, argArray])
对于apply和call两者在作用上是相同的,但两者在参数上有以下区别:

对于第一个参数意义都一样,但对第二个参数:apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。如 func.call(func1,var1,var2,var3)对应的apply写法为:func.apply(func1,[var1,var2,var3])同时使用apply的好处是可以直接将当前函数的arguments对象作为apply的第二个参数传入。

2.js有几种数据类型,其中基本数据类型有哪些

五种基本类型: Undefined、Null、Boolean、Number和String。
一种复杂的数据类型————Object,Object本质上是由一组无序的名值对组成的。
Object、Array和Function则属于引用类型

3. JS哪些操作会造成内存泄露

1)意外的全局变量引起的内存泄露

function leak(){  
	leak="xxx";		//leak成为一个全局变量,不会被回收  
}

2)闭包引起的内存泄露
3)没有清理的DOM元素引用
4)被遗忘的定时器或者回调
5)子元素存在引起的内存泄露

4. JavaScript中如何检测一个变量是一个String类型?请写出函数实现

typeof(obj) === “string”
typeof obj === “string”
obj.constructor === String

5. new操作符到底到了什么

new共经过了4个阶段

1、创建一个空对象

var obj=new Object();  

2、设置原型链

obj.__proto__= Func.prototype;   

3、让Func中的this指向obj,并执行Func的函数体。

var result =Func.call(obj); 

4、判断Func的返回值类型:

如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象。

if (typeof(result) == "object"){  
	func=result;  
}  
else{  
    func=obj;;  
}

6. 怎样添加、移除、移动、复制、创建和查找节点?

1)创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点

2)添加、移除、替换、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入

3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性

7. 请解释一下JavaScript的同源策略。

在客户端编程语言中,如javascript和 ActionScript,同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义。同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法。那么什么叫相同域,什么叫不同的域呢?当两个域具有相同的协议, 相同的端口,相同的host,那么我们就可以认为它们是相同的域。同源策略还应该对一些特殊情况做处理,比如限制file协议下脚本的访问权限。本地的HTML文件在浏览器中是通过file协议打开的,如果脚本能通过file协议访问到硬盘上其它任意文件,就会出现安全隐患,目前IE8还有这样的隐患。

8. 请用js去除字符串空格?

方法一:使用replace正则匹配的方法
去除所有空格:

str = str.replace(/\s*/g,"");

去除两头空格:

str = str.replace(/^\s*|\s*$/g,"");

去除左空格:

 str = str.replace( /^\s*/, “”);

去除右空格:

str = str.replace(/(\s*$)/g, "");

str为要去除空格的字符串,实例如下:

var str = " 23 23 ";
var str2 = str.replace(/\s*/g,"");
console.log(str2); // 2323

方法二:使用str.trim()方法
str.trim()局限性:无法去除中间的空格,实例如下:

var str = "   xiao  ming   ";
var str2 = str.trim();
console.log(str2);   //xiao  ming 

同理,str.trimLeft(),str.trimRight()分别用于去除字符串左右空格。
方法三:使用jquery,$.trim(str)方法
$.trim(str)局限性:无法去除中间的空格,实例如下:

var str = "   xiao  ming   ";
var str2 = $.trim(str)
console.log(str2);   //  xiao  ming

9. 比较typeof与instanceof?

相同点:JavaScript 中 typeof 和 instanceof 常用来判断一个变量是否为空,或者是什么类型的。

typeof的定义和用法:返回值是一个字符串,用来说明变量的数据类型。

细节:

(1)、typeof 一般只能返回如下几个结果:number,boolean,string,function,object,undefined。

(2)、typeof 来获取一个变量是否存在,如if(typeof a!="undefined"){alert("ok")},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错。

(3)、对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性。

Instanceof定义和用法:instanceof 用于判断一个变量是否属于某个对象的实例。

实例演示:

a instanceof b?alert("true"):alert("false"); //a是b的实例?真:假

var a = new Array(); 
alert(a instanceof Array);  // true
alert(a instanceof Object)  // true

如上,会返回 true,同时 alert(a instanceof Object) 也会返回 true;这是因为 Array 是 object 的子类。

function test(){};
var a = new test();
alert(a instanceof test)   // true

细节:
如下,得到的结果为‘N’,这里的 instanceof 测试的 object 是指 js 语法中的 object,不是指 dom 模型对象。

if (window instanceof Object){ alert('Y')} else {  alert('N');}  // 'N'

10. javascript面向对象中继承实现?

面向对象的基本特征有:封装、继承、多态

在JavaScript中实现继承的方法:

  1. 原型链(prototype chaining)
  2. call()/apply()
  3. 混合方式(prototype和call()/apply()结合)
  4. 对象冒充

继承的方法如下:

function A(name){  this.name=name; }
A.prototype.sayName=function(){ console.log(this.name); }
function B(age){ this.age=age; }

1、prototype原型链方式:

B.prototype=new A("mbj");  //被B的实例共享
var foo=new B(18);
foo.age;    //18,age是本身携带的属性
foo.name;   //mbj,等价于foo.__proto__.name
foo.sayName(); //mbj,等价于foo.__proto__.proto__.sayName()
foo.toString();  //"[object Object]",等价于foo.__proto__.__proto__.__proto__.toString();

这样student通过原型继承了A,在new B的时候,foo中有个隐藏的属性__proto__指向构造函数的prototype对象,在这里是A对象实例,A对象里面也有一个隐藏的属性__proto__,指向A构造函数的prototype对象,这个对象里面又有一个__proto__指向Object的prototype

这种方式的缺第一个缺点是所有子类共享父类实例,如果某一个子类修改了父类,其他的子类在继承的时候,会造成意想不到的后果。第二个缺点是在构造子类实例的时候,不能给父类传递参数。
2、call()/apply()方法 (构造函数继承)

function B(age,name){ 
 this.age=age;
 A.call(this,name); 
 // A.apply(this,arguments);
}
var foo=new B(18,"wmy");
foo.name;     //wmy
foo.age;      //18
foo.sayName();   //undefined

采用这种方式继承是把A中的属性加到this上面,这样name相当于就是B的属性,sayName不在A的构造函数中,所以访问不到sayName。这种方法的缺点是父类的prototype中的函数不能复用。

3、混合方法【prototype,call/apply】

function B(age,name){  this.age=age;A.call(this,name); }
B.prototype=new A("mbj");
var foo=new B(18,"wmy");
foo.name;     //wmy
foo.age;      //18
foo.sayName();   //wmy

这样就可以成功访问sayName函数了,结合了上述两种方式的优点,但是这种方式也有缺点,那就是占用的空间更大了。
4、对象冒充

function Person(name,age){
	this.name = name;
	this.age = age;
	this.show = function(){
		console.log(this.name+", "+this.age);
	}
}

function Student(name,age){
this.student = Person; //将Person类的构造函数赋值给this.student
this.student(name,age); //js中实际上是通过对象冒充来实现继承的
	delete this.student; //移除对Person的引用
}

var s = new Student("小明",17);
s.show();

var p = new Person("小花",18);
p.show();
// 小明, 17
// 小花, 18

猜你喜欢

转载自blog.csdn.net/g291976422/article/details/87935146