近期會對js世界里面的知識進行歸納總結(jié),為以后閱讀源碼打好基礎(chǔ)。
1 Object.assign
Object.assign() 方法用于將所有可枚舉的屬性的值從一個或多個源對象復(fù)制到目標對象。它將返回目標對象。
Object.assign(target, ...sources)
var o1 = { a: 1 };
var o2 = { b: 2,c:{a:5,b:6} };
var o3 = { c: {d:7} };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: {d:7} }
console.log(o1); // { a: 1, b: 2, c: {d:7} }
obj.b = 5
console.log(o2) // { b: 2,c:{a:5,b:6} }
這里看出object.assign是淺克隆,無法將里面一層對象拷貝。
如何實現(xiàn)深拷貝
function deepClone(data){
var type = Object.prototype.toString.call(data).slice(-8),
o;
if( type == 'Array'){
o = [];
}else if(type == 'Object'){
o = {}
}else{
return data
}
if( type == 'Array'){
for(var i = 0; i< data.length;i++){
o.push(deepClone(data[i]))
}
}else{
for(var i in data){
o[i] = deepClone(data[i])
}
}
return o
}
這樣來說明深淺克隆的區(qū)別吧:
var data = { a:6,b: 2,c:{a:5,b:6} }
var aa = deepClone(data)
aa.c = 6
data // { a:6,b: 2,c:6}
對比之前可以看出來了吧,深克隆改變自身會對原目標造成影響,而淺克隆不會。
繼承屬性和不可枚舉屬性是不能拷貝的
var obj = Object.create({foo: 1}, { // foo 是個繼承屬性。
bar: {
value: 2 // bar 是個不可枚舉屬性。
},
baz: {
value: 3,
enumerable: true // baz 是個自身可枚舉屬性。
}
});
var copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }
我們來見寫一個屬性融合吧。
function create(target,source){
for(var i in source){
if(source.hasOwnProperty(i)){
target.prototype[i] = source[i]
}
}
function aa(){}
aa.prototype = target.prototype
return new aa()
}
function target(){} qwe.prototype.say = function(){}
var source = {dance:function(){console.log('sss')},
dan:function(){console.log('dddd')}
}
var instance = create(target,source)
instance

相信不用我解釋大家也看得很明白了。
2 Object.create
Object.create() 方法會使用指定的原型對象及其屬性去創(chuàng)建一個新的對象。
Object.create(proto, [ propertiesObject ])
//Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); //call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
rect instanceof Shape); // true
rect.move(1, 1); //Outputs, "Shape moved."
我們知道在js原型繼承里面這樣可以實現(xiàn)繼承
function parent(){}
function child(){}
child.prototype = new parent()
這其實正好對應(yīng)下這段代碼
Rectangle.prototype = Object.create(Shape.prototype);
// Object.create 返回就是shape得實例
我們用shape.call(this)其實就是把那段構(gòu)造也寫上去。
function aa(){} aa.prototype = {ww:function(){console.log('fff')}}
var o = Object.create(aa.prototype, {
// foo會成為所創(chuàng)建對象的數(shù)據(jù)屬性
foo: {
writable:true,
configurable:true,
value: "hello"
},
// bar會成為所創(chuàng)建對象的訪問器屬性
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) {
console.log("Setting `o.bar` to", value);
}
}
});
o.ww() // ffff
o.foo // hello
o.bar // 10
o.bar = 6 // Setting o.bar to, 10
想必大家已經(jīng)看明白了,如果我們想要把普通人和程序員結(jié)合,我們可以這樣做:
function person(){}
person.prototype = {
walk:function(){},
eat:function(){}
}
//程序員必備技能
var skills = {
coding:{
writable:true,
configurable:true,
value: function(){console.log('i am coding')}
},
debug:{} ....
}
// 創(chuàng)造一個結(jié)合體
var mix = Object.create(person.prototype,skills)
mix.coding() // i am coding
需要注意的是,value為函數(shù)值得寫法,我們現(xiàn)在創(chuàng)造了一個不平凡的人。
3 arguments
arguments對象不是一個 Array 。它類似于數(shù)組,但除了 長度之外沒有任何數(shù)組屬性。例如,它沒有 pop 方法。但是它可以被轉(zhuǎn)換為一個真正的數(shù)組:
let args = Array.prototype.slice.call(arguments);
let args = [].slice.call(arguments);
我們需要把三個人用'---' 拼接起來
function myConcat(separator) {
var args = Array.prototype.slice.call(arguments, 1);
return args.join(separator);
}
myConcat("---", "red", "orange", "blue");
// red --- orange --- blue
同樣我們可以用這種方式創(chuàng)建一個html元素
function list(type) {
var result = "<" + type + "l><li>";
var args = Array.prototype.slice.call(arguments, 1);
result += args.join("</li><li>");
result += "</li></" + type + "l>"; // end list
return result;
}
var listHTML = list("ul", "One", "Two", "Three");
"<ul><li>One</li><li>Two</li><li>Three</li></ul>"
今天是情人節(jié),老婆大人讓我對他連續(xù)說 i love you ,直到。。。好吧,就說一分鐘的我愛你吧。。
function sayLove(){
var time = +new Date()
return function(){
console.log('I love u')
if(+new Date() - time < 60*1000){
arguments.callee()
}
}
}
我剛剛做了一個測試,程序每秒鐘可以說700次 i love u。。
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(); // object arguments
在嚴格模式下,第5版 ECMAScript (ES5) 禁止使用 arguments.callee()。當一個函數(shù)必須調(diào)用自身的時候, 避免使用 **arguments.callee(), **通過要么
給函數(shù)表達式一個名字,要么使用一個函數(shù)聲明.
尾遞歸調(diào)用
// 尾調(diào)用
function f(x){
return g(x);
}
// 非尾調(diào)用
function f(x){
return g(x) + 1;
}
尾調(diào)用的概念非常簡單,一句話就能說清楚,就是指某個函數(shù)的最后一步是調(diào)用另一個函數(shù)。
函數(shù)調(diào)用自身,稱為遞歸。如果尾調(diào)用自身,就稱為尾遞歸。
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1); // 非尾遞歸
}
factorial(50000) // 棧溢出
如果改寫成尾遞歸,只保留一個調(diào)用記錄,復(fù)雜度 O(1) 。
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1) // 120
史上最簡單的的數(shù)組去重
---- 原始做法----
function make(arr){
let aa = arr.filter( (item, index) =>
index == arr.indexOf(arr)
)
return aa
}
make([1,2,3,,2,3,1,5]) // 1,2,3,5
升級做法
et arr = [1,1,2,,2,3,3,4,5,5], set = new Set(arr), aa = Array.from(set)
aa // [1,2,3,4,5]
4 promise
本文針對有promise基礎(chǔ)的人,基本知識這里不講解。
function myAsyncFunction(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
};
我們上面定義了一個promise,代執(zhí)行玩ajax后調(diào)用函數(shù)。
myAsyncFunction(url).then(value => console.log(value),
value => console.log(value))
前面一個是成功回調(diào),后面一個是失敗回調(diào)。
Promise.prototype.then方法返回的是一個新的Promise對象,因此可以采用鏈式寫法。
myAsyncFunction("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
console.log(post) //這里打印的事json.post
});
需求來了,聽好了:現(xiàn)在我需要通過ajax去后臺哪一個數(shù)據(jù),數(shù)據(jù)里面有個url,在請求成功后我還需要再去請求這個url的地址,進行最后一步操作,怎么做?
myAsyncFunction("/posts.json").then(function(json) {
return myAsyncFunction(son.url);
}).then(function(post) {
console.log(post) //這里打印的事json.post
});
是不是很爽。。。
最后看一下promise.all的用法
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'three');
});
var p4 = new Promise((resolve, reject) => {
setTimeout(resolve, 4000, 'four');
});
Promise.all([p1, p2, p3, p4]).then(values => {
console.log(values); //['one' , 'two' , 'three' , 'four']
}, reason => {
console.log(reason)
});
我們這里一共有4個promise對象,都是異步執(zhí)行,過完4s打印如上內(nèi)容,其實就是每個promise返回值的數(shù)組。
其實有了這么多的知識足以在項目中運用自如了。我們來個vue的例子吧
const store = new Vuex.Store({
actions: {
deleteItem: ({ commit }, payload) => {
return callPromiseAPI(payload).then(res => {
commit('delete', { res })
})
},
getList: ({ commit }, payload) => {
return callPromiseAPI(payload).then(res => {
commit('list', { res })
})
}
}
})
function callPromiseAPI(payload){
return new Promise(function(resolve,reject){
resolve(payload)
})
}
我們需要刪除一個id為1的數(shù)據(jù)然后再去查一遍數(shù)據(jù)。
store.dispatch('deleteItem', { id: 1 }).then(() => {
// action done
store.dispatch(getList, {page: 1})
})
我們看到了deleteItem之后,會去在查詢page為1的數(shù)據(jù),之前的deleteItem返回的也是promise可以繼續(xù).then。
好了,今天就到這里了吧。。。