解决3:Object.prototype.toString.call({}) //正常是call传进去this,然后改变this指向,在这里传进去[],那么[]数组就代表this 返回结果为"[object Array]"
Object.prototype.toString.call([]) //这个返回是"[object Object]"
Object.prototype.toString.call(13) //这个返回是"[object Number]"
67.this(在视频中this笔试真题讲解的部分,这两节主要是讲例题,此处例题在另一个文档中)
1.函数预编译过程中this指的是1window
例1:
function test(c){ //正常不经过new,this指的就是window,当对test进行new的话,test内部就会发生变化,本来AO中this指的是window,但是要是经过new之后,this就指的就是 Object.create(test.prototype)
//var this = Object.create(test.prototype); 这是最精准的写法,下面的三行实现的是和这行一样的功能,但是这个比较精准
/* var this = {
__proto__ : test.prototype,
};*/
var a = 10;
function b (){
}
}
var AO = {
arguments : [1], //其次还会生成以下两行,
this : window,
c : 1, //首先我们了解的,AO中会生成以下三行。
a : 1,
b : function b(){
}
}
test(1);
new test ();
2.全局作用域里this指的是window,也就是直接打印console.log(this) 是window
3.call/apply可以改变函数运行时this指向。
4.谁调用这个方法,这个方法里的this指的就是谁
假如这个方法在全局范围内执行,里面的this指的是window,因为没人调用它,进行空执行,走预编译,然后指的就是window
也就是obj.func(); func里面的this指的是obj
this笔试真题讲解
例1:最终结果为1,2,3,4,5
function foo(){
bar.apply(null,arguments); //这个是将arguments作为参数传给了bar里面去,所以bar里有实参是一个数组,
}
function bar(){
console.log(arguments); //传进来的实参被传进arguments中去了,然后打印就是1,2,3,4,5
}
foo(1,2,3,4,5);
例2:this指向问题
var name = "222";
var a = {
name : "111",
say : function (){
console.log(this.name);
}
}
var fun = a.say; //这个a.say只是一个函数引用,就相当于将a中的function拿出来了,函数是在外面执行的,这时this指的是window中的name
fun();
a.say(); //这个不用说,a调用say(),this肯定指向a。
var b = {
name : "333",
say : function (fun){
fun();
}
}
b.say(a.say); /* b.say()执行时,这时的this的确指的是b,但是里面参传进去的参数a.say是个函数引用,这个函数引用被谁也没调用所以执行时走的是预编译环节,this指的是window和b无关,要是把对象b中fun()改为this.fun(),那结果就是333了 */
b.say = a.say; /*将a.say这个函数赋给b*/
b.say(); /*这个就是b自己调用say并执行,所以this指向b*/
最后一个可以这样理解:
var a = 100;
var deng = {
a : 200,
say : function (){
console.log(a); //打印a肯定是100,要是打印this.a那就是200
}
}
同理:
function test (){
console.log(this);
}
var test1 = {
say : function (){
test(); //打印的也是window,自己一个人执行,谁也没调用。
}
}
68.arguments(caller不是arguments上面的属性,arguments属性只有callee和length)
1.一共就一个用法,arguments.callee指向函数自身引用。在哪个函数里面就指向哪个函数。
例1:
function test(){
console.log(arguments.callee); //等价于test
}
test();
例2:利用立即执行函数实现阶乘运算,因为立即执行函数执行后会被立即销毁,所以就利用到了arguments.callee实现多次调用。
var num = (function (n){
if(n == 1){
return 1;
}
return n * arguments.callee(n - 1);
}(10))
2.func.caller中的caller是函数自己的属性,指向函数被调用的那个环境(也就是代指谁调用它的)
例1:
function test(){
demo(); //在test内部被调用执行,所以打印demo.caller结果就是test这个函数。
}
function demo(){
console.log(demo.caller);
}
test();
视频此处开始讲题即this笔试真题下的19分钟开始。题以及答案见另一个文档。
知识点补充:未声明就使用变量报错,放在typeof中不报错。
69.克隆
1.浅层克隆:原始值克隆,只拷值。(克隆后target对象属性改变,对自己没影响)
例1:
var liu = {
name : 'LFY',
age : 21,
}
function clone(origin , target){
var target = target || {}; //如果自己有原材料那就将原材料传进去进行克隆,如果没有原材料,那就target = {} 然后在进行克隆,将target对象返回
for(var prop in liu){
target[prop] = origin[prop];
}
return target;
}
var obj = clone(liu);
例2:当属性值为数组时,我将car进行改变 obj.car.push('LFY'); 然后访问liu.car的值也改变了。
var liu = {
name : 'LFY',
age : 21,
car :['visa' , 'unionpay'],
}
function clone(origin , target){
var target = target || {};
for(var prop in liu){
target[prop] = origin[prop];
}
return target;
}
var obj = clone(liu);
2.深层克隆:
(1)判断是不是原始值
(2)判断数组还是对象(数组也能for in 因为数组也算特殊类型的对象,prop代表索引位)
(3)建立相应数组或对象
(4)将引用值重新当作一个对象再次进行拷贝,循环往复1234
例1:
var obj = {
name : "abd",
age : 123,
card : ['visa' , 'master'],
wife : {
name :'bcd',
son : {
name : 'abcds',
}
}
}
var obj1 = {};
function deepClone(origin , target){
var target = target || {}; //传进去原材料(target)时,用自己的,没有对象时,用工厂原材料(也就是新建的空对象)完成克隆。
var toStr = Object.prototype.toString;
var arrStr = "[object Array]"
for(var prop in origin){
if(origin.hasOwnProperty(prop)){
if(origin[prop] !== "null" && typeof(origin[prop]) == 'object' ){ //判断是不是引用类型(值既不是null又是Object类型)
target[prop] = toStr.call(origin[prop]) == arrStr ? [] :{}; //引用类型再具体判断 是数组还是对象(target[prop] = toStr.call(origin[prop]) == arrStr ? [] :{};这个语句可以改为if else,但是这个语句更加简便)
/*if(toStr.call(origin[prop]) == arrStr){ //以下六行等价于上面那行,用三目运算符比较简洁。
target[prop] = [];
}
else{
target[prop] = {};
}*/
deepClone(origin[prop] , target[prop]); //将引用值作为对象再次进行拷贝
}
else { //当值为原始值时就是这个函数的出口
target[prop] = origin[prop];
}
}
}
return target; //当没有对象传进来时,就将一个空对象进行克隆,返回
}
3.三目运算符:其实实质上就是if else,但是有个比if else强大的就是会有返回值,相当于在if else中加了个return。
(1)格式:条件判断?是:否
例1: var num = 1 > 0 ? 2 + 2 : 1 + 1; //num=4;
例2: var num = 1 > 0 ?("10" > "9" ? 1 : 0) : 2; //括号中"10"和"9"比较的是ASCII码,"10"是两位字符串写,先1和9的ASCII码进行比较,"1"小于"9"。