面试实战问题解答(2)

面试问题解答

原型与原型链的了解?

原型是一个可以被复制(或者叫克隆)的一个类,通过复制原型可以创建一个一模一样的新对象。通俗的说,原型就是一个模板,在设计语言中更准确的说是一个对象模板。

原型(Person)定义了一些公用的属性和方法;利用原型(Person)创建出来的新对象实例(joe和john对象)会共享原型(Person)的所有属性和方法。

函数也是一个对象,对象不一定是函数。(对象有__proto__属性,函数有prototype属性)此处说明,方便大家理解下文。在javascript中,所有的对象都拥有一个__proto__属性指向该对象的原型(prototype)。

构造函数:

  • 构造函数也是一个普通函数,创建方式和普通函数一样,但构造函数习惯上首字母大写
  • 构造函数和普通函数的区别在于:调用方式不一样。作用也不一样(构造函数用来新建实例对象)
  • 3、调用方式不一样。
    • a. 普通函数的调用方式:直接调用 person();
    • 构造函数的调用方式:需要使用new关键字来调用 new Person();
  • 内部用this 来构造属性和方法

同步与异步?

同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。

:普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
异步: 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕

同步、异步、阻塞和非阻塞的概念

在进行网络编程时,我们常常见到同步、异步、阻塞和非阻塞四种调用方式。这些方式彼此概念并不好理解。下面是我对这些术语的理解。

  • 同步

所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。最常见的例子就是 SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的 LRESULT值返回给调用者。

  • 异步

异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。以CAsycSocket类为例(注意,CSocket从CAsyncSocket派生,但是起功能已经由异步转化为同步),当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程立刻可以朝下运行。当连接真正建立起来以后,socket底层会发送一个消息通知该对象。这里提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。可以使用哪一种依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。如果执行部件用状态来通知,那么调用者就需要每隔一定时间检查一次,效率就很低(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一种很严重的错误)。如果是使用通知的方式,效率则很高,因为执行部件几乎不需要做额外的操作。至于回调函数,其实和通知没太多区别。

  • 阻塞

阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。例如,我们在CSocket中调用Receive函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。如果主窗口和调用函数在同一个线程中,除非你在特殊的界面操作函数中调用,其实主界面还是应该可以刷新。socket接收数据的另外一个函数recv则是一个阻塞调用的例子。当socket工作在阻塞模式的时候,如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。

  • 非阻塞

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
对象的阻塞模式和阻塞函数调用
对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方式,我们可以通过一定的API去轮询状态,在适当的时候调用阻塞函数,就可以避免阻塞。而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。

单线程与多线程?

什么是进程?

当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
而一个进程又是由多个线程所组成的。

什么是线程?

线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,
即不同的线程可以执行同样的函数。

什么是多线程?

多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,
也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

多线程的好处:

可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,
这样就大大提高了程序的效率。

坏处:增加了调度和管理的开销,带来了一些不确定性,需要复杂的同步机制,避免死锁等等。
好处:一定程度上提高响应速度,在多核的情况下还是更能充分利用CPU资源的。

单线程,多线程,同步,异步

js就是单线程应用

线程是由cpu执行的最小单元

就好比一件事情可以分给几个人做

效率得到提高

单线程为了弥补这个缺点,就使用异步来解决

异步其实和回调很像,对于js来程序,如果执行耗时逻辑,肯定会阻塞当前线程,那要解决这个问题就使用异步

同步正好相反,会阻塞当前线程,直到响应后才能继续执行

多线程用途很广,比如你要从服务器获取一个很大的文件

如果是单线程,那就会很慢。

就会用异步的方式,等待获取数据后再处理

如果用同步就会阻塞

并行是针对多核心cpu,它才可以真正的并行。也就是cpu可以同时处理。就好比你有几个脑子,可以分别思考不同的事情

并发是cpu利用时间分片处理事情,比如你同时可能洗衣服,吃饭,看电视,本质上肯定做不到同时。但是你可以10毫秒洗衣服,10毫秒看电视。如果切换速度够快,那就看起来是同时执行了

多线程就是并发,利用cpu时间分片处理的

Java就是多线程的,js没有多线程,用异步来弥补多线程缺点

es6常用技术问题?

块级作用域 关键字let, 常量const
赋值解构

		let singer = { first: "Bob", last: "Dylan" };
		let { first: f, last: l } = singer; //  f = "Bob", l = "Dylan"
		let [a, b, c] = [1,2, 3] // a =1  ,b =2 , c =3
		let [all, year, month, day] =  /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec("2015-10-25");
		let [x, y] = [1, 2, 3]; // x = 1, y = 2
		
		let singer = { first: "Bob", last: "Dylan" };
		let { first: f, last: l } = singer; //  f = "Bob", l = "Dylan"
		let [a, b, c] = [1,2, 3] // a =1  ,b =2 , c =3
		let [all, year, month, day] =  /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec("2015-10-25");
		let [x, y] = [1, 2, 3]; // x = 1, y = 2

函数参数 - 默认值、参数打包、 数组展开(Default 、Rest 、Spread)

		//es6
		function findArtist(name='lu', age='26') {
		    ...
		}
		//es5
		function findArtist(name, age) {
		  var _name = name || 'lu';
		  var _age = age || '26';
		    ...
		}
		
		//Rest
		function f(x, ...y) {
		  // y is an Array
		  console.log(y);
		  return x * y.length;
		}
		// ['hello', true]
		f(3, "hello", true) == 6
		
		//Spread
		function f(x, y, z) {
		  return x + y + z;
		}
		// Pass each elem of array as argument
		f(...[1,2,3]) == 6

箭头函数 Arrow functions

​简化了代码形式,默认return表达式结果。

		
		cont b = a => a + '(demo)';
		
		cont b = function(a) {
		  return a + '(demo)'
		}

字符串模板 Template strings

		var name = "Bob", time = "today";
		`Hello ${name}, how are you ${time}?`
		// return "Hello Bob, how are you today?"

Iterators(迭代器)+ for…of

		for (var n of ['a','b','c']) {
		  console.log(n);
		}
		// 打印a、b、c
		
		for (const [index, info] of ['a','b','c'].entries()} {
		  
		}
		     
		for (const [key, val] of Object.entries({a:1, b:2})} {
		  
		}

Class

Class,有constructor、extends、super,但本质上是语法糖(对语言的功能并没有影响,但是更方便程序员使用)。

		
		//es6
		class Artist {
		    constructor(name) {
		        this.name = name;
		    }
		    perform() {
		        return this.name + " performs ";
		    }
		}
		class Singer extends Artist {
		    constructor(name, song) {
		        super.constructor(name);
		        this.song = song;
		    }
		    perform() {
		        return super.perform() + "[" + this.song + "]";
		    }
		}
		
		//es5
		function Artist(name) {
		    this.name = name;
		    this.perform = function() {
		        return this.name + " performs ";
		    }
		}
		Artist.prototype.perform = function () {
		     return this.name + " performs ";
		};
		
		function Singer(song, name) {
		    this.song = song;
		    Artist.call(this, name);
		    this.perform = function() {
		         return this.perform() + "[" + this.song + "]";
		    }
		}
		
		// es6
		let james = new Singer("Etta James", "At last");
		james instanceof Artist; // true
		james instanceof Singer; // true
		
		james.perform(); // "Etta James performs [At last]"
		
		//es5
		 Singer.prototype = Object.create(Artist.prototype);
		 Singer.prototype.constructor = Artist;
		 var james = new Singer("Etta James", "At last");

Modules

ES6的内置模块功能借鉴了CommonJS和AMD各自的优点:

(1).具有CommonJS的精简语法、唯一导出出口(single exports)和循环依赖(cyclic dependencies)的特点。

(2).类似AMD,支持异步加载和可配置的模块加载。


		// lib/math.js
		export function sum(x, y) {
		  return x + y;
		}
		export var pi = 3.141593;
		
		// app.js
		import * as math from "lib/math";
		alert("2π = " + math.sum(math.pi, math.pi));
		
		// otherApp.js
		import {sum, pi} from "lib/math";
		alert("2π = " + sum(pi, pi));
		
		Module Loaders:
		// Dynamic loading – ‘System’ is default loader
		System.import('lib/math').then(function(m) {
		  alert("2π = " + m.sum(m.pi, m.pi));
		});
		
		// Directly manipulate module cache
		System.get('jquery');
		System.set('jquery', Module({$: $})); // WARNING: not yet finalized
		
		//es5 
		document.write("<script language=javascript src='*.js'></script>");


Map + Set + WeakMap + WeakSet

四种集合类型,WeakMap、WeakSet作为属性键的对象如果没有别的变量在引用它们,则会被回收释放掉。


		// Sets
		var s = new Set();
		s.add("hello").add("goodbye").add("hello");
		s.size === 2;
		s.has("hello") === true;
		
		// Maps
		var m = new Map();
		m.set("hello", 42);
		m.set(s, 34);
		m.get(s) == 34;
		
		//WeakMap
		var wm = new WeakMap();
		wm.set(s, { extra: 42 });
		wm.size === undefined
		
		// Weak Sets
		var ws = new WeakSet();
		ws.add({ data: 42 });//Because the added object has no other references, it will not be held in the set

Math + Number + String + Array + Object APIs

一些新的API


		Number.EPSILON
		Number.isInteger(Infinity) // false
		Number.isNaN("NaN") // false
		
		Math.acosh(3) // 1.762747174039086
		Math.hypot(3, 4) // 5
		Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2
		
		"abcde".includes("cd") // true
		"abc".repeat(3) // "abcabcabc"
		
		Array.from(document.querySelectorAll('*')) // Returns a real Array
		Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
		
		[0, 0, 0].fill(7, 1) // [0,7,7]
		[1, 2, 3].find(x => x == 3) // 3
		[1, 2, 3].findIndex(x => x == 2) // 1
		[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
		["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
		["a", "b", "c"].keys() // iterator 0, 1, 2
		["a", "b", "c"].values() // iterator "a", "b", "c"
		
		Object.assign(Point, { origin: new Point(0,0) })

Proxies

使用代理(Proxy)监听对象的操作,然后可以做一些相应事情。对象属性拦截修改。


		var target = {};
		var handler = {
		  get: function (receiver, name) {
		    return `Hello, ${name}!`;
		  }
		};
		
		var p = new Proxy(target, handler);
		p.world === 'Hello, world!';
		
		可监听的操作: get、set、has、deleteProperty、apply、construct、getOwnPropertyDescriptor、defineProperty、getPrototypeOf、setPrototypeOf、enumerate、ownKeys、preventExtensions、isExtensible。

Symbols

Symbol是一种基本类型。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。


var key = Symbol("key");
var key2 = Symbol("key");
key == key2  //false
Promises

Promises是处理异步操作的对象,使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观(类似jQuery的deferred 对象)。

这里我建议使用es6 新更新 的 async 异步操作,更简洁方便


function fakeAjax(url) {
  return new Promise(function (resolve, reject) {
    // setTimeouts are for effect, typically we would handle XHR
    if (!url) {
      return setTimeout(reject, 1000);
    }
    return setTimeout(resolve, 1000);
  });
}

// no url, promise rejected
fakeAjax().then(function () {
  console.log('success');
},function () {
  console.log('fail');
});


// Ajax 是异步的,异步函数调用异步函数
async a () {
  const response = await Ajax();
  return response.id;
}

async c() {
    const result = await this.a();
}

// 调用异步函数
b () {
  a().then(result => {
    console.log(result);
  })
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值