第五期
typeof运算符和instanceof运算符以及isPrototypeOf()方法的区别
typeof
一般用来判断基础类型,他的返回值是一个字符串,返回值的值分别为:string、number、boolean、object、function、undefined;凡是用new创建的实例,返回的都是object。
instanceof
一般用来判断某个实例是否属于某种类型;一般通过原型关系来判断。以下是常见的例子:
alert(Object instanceof Object);//true
alert(Function instanceof Function);//true
alert(Function instanceof Object);//true
alert(String instanceof String);//false
alert(Number instanceof Number);//false
alert(Boolean instanceof Boolean);//false
isPrototypeOf
判断某对象是否是指定实例的原型;需要注意的是:该方法不会检查原型链中的对象。即:只检查本实例的直接原型,不会检查本实例的原型的原型。
function ClassA(){}
function ClassB(){}
function ClassC(){}
/**
* ClassB的原型设为ClassA,ClassC的原型设为ClassB
* 注意:这与原型继承不同
*/
ClassB.prototype = ClassA;
ClassC.prototype = ClassB;
var b = new ClassB();
var c = new ClassC();
alert(ClassA.isPrototypeOf(b));//true
alert(ClassB.isPrototypeOf(c));//true
alert(ClassA.isPrototypeOf(c));//false
描述以下变量的区别:null,undefined或undeclared
null 变量声明了然后赋值为null,是一个空的指针引用
undefined 是变量声明了但是还没有赋值,使用的时候就是undefined
undeclared 是没有声明,也就是没使用var关键字,如果赋值的话,会被创建于global object中,没赋值的话直接报语法错误,not defined。不同null,undefined是语言类型, undeclared是语法错误。
undeclared属于语法错误,'use strict' 下会避免此类语法错误。
BFC,IFC,FFC的区别
在了解上述区别的时候,先了解FC,FC是Formatting Context,格式化上下文。指页面中一个渲染区域,拥有一套渲染规则,它决定了其子元素如何定位,以及与其他元素的相互关系和作用。
BFC:Block块级格式化上下文,它会形成一个块,块里面的样式操作不会影响块外面的布局,一般用于防止外边距塌陷,浮动布局。
IFC:Inline行内格式化上下文,它没有固定的高度,高度是其包裹元素的最大高度,一般用来形成行内块级元素,用于线性排列。相关联的两个常用属性:inline-block、text-align、vertical-align。
GFC:Grid布局,网格布局,当display设置为grid的时候生效。
FFC:Flex自适应格式化上下文,伸缩布局,也叫弹性布局。
如何用网页脚本追踪用户
这个问题摘自阮一峰网络日志2019年4月15号如何用网页脚本追踪用户
目的是收集用户信息。
初始是通过延迟页面卸载来保证异步请求的成功。主要思路是延迟unload的执行;文中提到两个方法,一个耗时循环,两一个是setTimeout。
还有一种做法是反弹追踪,就是网页跳转时,先跳到一个或多个中间网址,以便收集信息,然后再跳转到原来的目标网址。
上面两种方式严重影响用户体验;浏览器专门实现了一个api来帮助我们,navigator.sendBeacon()方法可以保证,异步请求一定会发出。第一个参数是请求的网址,第二个参数是发送的数据。注意,Beacon API 发出的是 POST 请求。
还有一种方式是ping属性;HTML 的<a>
标签有一个ping属性,只要用户点击,就会向该属性指定的网址,发出一个 POST 请求。ping属性无法指定数据体,似乎只能通过 URL 的查询字符串携带信息。
prototype
、constructor
、arguments.callee
、caller
分别是什么意思
prototype是函数的特性,一般用于构造函数,通过构造函数创建的实例,我们有两种添加属性的方式,一种是通过实例添加;另一种是通过构造函数添加;
function employee(name,job,born){
this.name=name;
this.job=job;
this.born=born;
}
var bill=new employee("Bill Gates","Engineer",1985);
employee.prototype.salary=null;
bill.salary=20000;
通过实例添加的属性专属于当前实例,不会共享于其他通过此构造函数创建的实例;但是通过构造函数的prototype添加的属性会共享。
而且通过prototype添加的属性会直接添加到实例的__proto__下面。
constructor是实例的特性,它用来判断实例是通过哪个构造函数创建的,而且它是可以修改的,所以用它来判断不是很准确。
constructor还是class类中必不可少的属性,用于创建和初始化class创建的对象的特殊方法。用于定义类中的私有属性。
arguments.callee表示当前正在执行的函数,它常用在匿名函数中实现递归;
[1,2,3,4,5].map(function (n) {
return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
})
但它不是一个很好的解决方案,因为在严格模式下arguments会有限制,另一个原因是递归调用会获取到一个不同的 this 值。
var global = this;
var sillyFunction = function (recursed) {
if (!recursed) { return arguments.callee(true); }
if (this !== global) {
alert("This is: " + this);
} else {
alert("This is the global");
}
}
sillyFunction();
有一个很好的解决方式是使用内联函数:
var factorial = (function f(num) {
if (num <= 1) {
return 1;
} else {
return num*f(num - 1);
}
});
console.log(factorial(5)); // 120
var anothorFactorial = factorial;
factorial = null;
console.log(anothorFactorial(5)); // 120
还有一种解决方案是尾递归:
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1) // 120
由此可见,“尾调用优化”对递归操作意义重大,所以一些函数式编程语言将其写入了语言规格。ES6 亦是如此,第一次明确规定,所有 ECMAScript 的实现,都必须部署“尾调用优化”。这就是说,ES6 中只要使用尾递归,就不会发生栈溢出(或者层层递归造成的超时),相对节省内存。
ECMAScript 6 入门 --阮一峰
caller:返回调用指定函数的函数。 arguments.caller 已经废弃,但是你还可以使用 Function.caller。
我们常用caller来判断当前上下文。
如果一个函数f是在全局作用域内被调用的,则f.caller为null,相反,如果一个函数是在另外一个函数作用域内被调用的,则f.caller指向调用它的那个函数.
function myFunc() {
if (myFunc.caller == null) {
alert("该函数在全局作用域内被调用!");
} else{
alert("调用我的是函数是" + myFunc.caller);
}
}
function f(){
myFunc()
}
f()//"调用我的是函数是f"
myFunc()//该函数在全局作用域内被调用!