- 动态调用方法
- 练习 - 调用数组里面的每一个函数
- 练习 - 用函数去删除多个对象的 x 属性
- 动态调用对象的方法
- 练习 - 用方法名动态去调用方法
- 练习 - 处理方法不存在的情况
- 练习 - 动态调用 + 传参数
- 练习 - 处理某个属性不是方法的问题
- 练习 - 绑定 this 为对象本身
- 获取对象的元数据
- 练习 - 找出对象所有大于 0 的属性名
- 练习 - 找出原型对象的属性名
- 练习 - 找出数组的所有属性名
- 练习 - 找出接受两个参数以上的方法
- 练习 - 把全局函数按字母排序
- 生成类型
- 练习 - 手撕一个有 10 个属性的类型
- 练习 - 动态生成 100 个属性
- 练习 - 动态生成 100 个方法
- 练习 - 动态生成 100 个全局函数
- 练习 - 动态生成 100 个类型 **(未完成)**
- 生成函数的函数
- 练习 - 生成某个固定值的函数
- 练习 - 返回保留头 n 的数字元素的函数
- 练习 - 生成嵌套调用方法的函数
- 如果函数体没有 this 关键词,你可以直接忽略 call 和 apply 的第一个参数(因为它并不会被用到)。
let fn = function(a, b, c) {
return a + b + c;
}
fn(1, 2, 3);
fn.call(undefined, 1, 2, 3);
fn.apply(undefined, [1, 2, 3]);
- 你可以吧 this 当做一个特别的参数,用 call 或者 apply 传进去。比如我们想设定某个对象的 x 属性,可以用 call 去把 this 传递进去:
function setX(value) {
this.x = value;
}
let a = {};
// a.x = 10;
setX.call(a, 10);
setX.apply(a, [10]);
function fn1() {
console.log("fn1");
}
function fn2() {
console.log("fn2");
}
function fn3() {
console.log("fn3");
}
let functions = [fn1, fn2, fn3];
// 写一个循环去调用 functions 里面的每一个元素
// 每个元素都调用 3 次。
/*
输出:
fn1
fn1
fn1
fn2
fn2
fn2
fn3
fn3
fn3
*/
functions.forEach(x=>{
for(let i=0;i<3;i++)
x();
});
function deleteX() {
delete this["x"];
}
let objects = [
{a: 1, x: 1},
{a: 2, x: 2},
{a: 3, x: 3},
];
// 写一个循环去删除每个对象的 x 属性。
console.log(objects);
/*
输出:
[
{a: 1},
{a: 2},
{a: 3},
]
*/
objects.map(x=>deleteX.call(x));
let o = {
methodA() {
return 1;
},
methodB() {
return 2;
}
}
let methods = ["methodA", "methodB"];
let results = {};
// 1. 动态调用 methods 数组里面指定的方法,收集结果到 results 字典里面
methods.forEach(methodName => {
let result = o[methodName]();
results[methodName] = result;
});
/*
result 输出应该是:
{
methodA: 1,
methodB: 2,
}
*/
let o = {
methodA() {
return 1;
},
methodB() {
return 2;
}
}
let methods = ["methodA", "methodB", "methodC"];
let results = {};
// 1. 动态调用 methods 数组里面指定的方法,收集结果到 results 字典里面
// 2. 如果方法不存在,收集 undefined 到字典里面
methods.forEach(methodName => {
if(o[methodName]==null){
results[methodName] = undefined;
}else{
let result = o[methodName]();
results[methodName] = result;
}
});
let o = {
add1(x) {
return x + 1;
},
add(x, y) {
return x + y;
}
}
let methods = [["add1", 10], ["add1", 30], ["add", 10, 20], ["foobar", 10]];
// 1. 动态调用 methods 数组里面指定的方法,并传参。收集结果到 results 数组里面
// 2. 如果方法不存在,收集 undefined 到数组里面
let results = [];
/*
results 输出应该是:
[11, 31, 30, undefined]
*/
methods.forEach(methodName => {
let result;
if(o[methodName[0]]==null){
result = undefined;
}else if(methodName.length==2){
result = o[methodName[0]].call(undefined,methodName[1]);
}else{
result = o[methodName[0]].call(undefined,methodName[1],methodName[2]);
}
results.push(result);
});
let o = {
add1(x) {
return x + 1;
},
add(x, y) {
return x + y;
},
name: "crappy calculator",
}
let methods = [
["add1", 10],
["add1", 30],
["add", 10, 20],
["foobar", 10],
["name"],
];
// 1. 动态调用 methods 数组里面指定的方法,并传参。收集结果到 results 数组里面
// 2. 如果方法不存在,收集 undefined 到数组里面
// 3. 如果某个属性不是方法,手机 "not a method" 到数组里面
let results = [];
console.log("dddd");
/*
results 输出应该是:
[11, 31, 30, undefined, "not a method"]
*/
methods.forEach(methodName => {
let result;
if (o[methodName[0]] == null) {
result = "undefined";
} else if (typeof o[methodName[0]] != 'function') {
result = "not a method";
} else if (methodName.length == 2) {
//result = o[methodName[0]].call(undefined, methodName[1]);
result = o[methodName[0]](methodName[1]);
} else {
//result = o[methodName[0]].call(undefined, methodName[1], methodName[2]);
result = o[methodName[0]](methodName[1], methodName[2]);
}
results.push(result);
});
let o = {
add1(x) {
return x + 1;
},
add(x, y) {
return x + y;
},
times2(x) {
return this.add(x, x);
},
name: "crappy calculator",
}
let methods = [
["add1", 10],
["add1", 30],
["add", 10, 20],
["foobar", 10],
["name"],
["times2", 2]
];
// 1. 动态调用 methods 数组里面指定的方法,并传参。收集结果到 results 数组里面
// 2. 如果方法不存在,收集 undefined 到数组里面
// 3. 如果某个属性不是方法,手机 "not a method" 到数组里面
let results = [];
/*
results 输出应该是:
[11, 31, 30, undefined, "not a method", 4]
*/
methods.forEach(methodName => {
let result;
if (o[methodName[0]] == null) {
result = "undefined";
} else if (typeof o[methodName[0]] != 'function') {
result = "not a method";
} else if (methodName.length == 2) {
result = o[methodName[0]]( methodName[1]);
} else {
result = o[methodName[0]]( methodName[1], methodName[2]);
}
results.push(result);
});
console.log(results);
let o = {
a: 1,
b: 2,
c: -1,
d: 3,
e: -2,
}
// 输出大于 0 的属性名
// ["a", "b", "d"]
Object.keys(o).filter(x=>o[x]>0);
function MyClass() {
}
MyClass.prototype.a = 1;
MyClass.prototype.b = function() {
return 2;
};
// 输出所有在原型链上面的属性
// ["a", "b"]
Object.keys(MyClass.prototype);
- 用 Object.getOwnPropertyNames 列出所有属性名,包括不可迭代属性。
let numbers = [1, 2, 3];
// 输出 numbers 有的所有属性
// ["concat", "constructor", "copyWithin", "entries", "every", "fill", "filter", "find", "findIndex", "forEach", "includes", "indexOf", "join", "keys", "lastIndexOf", "length", "map", "pop", "push", "reduce", "reduceRight", "reverse", "shift", "slice", "some", "sort", "splice", "toLocaleString", "toString", "unshift", "values"]
Object.getOwnPropertyNames(numbers.constructor.prototype);
class MyClass {
a(x) {}
b(x, y) {}
c() {}
d(x,y,z) {}
}
// 输出接受两个参数以上的方法
// ["b", "d"]
参考:
Object.getOwnPropertyNames(MyClass.prototype).filter(
name => MyClass.prototype[name].length >= 2).sort()
全局变量其实就是 window 这个对象的属性。
- 请用 sort 方法去排序属性名
Object.getOwnPropertyNames(window).sort()
- 创建一个 Holder 类型,它有 10个属性。value1 到 value10, 返回值分别是 1 到 10
function Holder() { }
Holder.prototype.value1 = 1;
Holder.prototype.value2 = 2;
// ...
Holder.prototype.value10 = 10;
for(let i=1;i<=10;i++){
Holder.prototype["value"+i]=i;
}
function Holder() { }
// 用 ES6 class 语法也可以
// class Holder { }
let o = new Holder();
let o2 = new Holder();
o.value1;
// 1
o.value2;
// 2
o.value100;
// 100
o.value1 = -1;
o.value1;
// -1
// 修改 o 的属性不应该改动 o2 的属性
o2.value1
// 1
for(let i=1;i<=100;i++){
Holder.prototype["value"+i]=i;
}
function Adder() { }
let o = new Adder();
o.add1(1);
// 2
o.add2(1);
// 3
o.add3(1);
// 4
// ...
o.add100(1);
// 101
for( let i=1;i<=100;i++){
//一定要写let,否则下面的(x+i)的i不能变为值
Adder.prototype["add"+i]=function(x){
return x + i;
}
}
- 全局函数其实就是 window 这个对象的属性。请动态生成 100 个 全局函数:
add1(1);
// 2
add2(1);
// 3
add3(1);
// 4
// ...
add100(1);
// 101
for(let i=1;i<=100;i++){
window["add"+i]=function(x){return x+i;}
}
class Adder1 {
constructor(x) {
this.x = x;
}
calculate() {
return this.x + 1;
}
}
class Adder2 {
constructor(x) {
this.x = x;
}
calculate() {
return this.x + 2;
}
}
// ...
class Adder100 {
constructor(x) {
this.x = x;
}
calculate() {
return this.x + 100;
}
}
它们都有 calculate 这个方法,功能如下:
(new Adder1(1)).calculate();
// 2
(new Adder41(1)).calculate();
// 42
(new Adder100(1)).calculate();
// 101
JavaScript 的函数是对象。一个函数的返回值可以是个普通的对象,也可以是一个函数,因为函数也是对象。
我们可以声明一个 makeObject 函数,它返回一个对象,这个对象的 value 属性为 1:
function makeObject() {
return { value: 1 }
}
let o = makeObject();
o.value;
// 1
我们可以声明一个 makeFunction 函数,它返回一个函数:
function makeFunction() {
return () => 1;
}
let f = makeFunction();
f();
// 1
makeObject 和 makeFunction 并没有什么本质上的不同。这两个函数返回的都是对象。
makeFunction 是个返回函数的函数,江湖上叫它高阶函数。
所谓 “高阶函数” 其实没啥了不起,和返回普通的对象函数一样。你只要确保返回的函数满足了你的需求就行。
假设有个 makeObject 函数满足以下需求:
function makeObject(n) {
return { value: n };
}
let o;
o = makeObject(1);
o.value;
// 1
o = makeObject(42);
o.value;
// 42
请写出相对应的 makeFunction 函数满足类似的需求:
let f = makeFunction(1);
f();
// 1
f();
// 42
function makeFunction(n) {
return () => n;
}
let f = makeFunction(3);
console.log(f());
let take1 = makeTakeN(1);
let take3 = makeTakeN(3);
let take6 = makeTakeN(6);
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(take1(numbers));
// [1]
console.log(take3(numbers));
// [1, 2, 3]
console.log(take6(numbers));
// [1, 2, 3, 4, 5, 6]
function makeTakeN(n) {
return (numbers) =>
numbers.slice(0, n);
}
function add2(x) {
return x + 2;
}
function times2(x) {
return x * 2;
}
// (3 + 2) * 2
console.log(times2(add2(3)));
// 10
// f(x) = (x + 2) * 2
let f = compose(times2, add2);
f(3)
// 10
f(5)
// 14
// f(x) = (x * 2) + 2
let f2 = compose(add2, times2);
f2(3)
// 8
f2(5)
// 12
function compose(fn1,fn2){
return (n)=>fn1(fn2(n));
}