我对js对象一无所知
program javascript application 看了这个书, 才知道我对js对象一无所知. 感谢Eric Elliott大神. 大神为了写书, 至少弄了3个样例框架. 未来的spring啊.
构造函数 竟然是不该使用的方法
虽然我也讨厌new, 可是真没想到竟然是这个结论, js使用构造函数, 就是跑偏了.
funciton car(){}
var mycar= new car; //就是这种写法不要搞.
字面量是王道, 然而有作用域问题
- 这里其实我不是很理解, 难道不能用let规避吗?
var mycar={
color: 'pink',
gas: function gas(){
return this; //为了链式调用, 所有方法都要return this.
},
}
工厂方法
//正常的工厂
var car=function car(a, b, c){
var xxx; //这里其实声明的是一个私有变量, 不能被外部直接访问.
return{ a,b,c,
br:function br(){},
}
}
//单例工厂
function fac(){
var x={}; //这个就是单例对象, 私有且唯一.
return {
get: function get(){
return x;
}
}
}
var h1=fac().get();
var h2=fac().get();
//现在h1和h2其实指向同一个对象.
工厂方法的进一步提升
var carproto={
//...省略
},
car=funciton car (op){
return extend(object.create(carProto),op); //感觉这里或许可以直接用object.assign
},
mycar=car({a:'a'});
关于工厂有一个建议, 对象和数组这种引用类型的使用要注意一下, 直接新建比较好.
相关基础知识插入 extend和object.create
extend的underscore实现, 这个实现了原型克隆.
_.extend=function(ob){ //第一个参数是待处理的返回值.
each(slice.call(arguments,1), function(source){ //把后面的每一个参数都处理为第一个参数的属性.
for(var pr in source){
ob[pr] =source[pr];
}
});
return ob;
};
object.create, 这个实现了原型代理
Object.create(proto, [propertiesObject])
//可以这么实现:
Object.create=function(o){
function f(){};
f.prototype=o;
return new f;
}
共享原型模式
var carproto={
//...省略
},
car=funciton car (){
return object.create(carProto); //
},
mycar=car();
youcar=car(); //这些都是用了同样的原型.
作者自己的库stamps
- 地址: https://stampit.js.org
- git: https://github.com/stampit-org/stampit
牛的要死, 最初的版本只有90行代码. 现在的版本有400行, 但是, 整个项目的测试代码有几千行. 腻害哦.
更基础的基础知识
- lambda和闭包, 函数可以作为参数和返回值使用.
- 对象字面量, 数组字面量, 正则字面量, 字面量是王道.
- 动态对象扩展.
- 原型, 可以clone
- 工厂函数, 完全可以替代构造函数.
- 流式api与链式调用.
原型有两种打开方式
- 原型代理, object.create就是原型代理. 实际就是指定了新的对象的prototype. 原型上的数据天生就是分享的, 就是享元模式.
- 原型克隆, object.assign就差不多是克隆了, 完全复制一套属性给新的对象.
对象的构造
- 构造函数, 这个不推荐, 虽然我用的很熟, 但是确实不好用.
- 字面量, 这个效果拔群, 能用尽量用.
- 工厂函数, 这个确实好用. 私有的, 共有的(全局且私有)……
//前面的extend等函数存在的情况下
const cprototype={}, //一个用作prototype的字面量, 方法属性都放里面.
car= function car(opt){
return extend(Object.create(cprototype),opt);
/** 这个目标是可以任意指定对象的属性. 不指定就是默认属性.
* 不需要一堆this.xxx=xxx了. 这个新的对象他的原型就是cprototype.
* 同时他会把opt的内容copy进来, 可以覆盖掉原本的默认值.
*/
},
mycar = car({color: 'red'}); //这里得到一个新的对象.
关于stamp: 现代的方案有所调整, 参考姊妹篇: 2019-05-08-stamp或者是一条出路
object很关键
//类方法
Object.assign()
Copies the values of all enumerable own properties from one or more source objects to a target object.
Object.create(原型, 属性对象) //制造一个object, 按照原型和属性
Creates a new object with the specified prototype object and properties.
Object.defineProperty()
Adds the named property described by a given descriptor to an object.
Object.defineProperties()
Adds the named properties described by the given descriptors to an object.
Object.entries()
Returns an array of a given object’s own enumerable property [key, value] pairs.
Object.freeze()
Freezes an object: other code can’t delete or change any properties.
Object.keys() , 拿到所有键, 作为数组.
Object.values(), 拿到对象中的所有键值对的值, 作为数组.
解构和展开 destructuring assignment object spread
{xxx, oo}=p;
{...p};
const allRules = {...obj1, ...obj2, ...obj3};
[a, b, ...rest] = [10, 20, 30, 40, 50];
{a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}; //rest = {c: 30, d: 40}
[a=5, b=7] = [1]; //带默认值.
[a, b] = [b, a]; //可以做交换.
//参数也可以
function drawES2015Chart({size = 'big', coords = {x: 0, y: 0}, radius = 25} = {}) {
console.log(size, coords, radius);
// do some chart drawing
}
drawES2015Chart({
coords: {x: 18, y: 30},
radius: 30
});
//循环也能用
for (var {name: n, family: {father: f}} of people) {
console.log('Name: ' + n + ', Father: ' + f);
}
//中括号代表字面量
let key = 'z';
let {[key]: foo} = {z: 'bar'};
console.log(foo); // "bar"
const props = [
{ id: 1, name: 'Fizz'},
{ id: 2, name: 'Buzz'},
{ id: 3, name: 'FizzBuzz'}
];
const [,, { name }] = props;
console.log(name); // "FizzBuzz"
对象的遍历
for (var i in obj) { //这个要筛掉原型链上的属性
// obj.hasOwnProperty() is used to filter out properties from the object's prototype chain
if (obj.hasOwnProperty(i)) {
}
}
Object.keys //key数组
Object.values //value数组
Object.entries //[key, value]的数组
forEach //object木有foreach
for of //他要求这个对象是iterable, 也就是要有iterator
xxx.keys() //行吗?
//不行, 除非iterable