J44 原型练习题

309 阅读6分钟

1.题目: 实现函数fn,让其具有如下功能

let res = fn(1,2)(3);
console.log(res); //=>6  1+2+3

//方法一:
function fn(x, y) {
	return function (z) {
		return x + y + z;
	}
}
let res = fn(1, 2)(3);
//=>先让FN执行,执行的返回结果再执行(返回结果一定是个函数
//把返回的小函数执行,最后小函数返回的结果是把,这几次传递的实参依次相加
console.log(res); //=>6  1+2+3 

//方法二:
function fn() {
	// 执行FN传递的进来的实参集合  Array.from()把类数组转换为数组
	let outerArg = Array.from(arguments);
	return function () {
// 执行返回的小函数,传递进来的实参集合
		let innerArg = Array.from(arguments);
		outerArg = outerArg.concat(innerArg);
// 把数组按照"+"变为每一项相加的字符串,再基于EVAL把字符串变为表达式执行
		return eval(outerArg.join('+'));
	}
}
let res = fn(1, 2)(3);
console.log(res); //=>6  1+2+3 

//=>方案三:基于ES6中的箭头函数来优化
let fn = (x, y) => (z) => x + y + z;
let res = fn(1, 2)(3);
console.log(res); //=>6

2.this计算题

var x = 2;
var y = {
	x: 3,
	z: (function (x) {
		this.x *= x;
		x += 2;
		return function (n) {
			this.x *= n;
			x += 3;
			console.log(x);
		}
	})(x)
};
var m = y.z;
m(4);
y.z(5);
console.log(x, y.x);//=>16   15

3.原型练习题

function Fn(n, m) {
	n = n || 0;
	m = m || 0;
	this.x = n;
	this.y = m;
	this.getX = function () {
		console.log(this.x);
	}
	return n + m;  
}
Fn.prototype.sum = function () {
	console.log(this.x + this.y);
}
Fn.prototype = {
	getX: function () {
		this.x += 1;
		console.log(this.x);
	},
	getY: function () {
		this.y -= 1;
		console.log(this.y);
	}
};
let f1 = new Fn(10, 20);
let f2 = new Fn;

console.log(f1.getX === f2.getX); //=>false  都是私有的

console.log(f1.getY === f2.getY); //=>true  都是公有的

// 都是找原型上的方法(值得注意的是:在IE浏览器中是不允许我们直接操作 __proto__)
console.log(f1.__proto__.getY === Fn.prototype.getY); //=>true

console.log(Fn.prototype.getX === f2.getX); //=>false  原型上的 VS 私有的

console.log(f1.constructor); //=>Object

f1.getX();
// 执行的是私有的getX;方法中的this:f1;console.log(this.x) => f1.x => 10

Fn.prototype.getX();
// 执行的是公有的getX;方法中的this:Fn.prototype;
// this.x += 1    Fn.prototype.x=Fn.prototype.x+1=undefined+1=NaN
// console.log(this.x); => Fn.prototype.x => NaN

f2.getY();
// 执行的是公有的getY;方法中的this:f2;
// this.y -= 1;   f2.y=f2.y-1=0-1=-1
// console.log(this.y);  => f2.y => -1

Fn.prototype.getY();
// 执行的是公有的getY;方法中的this:Fn.prototype;
// this.y -= 1;   Fn.prototype.y=Fn.prototype.y-1=undefined-1=NaN
// console.log(this.y);  => Fn.prototype.y => NaN

f1.sum();
// f1.sum => undefined
// undefined() :报错,f1.sum is not a function

//忽略:上面代码的原型优化  Fn.prototype.sum = function () {
	console.log(this.x + this.y);
}
let obj = {
	// constructor: Fn,
	getX: function () {
		this.x += 1;
		console.log(this.x);
	},
	getY: function () {
		this.y -= 1;
		console.log(this.y);
	}
};
// Object.assign(obj1,obj2)把两个对象进行合并,合并过程中,有冲突的属性以obj2为主,
剩余的不冲突的都合并在一起,返回一个合并后的新对象
Fn.prototype = Object.assign(Fn.prototype, obj);

4.原型链计算题

function fun() {
	this.a = 0;
	this.b = function () {
		alert(this.a);
	}
}
fun.prototype = {
	b: function () {
		this.a = 20;
		alert(this.a);
	},
	c: function () {
		this.a = 30;
		alert(this.a)
	}
}
var my_fun = new fun(); //=>fun是一个类  my_fun它的一个实例
// 实例私有属性:{a:0,b:function...}   my_fun
// 实例公有属性:{b:function...,c:function...}

my_fun.b();
// 执行的是私有方法b;this=>my_fun;
// alert(this.a); => my_fun.a  =>"0"

my_fun.c();
// 执行的是公有方法c;this=>my_fun;
// this.a = 30;  => my_fun.a=30 把自己的私有属性a的值修改为30
// alert(this.a) => "30"

5.原型链计算题

function C1(name) {
	// name = undefined
	if (name) { //=>if(undefined)
		// 条件不成立,也就不执行这句话(没有给实例设置私有的属性NAME)
		this.name = name;
	}
}
function C2(name) {
	// name = undefined
	this.name = name; //=>给实例设置一个私有的属性NAME,属性值是UNDEFINED
}
function C3(name) {
	// name = undefined
	this.name = name || 'join'; //=>给实例设置了一个私有的属性NAME,属性值'JOIN'
}
C1.prototype.name = 'Tom';
C2.prototype.name = 'Tom';
C3.prototype.name = 'Tom';

alert((new C1().name) + (new C2().name) + (new C3().name));
// new C1().name  创建C1类的一个实例,调取实例上的NAME  =>"Tom"
// new C2().name  =>"undefined"
// new C3().name  =>'join'
// =>"Tomundefinedjoin" 

6.原型链计算题

function Fn() {
	let a = 1;
	this.a = a;
}
Fn.prototype.say = function () {
	this.a = 2;
}
Fn.prototype = new Fn;
let f1 = new Fn;
Fn.prototype.b = function () {
	this.a = 3;
};
console.log(f1.a); //=>1  私有属性
console.log(f1.prototype); //=>undefined 
// 只有函数有原型prototype属性,实例是不存在这个属性的
console.log(f1.b); //=>f (){this.a = 3;} 这个函数
console.log(f1.hasOwnProperty('b')); //=>false 因为不是它的私有属性
console.log('b' in f1); //=>true
console.log(f1.constructor == Fn); //=>true 

7.原型链计算题

function Person() {
	this.name = 'Hello';
}
Person.prototype.getName = function () {
	console.log(this.name);
	console.log(this.age);
};
Person.prototype.age = 5000;
//实例对象
//  per1 = {
//  //=>私有属性
//   name : 'Hello',
//   age : 9,
//   __proto__ : {
//   //=>原型上公有的属性和方法
//   getName : function...,
//   age : 5000
//    }
// } 
//
var per1 = new Person;
per1.getName();
// 执行的是公有方法;this=>per1;
// this.name => per1.name => 'Hello'  私有
// this.age => per1.age => 5000  公有
per1.age = 9; //=>给PER1这个实例对象设置私有属性AGE=9
per1.getName();
// 执行的是公有方法;this=>per1;
// this.name => per1.name => 'Hello'  私有
// this.age => per1.age => 9  私有
console.log(per1.age); //=>9

//  per2 = {
// 	  //=>私有属性
//     name : 'Hello',
//    __proto__ : {
//       //=>原型上公有的属性和方法
//       getName : function...,
//       age : 5000
//    }
// } 
var per2 = new Person;
console.log(per2.age); //=>5000

8.编写程序实现如下效果

let n = 10;
let m = n.plus(10).minus(5);
console.log(m);//=>15(10+10-5)

//提示:在Number.prototype上扩展方法,这样所有的数字都可以调取这些方法了

Number.prototype.plus = function plus(n) {
	// this:当前操作的这个数字
	return this + n;
};

Number.prototype.minus = function minus(n) {
	return this - n;
};

let n = 10;
let m = n.plus(10).minus(5);
//=>为了能够调用链式写法,需要保证PLUS/MINUS方法执行完的返回结果依然是一个数字
console.log(m); //=>15 

9.编写程序实现如下效果

let ary = [12,23,12,13,13,12,23,14,8];
ary.unique().sort((a,b)=>a-b);
//=> 最后的ary等于[8,12,13,14,23]

Array.prototype.unique = function unique() {
// this:一般都是当前Array类的一个实例(我们要操作的数组)set 是去重
	return Array.from(new Set(this));
};
let ary = [12, 23, 12, 13, 13, 12, 23, 14, 8];
ary = ary.unique().sort((a, b) => a - b);
console.log(ary);

10. 一个url后面好多key:value,如localhost?key=val&key2=val2&key3=val3,封装一个函数 getParam(‘key’) 通过key获得相应等号后面的值

let url="locallhost?key1=val1&key2=val2&key3=val3";
console.log(url.getParam("key3")); 
//=>'val3'

String.prototype.getParams = function getParams(attr) {
	// 1.获取字符串中问号后面传参的值,以对象键值对的方式进行存储
	let askIndex = this.indexOf('?'),
		polIndex = this.indexOf('#'),
		askText = '',
		obj = {};
	if (askIndex > -1) {
		polIndex === -1 ? polIndex = this.length : null;
		askText = this.substring(askIndex + 1, polIndex);
	}
	askText = askText.split('&'); //=>["key1=val1", "key2=val2", "key3=val3"]
	askText.forEach(item => {
		item = item.split('='); //=>["key1", "val1"] ...
		obj[item[0]] = item[1];
	});
// console.log(obj); //=>{key1: "val1", key2: "val2", key3: "val3"}
// 2.根据传递的属性名到对象中找到对应的属性值(如果没有这个属性,不让其返回UNDEFINED,而是让其返回空字符串)
	return obj[attr] || "";
};
let url = "locallhost?key1=val1&key2=val2&key3=val3";
console.log(url.getParams("aaa")); 

11.下面代码a在什么值情况下会输出1

var a = ?;
if (a == 1 && a == 2 && a == 3) {
	console.log(1);
}

/*  解决方案一
 *   ==和===的区别? 
 *    1\. ==进行比较的时候,两边数据类型不一致,
       //则先转换为相同的数据类型,然后再进行比较
 *    2\. 除了 对象==字符串 是把对象转换为字符串,其余的都是转换为数字
 //(其中比较特殊的是对象,对象转换为数字,首先要把他转换为字符串  =>  toString 方法)
 */

 var a = {
	n: 0,
	toString: function () {
		// a.toString() : this=>a
		return ++this.n;
	}
};
if (a == 1 && a == 2 && a == 3) {
	console.log('OK');
}

//2\. 让每一次toString的时候都执行shift,
//删除数组中的第一项,每一次删除返回的结果就是删除的这一项

var a = [1, 2, 3];
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
	console.log('OK');
}

/*
 * 3.解决方案二
 *   Object.defineProperty:监听某个对象的某个属性,可以在获取或者设置属性的值的时候,做一些自己要做的事情(Vue框架MVVM实现的原理就是基于这个完成的) =>同样原理的还可以使用Proxy代理处理
 *   
 *   全局上下文中变量不带VAR相当于给全局window设置一个属性
 */
var i = 0;
Object.defineProperty(window, 'a', {
	get() {
		// 只要获取a的值,就一定会触发get方法执行
		return ++i;
	}
});
if (a === 1 && a === 2 && a === 3) {
	console.log('OK');
}
/* console.log(obj.toString()); //=>"[object Object]"  它是obj实例基于__proto__找到Object.prototype上的toString方法,然后去执行的 

let obj = {
	n: 0,
	toString: function () {
		return 'OK';
	}
};
console.log(obj.toString()); //=>"OK" 此处执行的是自己的私有方法(私有中有,就不会再向原型上进行查找了)
*/

12.下面代码的输出结果?为什么?

let obj = {
		2: 3,
		3: 4,
		length: 2,
		push: Array.prototype.push
	}
	obj.push(1);
	obj.push(2);
	console.log(obj);
	let obj = {
		n: 0
	};

// obj.push调取的是私有的属性方法 => Array.prototype.push
// obj.push(1) 相当于让Array原型上的push方法执行
 Array.prototype.push = function push(n) {
	// 给数组THIS(操作的这个实例)末尾追加新的值
	this[this.length] = n;
	// 1.不仅新增内容到了末尾
	// 2.而且让数组的长度LENGTH累加1
	return this.length;
};
arr.push(100); 

let obj = {
	2: 3,
	3: 4,
	length: 2,
	push: Array.prototype.push
};
obj.push(1);
/*
 * n=1  this:obj
 *   obj[obj.length]=1 => obj[2]=1 => {2:1,3:4...}
 *   length累加1 => {2:1,3:4,length:3...}
 */
obj.push(2);
/*
 * n=2  this:obj 
 *   this[this.length]=n => obj[obj.length]=2 => obj[3]=2 => {2:1,3:2,length:3...}
 *   length++  => {2:1,3:2,length:4...}
 */
console.log(obj); //=>{2: 1, 3: 2, length: 4, push: ƒ}