js常见面试题

2020-07-27  本文已影响0人  小王子__

1, BFC是什么?触发BFC的条件是什么?触发后又能解决什么问题呢

var foo={n:1};
(function(foo){
   console.log(foo.n);
   foo.n=3;
   var foo={n:2};
   console.log(foo.n);
})(foo);
console.log(foo.n);
var foo = {n:1};
(function(foo){            //形参foo同实参foo一样指向同一片内存空间,这个空间里的n的值为1
    var foo;               //重复声明,无效。
    console.log(foo.n);    //输出1
    foo.n = 3;             //形参与实参foo指向的内存空间里的n的值被改为3
    foo = {n:2};           //形参foo指向了新的内存空间,里面n的值为2.
    console.log(foo.n);    //输出新的内存空间的n的值
})(foo);
console.log(foo.n);        //实参foo的指向还是原来的内存空间,里面的n的值为3.

3,cookies , sessionStorage 和 localStorage 的区别
4,JS中的原型和原型链
创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途就是包含可以由特定类型的所有实例共享的属性和方法,简单点说就是,当我们创建函数的时候系统会自动分配一个prototype属性,用来存储可以让所有实例共享的属性和方法

每一个构造函数都有一个prototype属性,这个属性指向一个对象,也就是原型对象
原型对象默认拥有一个constructor属性,指向指向他的那个构造函数
每个对象都拥有一个隐藏的__proto__,指向他的原型对象
function Person() {}
var p = new Person()
p.__proto__ = Person.prototype // true
Person.prototype.constructor = Person  // true

原型特点:

function Person () {
    }
    Person.prototype.name = '小马'
    Person.prototype.age = 20
    Person.prototype.sayHi = function () {
        console.log('Hi')
    }
    var p1 = new Person()
    var p2 = new Person()
    p1.name = '小王'
    p1.age = 18
    console.log(p1.name)  // '小王'
    console.log(p1.age)   // 18
    console.log(p1.sayHi())   // Hi
    console.log(p2.name)  // '小马'
    console.log(p2.age)   // 20
    console.log(p2.sayHi())   // Hi

从代码中可以看出:

function Person () {
    }
    Person.prototype = {
        name: '小马',
        age: 20,
        sayHi () {
            console.log('Hi')
        }
    }
    var p1 = new Person()
    var p2 = new Person()
    p1.name = '小王'
    p1.age = 18
    console.log(p1.name)  // '小王'
    console.log(p1.age)   // 18
    console.log(p1.sayHi())   // Hi
    console.log(p2.name)  // '小马'
    console.log(p2.age)   // 20
    console.log(p2.sayHi())   // Hi

只是在我们重写原型链的时候需要注意以下问题 :

function Person () {}
    var p = new Person ()
    Person.prototype = {
        name: '小王',
        age: 20
    }
    console.log(Person.prototype.constructor == Person)   // false
    console.log(p.name)  // undefined

重写原型对象之前:


image.png

重写原型对象之后:


image.png
var arr = [1,2,4]
console.dir(arr.valueOf()) 
image.png
arr.__proto__ === Array.prototype
true
Array.prototype.__proto__ === Object.prototype
true
arr.__proto__.__proto__ === Object.prototype
true

// 原型链的终点
Object.prototype.__proto__ === null
true

原型链如下:

arr ---> Array.prototype ---> Object.prototype ---> null

这就是传说中的原型链,层层向上查找,最后还没有就返回undefined
4,JavaScript 中的继承
什么是继承?

继承是指一个对象直接使用另外一个对象的属性和方法
由此可见只要实现属性和方法的继承,就达到继承的效果
我们先创建一个Person类

function Person (name, age) {
    this.name = name
    this.age = age
}
// 方法定义在构造函数的原型上
Person.prototype.getName = function () { console.log(this.name)}

此时我想创建一个Teacher类,我希望它可以继承Person所有的属性,并且额外添加属于自己特定的属性

function Teacher (name, age, subject) {
    Person.call(this, name, age)
    this.subject = subject
}

属性的继承是通过在一个类内执行另外一个类的构造函数,通过call指定this为当前执行环境,这样就可以得到另外一个类的所有属性

function Person (name, age) {
        this.name = name
        this.age = age
    }
    Person.prototype.getName = function () {
        console.log(this.name)
    }
    function Teacher (name,age,sub) {
        Person.call(this,name, age)
        this.sub = sub
    }
    var te = new Teacher('小王', 18, '前端')
    console.log(te.age)   // 18
    console.log(te.name)   // '小王'

很明显Teacher成功继承了Person的属性
4, html5 本地存储( localStorage )相关 api ,并实现 getAll 方法,获取本地存储

var str = "hello Tony";
str.substr(6);  //Tony
str.substring(6); //Tony

不同点:有两个参数时
(1)substr(start,length) 返回从start位置开始length长度的子串

“goodboy”.substr(1,6);   //oodboy

【注】当length为0或者负数,返回空字符串
(2)substring(start,end) 返回从start位置开始到end位置的子串(「不包含end」)

“goodboy”.substring(1,6);  //oodbo

【注】:
(1)substring 方法使用 start 和 end 两者中的较小值作为子字符串的起始点
(2)start 或 end 为 NaN 或者负数,那么将其替换为0
str是字符串时str.substring(start,end)和str.slice(start,end)完全等价;str是数组时str.slice(start,end)还可以继续用,str.substring(start,end)就不行了。
6, JS 截取地址栏指定字符后的内容
1,获取地址栏路径

var url = window.location.href;

2,截取指定字符后的内容

/**
  * 截取指定字符后的内容
  * @param url 路径
  * @param parameter 字符
  */
function getCaption(url,parameter) {
    var index = url.lastIndexOf(parameter);
    url = url.substring(index + 1, url.length);
    return url;
}

3,调用方法及结果

var url="http://www.baidu.com?123";
var a = getCaption(url, "?");
//  123

7, 以下代码的运行结果是

var game='4399'
game.substring(2,1)
console.log(game)
// 4399

这里有两个坑,第一个是start<stop的话,会自动交换这两个参数,第二个是substring对原数组不会改变。
8,JS的重定向有哪些

location.assign("http://www.baidu.com");
location.href="http://www.baidu.com";
window.location="http://www.baidu.com";
top.location="http://www.baidu.com";
self.location="http://www.baidu.com";
window.location.href="http://www.baidu.com";

9, 谈谈你对虚拟DOM原理的理解
1,什么是Virtual DOM(虚拟DOM)
Virtual DOM是对DOM的抽象,本质上是JavaScript对象,这个对象就是更加轻量级的对DOM的描述.
2,为什么需要Virtual DOM
既然我们已经有了DOM,为什么还需要额外加一层抽象?

首先,我们都知道在前端性能优化的一个秘诀就是尽可能少地操作DOM,不仅仅是DOM相对较慢,更因为频繁变动DOM会造成浏览器的回流或者重回,这些都是性能的杀手,因此我们需要这一层抽象,在patch过程中尽可能地一次性将差异更新到DOM中,这样保证了DOM不会出现性能很差的情况.

其次,现代前端框架的一个基本要求就是无须手动操作DOM,一方面是因为手动操作DOM无法保证程序性能,多人协作的项目中如果review不严格,可能会有开发者写出性能较低的代码,另一方面更重要的是省略手动DOM操作可以大大提高开发效率.

最后,也是Virtual DOM最初的目的,就是更好的跨平台,比如Node.js就没有DOM,如果想实现SSR(服务端渲染),那么一个方式就是借助Virtual DOM,因为Virtual DOM本身是JavaScript对象
10, 怎么利用img进行xss攻击
这个问题,我有点蒙蔽,我以为是 转发图片给上当者,然后就攻击了,网上找了答案,果不其然,我想错了
因为最近在学习web安全,出于好奇,尝试对CSDN进行了XSS注入,没想到真的成功了。
操作步骤:
直接找一篇博客,在底下评论

<img src="pic.gif" οnerrοr="javascript:this.src='/noPic.gif';" alt="pic" />

因为CSDN做了简单的转义,他会将注入的标签,去掉闭合性,也就是会把我注入的内容处理为:

<img src="pic.gif" οnerrοr="javascript:this.src='/noPic.gif';" alt="pic">

这样,注入的标签就失去了他的闭合性了,对一些普通的攻击就进行了防御,但是onerror事件是专门针对js出错的,所以,标签闭合性被破坏刚好触发了这个事件,所以,他会被执行,执行之后将img标签的src属性替换成我们想要的属性,然而我注入的这个地址,故意又是一个不能访问的地址,于是,就反复的触发这个onerror事件,最终导致浏览器堆栈溢出了。
说明:如果图片存在,但网络很不通畅,也可能触发 onerror。
解决方法:

1,for in 取的是key  for of 取的是value
2, for in 可以用于数组和对象 for of只能用于数组遍历

charAt() 返回指定位置的字符
去掉var str = "wangaaaallla"出现最多的字符,并统计出现次数

    let str = "wangaaaallla"
    function getStr (str) {
        let obj = {}
        for (var i = 0; i < str.length; i++) {
            console.log(obj[str.charAt(i)])
            if (obj[str.charAt(i)]) {
                obj[str.charAt(i)]++
            } else {
                obj[str.charAt(i)]=1
            }
        }
        let sum = 0
        let number
        for (let i in obj) {
            if (obj[i]>sum) {
                sum=obj[i]
                number=i
            }
        }
        console.log(number+'出现了====='+sum+'次');
    }
    getStr(str)

18, 获得并解析url中的参数 比如url: http://NaoNao.com/?product=shirt&color=blue&newuser&size=m#Hello

function UrlSearch() {
        var name,value;
        var args = {}
        var str='http://NaoNao.com/?product=shirt&color=blue&newuser&size=m#Hello'; //取得整个地址栏
        var num=str.indexOf("?")  // 18
        str=str.substr(num+1); //取得所有参数 product=shirt&color=blue&newuser&size=m#Hello
        var arr=str.split("&"); //各个参数放到数组里
        for(var i=0;i < arr.length;i++){
            num=arr[i].indexOf("=");  // 7 5 -1 4
            if(num>0){
                name=arr[i].substring(0,num);
                value=arr[i].substr(num+1);
                args[name] = value
            }
        }
        console.log(args)  // {product: "shirt", color: "blue", size: "m#Hello"}
        return args
    }
    UrlSearch()

substring() 方法用于提取字符串中介于两个指定下标之间的字符

var str="Hello world!"
undefined
str.substring(3, str.length)
"lo world!"

substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符

var str="Hello world!"
undefined
str.substring(3, str.length)
"lo world!"

slice() 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。

var str="Hello happy world!"
undefined
str.slice(6)
"happy world!"

19,JS实现排序
1,冒泡排序 bubble
思想: 让数组中的当前项和后一项比较,如果当前项大于后一项,则两者交换位置

let ary = [12, 8, 24, 16, 1]
    function  bubble (v) {
        for (let i = 0; i < v.length-1; i++) {   // 外层循环i控制比较的轮数
            for (let j = 0; j < v.length-i-1; j++) {  // 里层循环控制每一轮比较的次数
                if (v[j] > v[j + 1]) {
                    [v[j], v[j + 1]] = [v[j + 1], v[j]]
                }
            }
        }
        console.log(v)   // [1, 8, 12, 16, 24]
        return v
    }
    bubble(ary)

2,插入排序 insert

let ary = [12, 8, 24, 16, 1]
    function insert (v) {
        let arr = []
        arr.push(v[0])
        for (var i = 1; i < v.length; i++) {
            let temp = v[i]
            for (var j = arr.length - 1; j >= 0; j--) {
                let _a = arr[j]
                if (temp > _a) {
                    arr.splice(j + 1, 0, temp)
                    break
                }
                if (j === 0) {
                    arr.unshift(temp)
                }
            }
        }
        console.log(arr)    // [1, 8, 12, 16, 24]
        return arr
    }
    insert(ary)
上一篇 下一篇

猜你喜欢

热点阅读