We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
最近正在准备找工作,作为野路子前端个人认为很有必要梳理一下前端相关基础知识(刷题),所以分三大块HTML、CSS和JavaScript来进行整理记录。 其中很多知识点并不是一两句话就能聊清楚的,所以很多内容都是粗鄙浅显的,更加深入的讨论需要单独开坑,所以引入了其他大牛整理好的相关内容以供翻阅参考。 切记不可急于求成,不能妄自菲薄。
__proto__
JavaScript从原型到原型链
栈:原始数据类型(Undefined,Null,Boolean,Number、String) 堆:引用数据类型(对象、数组和函数)
// 结合下面的内存空间图观察 var a1 = 0; // 变量对象 var a2 = 'this is string'; // 变量对象 var a3 = null; // 变量对象 var b = { m: 20 }; // 变量b存在于变量对象中,{m: 20} 作为对象存在于堆内存中 var c = [1, 2, 3]; // 变量c存在于变量对象中,[1, 2, 3] 作为对象存在于堆内存中
两种类型的区别是:存储位置不同。 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储; 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能; 引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体 javascript内存空间详解
var values = [1, 2, 3, 4, 5]; values.sort(function(){ return Math.random() - 0.5; }); console.log(values)
使用Math.random乱的不够彻底,可以使用Fisher–Yates算法进行乱序:
Math.random
function shuffle(a) { for (let i = a.length; i; i--) { let j = Math.floor(Math.random() * i); [a[i - 1], a[j]] = [a[j], a[i - 1]]; } return a; }
JavaScript专题之乱序
function createPerson(name) { var o = new Object(); o.name = name; o.getName = function () { console.log(this.name); }; return o; } var person1 = createPerson('kevin');
function Person(name) { this.name = name; this.getName = function () { console.log(this.name); }; } var person1 = new Person('kevin');
function Person() { } Person.prototype.name = 'keivn'; Person.prototype.getName = function () { console.log(this.name); }; var person1 = new Person();
function Person(name) { this.name = name; } Person.prototype = { constructor: Person, getName: function () { console.log(this.name); } }; var person1 = new Person();
JavaScript深入之创建对象的多种方式以及优缺点
function Parent () { this.names = ['kevin', 'daisy']; } function Child () { } Child.prototype = new Parent();
function Parent () { this.names = ['kevin', 'daisy']; } function Child () { Parent.call(this); }
function Parent (name) { this.name = name; this.colors = ['red', 'blue', 'green']; } Parent.prototype.getName = function () { console.log(this.name) } function Child (name, age) { Parent.call(this, name); this.age = age; } Child.prototype = new Parent();
function createObj(o) { function F(){} F.prototype = o; return new F(); }
function createObj (o) { var clone = object.create(o); clone.sayName = function () { console.log('hi'); } return clone; }
function object(o) { function F() {} F.prototype = o; return new F(); } function prototype(child, parent) { var prototype = object(parent.prototype); prototype.constructor = child; child.prototype = prototype; } // 当我们使用的时候: prototype(Child, Parent);
JavaScript深入之继承的多种方式和优缺点
函数在调用激活时,会开始创建对应的执行上下文,在执行上下文生成的过程中,变量对象,作用域链,以及this的值会分别被确定。
其中作用域链,在解释器进入到一个执行上下文时,初始化完成并将其分配给当前执行上下文。每个执行上下文的作用域链由当前上下文的变量对象(VO)及父级执行上下文的作用域链构成。
可以理解为:currentScopeChain = currentVO + all parents scopes
JavaScript执行上下文
this的指向,是在函数被调用的时候确定的,也就是在创建EC阶段 涉及到this指向问题需要考虑到如下情况:全局下,函数独立调用,对象方法调用,new,call,apply,bind。
关于this的详细解析-->this到底指向哪里
null表示"没有对象",即该处不应该有值。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。
所以设置一个值为 null 是合理的,如: objA.valueA = null; 但设置一个值为 undefined 是不合理的
undefined与null的区别
parseInt函数解析一个字符串参数,并返回一个指定基数的整数。
parseInt(string, radix);
radix 一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数"10"表示使用我们通常使用的十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常将值默认为10。
返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN。
Array.prototype.map()方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
let new_array = arr.map(function callback(currentValue, index, array) { // Return element for new_array }[, thisArg])
可以发现["1", "2", "3"].map(parseInt)实际执行为:
["1", "2", "3"].map(parseInt)
parseInt('1', 0); // OK - gives 1 parseInt('2', 1); // FAIL - 1 isn't a legal radix parseInt('3', 2); // FAIL - 3 isn't legal in base 2
那么最终结果为[1,NaN,NaN]
[1,NaN,NaN]
Why does parseInt yield NaN with Array#map?
MDN 对闭包的定义为:
闭包是指那些能够访问自由变量的函数。
那什么是自由变量呢?
自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。
由此,我们可以看出闭包共有两部分组成:
闭包 = 函数 + 函数能够访问的自由变量
ECMAScript中,闭包指的是:
JavaScript深入之闭包
jQuery中Type API:
var class2type = {}; // 生成class2type映射 "Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) { class2type["[object " + item + "]"] = item.toLowerCase(); }) function type(obj) { // 一箭双雕 if (obj == null) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[Object.prototype.toString.call(obj)] || "object" : typeof obj; }
JavaScript专题之类型判断(上) JavaScript专题之类型判断(下)
放出一个模拟板:
function objFactory(){ // 初始化一个临时对象 var obj = new Object() // 获取第一个参数为构造函数,shift会改变原数组哦 var Construct = [].shift.call(arguments) // 将临时对象的原型指向构造函数的prototype obj.__proto__ = Construct.prototype // 使用apply给obj添加属性 var result = Construct.apply(obj, arguments) return (typeof result === 'object' && result !== null) ? result : obj }
new运算符模拟实现
Node.appendChild()方法将一个节点添加到指定父节点的子节点列表末尾。
ChildNode.remove() 方法把从它所属的DOM树中删除对象。
Node.replaceChild()用指定的节点替换当前节点的一个子节点,并返回被替换掉的节点。
Node.cloneNode()方法返回调用该方法的节点的一个副本。
Document.createDocumentFragment() 创建一个新的空白的文档片段。 Document.createElement() 创建由tagName 指定的HTML元素,或一个HTMLUnknownElement,如果tagName不被识别。 document.createTextNode() 创建一个新的文本节点。
Element.querySelector()返回与指定的选择器组匹配的元素的后代的第一个元素。 Element.querySelectorAll()返回一个non-live的NodeList, 它包含所有元素的非活动节点,该元素来自与其匹配指定的CSS选择器组的元素。(基础元素本身不包括,即使它匹配。)
document.getElementById()返回一个匹配特定 ID的元素.
Element.getElementsByClassName()Element.getElementsByClassName() 方法返回一个即时更新的(live) HTMLCollection,包含了所有拥有指定 class 的子元素。当在 document 对象上调用此方法时,会检索整个文档,包括根元素。
element.getElementsByTagName()方法返回一个动态的包含所有指定标签名的元素的HTML集合HTMLCollection。指定的元素的子树会被搜索,不包括元素自己。返回的列表是动态的,这意味着它会随着DOM树的变化自动更新自身。所以,使用相同元素和相同参数时,没有必要多次的调用Element.getElementsByTagName() .
addEventListener:绑定事件的监听函数 removeEventListener:移除事件的监听函数 dispatchEvent:触发事件
DOM提供三种方法,可以用来为事件绑定监听函数。
事件模型
var xhr = new XMLHttpRequest(); // 指定通信过程中状态改变时的回调函数 xhr.onreadystatechange = function(){ // 通信成功时,状态值为4 if (xhr.readyState === 4){ if (xhr.status === 200){ console.log(xhr.responseText); } else { console.error(xhr.statusText); } } }; xhr.onerror = function (e) { console.error(xhr.statusText); }; // open方式用于指定HTTP动词、请求的网址、是否异步 xhr.open('GET', '/endpoint', true); // 发送HTTP请求 xhr.send(null);
AJAX
window对象在浏览器中,window对象(注意,w为小写)指当前的浏览器窗口。它也是所有对象的顶层对象
document节点是文档的根节点,每张网页都有自己的document节点。window.document属性就指向这个节点。只要浏览器开始载入HTML文档,这个节点对象就存在了,可以直接调用。
cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。 cookie数据始终在同源的http请求中携带(即使不需要),即会在浏览器和服务器间来回传递。 sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
存储大小:
有期时间:
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
sessionStorage 数据在当前浏览器窗口关闭后自动删除。
cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
共享:
localStorage的修改会促发其他文档窗口的update事件
// event(事件)工具集,来源:https://github.com/markyun/Markyun.js markyun.Event = { // 页面加载完成后 readyEvent : function(fn) { if (fn==null) { fn=document; } var oldonload = window.onload; if (typeof window.onload != 'function') { window.onload = fn; } else { window.onload = function() { oldonload(); fn(); }; } }, // 视能力分别使用dom0||dom2||IE方式 来绑定事件 // 参数: 操作的元素,事件名称 ,事件处理程序 addEvent : function(element, type, handler) { if (element.addEventListener) { //事件类型、需要执行的函数、是否捕捉 element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent('on' + type, function() { handler.call(element); }); } else { element['on' + type] = handler; } }, // 移除事件 removeEvent : function(element, type, handler) { if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else if (element.detachEvent) { element.detachEvent('on' + type, handler); } else { element['on' + type] = null; } }, // 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获) stopPropagation : function(ev) { if (ev.stopPropagation) { ev.stopPropagation(); } else { ev.cancelBubble = true; } }, // 取消事件的默认行为 preventDefault : function(event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } }, // 获取事件目标 getTarget : function(event) { return event.target || event.srcElement; }, // 获取event对象的引用,取到事件的所有信息,确保随时能使用event; getEvent : function(e) { var ev = e || window.event; if (!ev) { var c = this.getEvent.caller; while (c) { ev = c.arguments[0]; if (ev && Event == ev.constructor) { break; } c = c.caller; } } return ev; } };
Event.target一个触发事件的对象的引用。它与event.currentTarget不同, 当事件处理程序在事件的冒泡或捕获阶段被调用时。
event.currentTarget当事件遍历DOM时,标识事件的当前目标。它总是引用事件处理程序附加到的元素,而不是event.target,它标识事件发生的元素。
e.target与e.currentTarget的区别
JS模块化方案很多,AMD/CommonJS/UMD/ES6 Module等。
由于nodejs流行所以现在CommonJS规范使用的人数较多,当然ES6 Module应该会慢慢成为主流,至于AMD和CMD由于seajs和requirejs使用越来越少所以这两个规范的应用应该也是一样吧。
如何实现一个 CMD 模块加载器 前端模块化、组件化
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
//定义类 class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } }
Class 的基本语法
我们可以知道call()方法的作用和 apply() 方法类似,只有一个区别,就是 call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。
JavaScript模拟实现call,apply,bind等方法
Object构造函数创建一个对象包装器。
Array用于构造数组的全局对象
Array对象
创建变量对象过程:
从创建变量对象步骤1,,2,3可以发现这就是我们常说的变量提升和函数声明优先级高于变量声明的原因。
利用数组的一些方法比如:slice、concat 返回一个新数组的特性来实现拷贝。
var arr = ['old', 1, true, null, undefined]; var new_arr1 = arr.concat(); var new_arr2 = arr.slice();
手动实现一个浅拷贝:
var shallowCopy = function(obj) { // 只拷贝对象 if (typeof obj !== 'object') return; // 根据obj的类型判断是新建一个数组还是对象 var newObj = obj instanceof Array ? [] : {}; // 遍历obj,并且判断是obj的属性才拷贝 for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj; }
我们把这种复制引用的拷贝方法称之为浅拷贝,与之对应的就是深拷贝,深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}] var new_arr = JSON.parse( JSON.stringify(arr) );
这是一个简单粗暴的好方法,就是有一个问题,不能拷贝函数。
手动实现一个深拷贝:
var deepCopy = function(obj) { if (typeof obj !== 'object') return; var newObj = obj instanceof Array ? [] : {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]; } } return newObj; }
尽管使用深拷贝会完全的克隆一个新对象,不会产生副作用,但是深拷贝因为使用递归,性能会不如浅拷贝,在开发中,还是要根据实际情况进行选择。
JavaScript专题之深浅拷贝
extend 的用法: jQuery.extend( [deep], target, object1 [, objectN ] )
jQuery.extend( [deep], target, object1 [, objectN ] )
函数的第一个参数可以传一个布尔值,如果为 true,我们就会进行深拷贝,false 依然当做浅拷贝。 target,表示要拓展的目标,我们就称它为目标对象吧。 后面的参数,都传入对象,内容都会复制到目标对象中,我们就称它们为待复制对象吧。
实现思路:
// 第二版 function extend() { // 默认不进行深拷贝 var deep = false; var name, options, src, copy; var length = arguments.length; // 记录要复制的对象的下标 var i = 1; // 第一个参数不传布尔值的情况下,target默认是第一个参数 var target = arguments[0] || {}; // 如果第一个参数是布尔值,第二个参数是才是target if (typeof target == 'boolean') { deep = target; target = arguments[i] || {}; i++; } // 如果target不是对象,我们是无法进行复制的,所以设为{} if (typeof target !== 'object') { target = {} } // 循环遍历要复制的对象们 for (; i < length; i++) { // 获取当前对象 options = arguments[i]; // 要求不能为空 避免extend(a,,b)这种情况 if (options != null) { for (name in options) { // 目标属性值 src = target[name]; // 要复制的对象的属性值 copy = options[name]; if (deep && copy && typeof copy == 'object') { // 递归调用 target[name] = extend(deep, src, copy); } else if (copy !== undefined){ target[name] = copy; } } } } return target; };
核心的部分还是跟实现深浅拷贝函数一致,如果要复制的对象的属性值是一个对象,就递归调用 extend。不过 extend 的实现中,多了很多细节上的判断,比如第一个参数是否是布尔值,target 是否是一个对象,不传参数时的默认值等。
以上实现和jQuery中版本还有一定差别,详细内容-->JavaScript专题之从零实现jQuery的extend
.bind()方法将事件类型和一个事件处理函数直接注册到了被选中的DOM元素中。
.live()方法将与事件处理函数关联的选择器和事件信息一起附加到文档的根级元素(即document)。通过将事件信息注册到document上,这个事件处理函数将允许所有冒泡到document的事件调用它(例如委托型、传播型事件)。一旦有一个事件冒泡到document元素上,Jquery会根据选择器或者事件的元数据来决定哪一个事件处理函数应该被调用,如果这个事件处理函数存在的话。这个额外的工作将会在用户交互时对性能方面造成一定的影响,但是初始化注册事件的过程相当地快。
.delegate()方法与.live()方式实现方式相类似,它不是将选择器或者事件信息附加到document,而是让你指定附加的元素。就像是.live()方法一样,这个方法使用事件委托来正确地工作。
Jquery 1.7版本中.bind(),.live() 和.delegate()方法只需要使用.on()方法一种方式来调用它们。 如何使用.on()方法决定了它如何调用其他方法。你可以认为.on()方法被具有不同签名的方法”重载“了,而这些方法实现了不同的事件绑定的连接方式。
/* Jquery的 .bind() , .live() 和 .delegate() 方法只需要使用`.on()`方法一种方式来调用它们 */ // Bind $( "#members li a" ).on( "click", function( e ) {} ); $( "#members li a" ).bind( "click", function( e ) {} ); // Live $( document ).on( "click", "#members li a", function( e ) {} ); $( "#members li a" ).live( "click", function( e ) {} ); // Delegate $( "#members" ).on( "click", "li a", function( e ) {} ); $( "#members" ).delegate( "li a", "click", function( e ) {} );
[译] Jquery中 .bind() .live() .delegate() 和 .on() 之间的区别
节流的原理很简单: 如果你持续触发事件,每隔一段时间,只执行一次事件。
关于节流的实现,有两种主流的实现方式,一种是使用时间戳,一种是设置定时器。
JavaScript专题之跟着 underscore 学节流
简单解释一下debounce的原理: 在持续触发某个事件时,该事件的回调函数不会立即触发,而是在最后一个触发事件结束一段时间后去执行回调函数。
我们会为目标函数设置一个定时器,当定时器未执行时,事件再次被触发,则清除当前的定时器,然后设置新的定时器,直到定时器timeout执行目标函数。
function debounceTwo(fun, wait){ var timeout; return function(){ // 获取当前this,用于指定目标函数的this值 var context = this; // 获取调用时的参数 var args = arguments; clearTimeout(timeout); timeout = setTimeout(function(){ fun.apply(context, args); }, wait); } };
_.debounce源码学习 JavaScript专题之跟着underscore学防抖
Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。
如下是一个简单的babel配置文件.babelrc
.babelrc
{ // 设置转码规则,使用的时候需要安装对应的插件, // 对应babel-preset-xxx,例如下面的配置babel-preset-env "presets": [ ["env", {// options "modules": false,// 不会转换模块 "targets": { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] // 使用BrowserList(https://github.com/ai/browserslist)表查询选择浏览器 } }], "stage-2" ], // 插件,该插件解决编译中产生的重复的helper函数,减小代码体积 "plugins": ["transform-runtime"], "env": {// 特定环境下执行编译规则 "test": {// env为test时的编译规则 "presets": ["env", "stage-2"],// 同上 "plugins": ["istanbul"]// 测试使用插件 } } }
stage-x和es2015等有些类似,但是它是按照JavaScript的提案阶段区分的,一共有5个阶段。 而数字越小,阶段越靠后,存在依赖关系。也就是说stage-0是包括stage-1的以此类推。
Runtime transform主要有以下options选择。
helpers: boolean,默认true 使用babel的helper函数。
polyfill: boolean,默认true 使用babel的polyfill,但是不能完全取代babel-polyfill。
regenerator: boolean,默认true 使用babel的regenerator。
moduleName: string,默认babel-runtime 使用对应module处理。
这里的options一般不用自己设置,用默认的即可。这个插件最大的作用主要有几下几点:
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。 举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片。
如何写好.babelrc? Babel 入门教程
利用<script>标签没有跨域限制的“漏洞”(历史遗迹啊)来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个<script>元素,地址指向第三方的API网址,形如: <script src="http://www.example.net/api?param1=1¶m2=2"></script> 并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。 第三方产生的响应为json数据的包装(故称之为jsonp,即json padding),形如: callback({"name":"hax","gender":"Male"}) 这样浏览器会调用callback函数,并传递解析后json对象作为参数。本站脚本可在callback函数里处理所传入的数据。 补充:“历史遗迹”的意思就是,如果在今天重新设计的话,也许就不会允许这样简单的跨域了嘿,比如可能像XHR一样按照CORS规范要求服务器发送特定的http头。
<script>
<script src="http://www.example.net/api?param1=1¶m2=2"></script>
callback({"name":"hax","gender":"Male"})
贺师俊知乎回答 说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
同源:两个文档同源需满足
跨域通信:js进行DOM操作、通信时如果目标与当前窗口不满足同源条件,浏览器为了安全会阻止跨域操作。
CORS是一个W3C标准,全称是“跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。 对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。 因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
XSS:跨站脚本(Cross-site scripting,通常简称为XSS)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。
CSRF:跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
用大白话谈谈XSS与CSRF
参考文章: markyun
The text was updated successfully, but these errors were encountered:
什么叫野路子前端?上班时经常出去打野那种吗?
Sorry, something went wrong.
No branches or pull requests
JavaScript原型,原型链 ? 有什么特点?
__proto__
属性指向的是该实例的原型对象JavaScript从原型到原型链
JavaScript有几种类型的值?,你能画一下他们的内存图吗?
栈:原始数据类型(Undefined,Null,Boolean,Number、String)
堆:引用数据类型(对象、数组和函数)
两种类型的区别是:存储位置不同。
原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体
javascript内存空间详解
JavaScript实现乱序
使用
Math.random
乱的不够彻底,可以使用Fisher–Yates算法进行乱序:JavaScript专题之乱序
javascript创建对象的几种方式
缺点:对象无法识别,因为所有的实例都指向一个原型
优点:实例可以识别为一个特定的类型
缺点:每次创建实例时,每个方法都要被创建一次
优点:方法不会重新创建
缺点:
1.所有的属性和方法都共享
2.不能初始化参数
优点:该共享的共享,该私有的私有,使用最广泛的方式
缺点:有的人就是希望全部都写在一起,即更好的封装性
JavaScript深入之创建对象的多种方式以及优缺点
Javascript如何实现继承
缺点:
1.引用类型的属性被所有实例共享
2.在创建 Child 的实例时,不能向Parent传参
优点:
1.避免了引用类型的属性被所有实例共享
2.可以在 Child 中向 Parent 传参
缺点:
方法都在构造函数中定义,每次创建实例都会创建一遍方法。
优点:融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式。
缺点:
包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样。
缺点:跟借用构造函数模式一样,每次创建对象都会创建一遍方法
引用《JavaScript高级程序设计》中对寄生组合式继承的夸赞就是:
这种方式的高效率体现它只调用了一次 Parent 构造函数,并且因此避免了在 Parent.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
JavaScript深入之继承的多种方式和优缺点
Javascript作用域链
函数在调用激活时,会开始创建对应的执行上下文,在执行上下文生成的过程中,变量对象,作用域链,以及this的值会分别被确定。
其中作用域链,在解释器进入到一个执行上下文时,初始化完成并将其分配给当前执行上下文。每个执行上下文的作用域链由当前上下文的变量对象(VO)及父级执行上下文的作用域链构成。
可以理解为:currentScopeChain = currentVO + all parents scopes
JavaScript执行上下文
谈谈this对象的理解
this的指向,是在函数被调用的时候确定的,也就是在创建EC阶段
涉及到this指向问题需要考虑到如下情况:全局下,函数独立调用,对象方法调用,new,call,apply,bind。
关于this的详细解析-->this到底指向哪里
undefined与null的区别
null表示"没有对象",即该处不应该有值。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。
所以设置一个值为 null 是合理的,如:
objA.valueA = null;
但设置一个值为 undefined 是不合理的
undefined与null的区别
["1", "2", "3"].map(parseInt) 答案是多少?
parseInt函数解析一个字符串参数,并返回一个指定基数的整数。
parseInt(string, radix);
radix
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数"10"表示使用我们通常使用的十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常将值默认为10。
返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN。
Array.prototype.map()方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
可以发现
["1", "2", "3"].map(parseInt)
实际执行为:那么最终结果为
[1,NaN,NaN]
Why does parseInt yield NaN with Array#map?
什么是闭包(closure),为什么要用它?
MDN 对闭包的定义为:
那什么是自由变量呢?
由此,我们可以看出闭包共有两部分组成:
ECMAScript中,闭包指的是:
1.即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)
2.在代码中引用了自由变量
JavaScript深入之闭包
对象的类型判断
jQuery中Type API:
JavaScript专题之类型判断(上)
JavaScript专题之类型判断(下)
new操作符具体干了什么
放出一个模拟板:
new运算符模拟实现
===运算符判断相等的流程是怎样的
==运算符判断相等的流程是怎样的
函数内部arguments变量有哪些特性,有哪些属性,如何将它转换为数组
DOM操作 —— 如何添加、移除、移动、复制、创建和查找节点等。
添加
Node.appendChild()方法将一个节点添加到指定父节点的子节点列表末尾。
移除
ChildNode.remove() 方法把从它所属的DOM树中删除对象。
移动
Node.replaceChild()用指定的节点替换当前节点的一个子节点,并返回被替换掉的节点。
复制
Node.cloneNode()方法返回调用该方法的节点的一个副本。
创建
Document.createDocumentFragment() 创建一个新的空白的文档片段。
Document.createElement() 创建由tagName 指定的HTML元素,或一个HTMLUnknownElement,如果tagName不被识别。
document.createTextNode() 创建一个新的文本节点。
查找节点
Element.querySelector()返回与指定的选择器组匹配的元素的后代的第一个元素。
Element.querySelectorAll()返回一个non-live的NodeList, 它包含所有元素的非活动节点,该元素来自与其匹配指定的CSS选择器组的元素。(基础元素本身不包括,即使它匹配。)
document.getElementById()返回一个匹配特定 ID的元素.
Element.getElementsByClassName()Element.getElementsByClassName() 方法返回一个即时更新的(live) HTMLCollection,包含了所有拥有指定 class 的子元素。当在 document 对象上调用此方法时,会检索整个文档,包括根元素。
element.getElementsByTagName()方法返回一个动态的包含所有指定标签名的元素的HTML集合HTMLCollection。指定的元素的子树会被搜索,不包括元素自己。返回的列表是动态的,这意味着它会随着DOM树的变化自动更新自身。所以,使用相同元素和相同参数时,没有必要多次的调用Element.getElementsByTagName() .
事件 —— 如何使用事件,以及IE和标准DOM事件模型之间存在的差别。
addEventListener:绑定事件的监听函数
removeEventListener:移除事件的监听函数
dispatchEvent:触发事件
DOM提供三种方法,可以用来为事件绑定监听函数。
事件模型
DOM事件的绑定的几种方式
XMLHttpRequest —— 这是什么、怎样完整地执行一次GET请求、怎样检测错误。
AJAX
什么是window对象
window对象在浏览器中,window对象(注意,w为小写)指当前的浏览器窗口。它也是所有对象的顶层对象
什么是document对象
document节点是文档的根节点,每张网页都有自己的document节点。window.document属性就指向这个节点。只要浏览器开始载入HTML文档,这个节点对象就存在了,可以直接调用。
cookies,sessionStorage 和 localStorage 的区别?
cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。
cookie数据始终在同源的http请求中携带(即使不需要),即会在浏览器和服务器间来回传递。
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
存储大小:
有期时间:
共享:
localStorage的修改会促发其他文档窗口的update事件
通用的事件侦听器函数
target和currentTarget的区别
Event.target一个触发事件的对象的引用。它与event.currentTarget不同, 当事件处理程序在事件的冒泡或捕获阶段被调用时。
event.currentTarget当事件遍历DOM时,标识事件的当前目标。它总是引用事件处理程序附加到的元素,而不是event.target,它标识事件发生的元素。
e.target与e.currentTarget的区别
模块化开发
JS模块化方案很多,AMD/CommonJS/UMD/ES6 Module等。
由于nodejs流行所以现在CommonJS规范使用的人数较多,当然ES6 Module应该会慢慢成为主流,至于AMD和CMD由于seajs和requirejs使用越来越少所以这两个规范的应用应该也是一样吧。
实现一个 CMD 模块加载器
3.1 如果有,继续加载其子模块,并在子模块上绑定 “complete” 事件,来触发本身 的 “complete” 事件;
3.2 如果没有则直接触发本身的 “complete” 事件。
3.3 如果子模块中还有依赖,则会递归这个过程。
如何实现一个 CMD 模块加载器
前端模块化、组件化
ECMAScript6 为什么会出现class这种东西?
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
Class 的基本语法
.call() 和 .apply() 的区别
我们可以知道call()方法的作用和 apply() 方法类似,只有一个区别,就是 call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。
JavaScript模拟实现call,apply,bind等方法
数组和对象有哪些原生方法
Object构造函数创建一个对象包装器。
Array用于构造数组的全局对象
Array对象
JavaScript中的作用域与变量声明提升
创建变量对象过程:
从创建变量对象步骤1,,2,3可以发现这就是我们常说的变量提升和函数声明优先级高于变量声明的原因。
JavaScript执行上下文
如何实现深拷贝?
数组的浅拷贝
利用数组的一些方法比如:slice、concat 返回一个新数组的特性来实现拷贝。
手动实现一个浅拷贝:
我们把这种复制引用的拷贝方法称之为浅拷贝,与之对应的就是深拷贝,深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
数组的深拷贝
这是一个简单粗暴的好方法,就是有一个问题,不能拷贝函数。
手动实现一个深拷贝:
尽管使用深拷贝会完全的克隆一个新对象,不会产生副作用,但是深拷贝因为使用递归,性能会不如浅拷贝,在开发中,还是要根据实际情况进行选择。
JavaScript专题之深浅拷贝
jQuery 的属性拷贝(extend)的实现原理是什么?
extend 的用法:
jQuery.extend( [deep], target, object1 [, objectN ] )
函数的第一个参数可以传一个布尔值,如果为 true,我们就会进行深拷贝,false 依然当做浅拷贝。 target,表示要拓展的目标,我们就称它为目标对象吧。
后面的参数,都传入对象,内容都会复制到目标对象中,我们就称它们为待复制对象吧。
实现思路:
核心的部分还是跟实现深浅拷贝函数一致,如果要复制的对象的属性值是一个对象,就递归调用 extend。不过 extend 的实现中,多了很多细节上的判断,比如第一个参数是否是布尔值,target 是否是一个对象,不传参数时的默认值等。
以上实现和jQuery中版本还有一定差别,详细内容-->JavaScript专题之从零实现jQuery的extend
谈一下Jquery中的bind(),live(),delegate(),on()的区别?
bind()
.bind()方法将事件类型和一个事件处理函数直接注册到了被选中的DOM元素中。
live()
.live()方法将与事件处理函数关联的选择器和事件信息一起附加到文档的根级元素(即document)。通过将事件信息注册到document上,这个事件处理函数将允许所有冒泡到document的事件调用它(例如委托型、传播型事件)。一旦有一个事件冒泡到document元素上,Jquery会根据选择器或者事件的元数据来决定哪一个事件处理函数应该被调用,如果这个事件处理函数存在的话。这个额外的工作将会在用户交互时对性能方面造成一定的影响,但是初始化注册事件的过程相当地快。
delegate()
.delegate()方法与.live()方式实现方式相类似,它不是将选择器或者事件信息附加到document,而是让你指定附加的元素。就像是.live()方法一样,这个方法使用事件委托来正确地工作。
on()
Jquery 1.7版本中.bind(),.live() 和.delegate()方法只需要使用.on()方法一种方式来调用它们。
如何使用.on()方法决定了它如何调用其他方法。你可以认为.on()方法被具有不同签名的方法”重载“了,而这些方法实现了不同的事件绑定的连接方式。
[译] Jquery中 .bind() .live() .delegate() 和 .on() 之间的区别
JS之事件节流
节流的原理很简单:
如果你持续触发事件,每隔一段时间,只执行一次事件。
关于节流的实现,有两种主流的实现方式,一种是使用时间戳,一种是设置定时器。
JavaScript专题之跟着 underscore 学节流
JS的函数防抖
简单解释一下debounce的原理:
在持续触发某个事件时,该事件的回调函数不会立即触发,而是在最后一个触发事件结束一段时间后去执行回调函数。
我们会为目标函数设置一个定时器,当定时器未执行时,事件再次被触发,则清除当前的定时器,然后设置新的定时器,直到定时器timeout执行目标函数。
_.debounce源码学习
JavaScript专题之跟着underscore学防抖
Babel了解?
Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。
如下是一个简单的babel配置文件
.babelrc
stage-x
stage-x和es2015等有些类似,但是它是按照JavaScript的提案阶段区分的,一共有5个阶段。
而数字越小,阶段越靠后,存在依赖关系。也就是说stage-0是包括stage-1的以此类推。
transform-runtime
Runtime transform主要有以下options选择。
helpers: boolean,默认true
使用babel的helper函数。
polyfill: boolean,默认true
使用babel的polyfill,但是不能完全取代babel-polyfill。
regenerator: boolean,默认true
使用babel的regenerator。
moduleName: string,默认babel-runtime
使用对应module处理。
这里的options一般不用自己设置,用默认的即可。这个插件最大的作用主要有几下几点:
babel-polyfill
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。
举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片。
如何写好.babelrc?
Babel 入门教程
JSONP 的工作原理是什么?
利用
<script>
标签没有跨域限制的“漏洞”(历史遗迹啊)来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个<script>
元素,地址指向第三方的API网址,形如:<script src="http://www.example.net/api?param1=1¶m2=2"></script>
并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。 第三方产生的响应为json数据的包装(故称之为jsonp,即json padding),形如:callback({"name":"hax","gender":"Male"})
这样浏览器会调用callback函数,并传递解析后json对象作为参数。本站脚本可在callback函数里处理所传入的数据。补充:“历史遗迹”的意思就是,如果在今天重新设计的话,也许就不会允许这样简单的跨域了嘿,比如可能像XHR一样按照CORS规范要求服务器发送特定的http头。
贺师俊知乎回答
说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
CORS通信
同源:两个文档同源需满足
跨域通信:js进行DOM操作、通信时如果目标与当前窗口不满足同源条件,浏览器为了安全会阻止跨域操作。
CORS是一个W3C标准,全称是“跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
了解XSS和CSRF
XSS:跨站脚本(Cross-site scripting,通常简称为XSS)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。
CSRF:跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
用大白话谈谈XSS与CSRF
参考文章:
markyun
The text was updated successfully, but these errors were encountered: